Skip to content

epymorph.simulation

General simulation requisites and utility functions.

NEVER module-attribute

NEVER = TickDelta(-1, -1)

A special TickDelta which expresses an event that should never happen. Any Tick plus NEVER equals NEVER.

ListValue module-attribute

ListValue = Sequence[
    Union[ScalarValue, StructValue, "ListValue"]
]

A type alias which describes acceptable input forms for parameter values which are lists. (Necessary because this type is recursive: lists can be nested inside lists.)

ParamValue module-attribute

ParamValue = Union[
    ScalarValue,
    StructValue,
    ListValue,
    "SimulationFunction",
    Expr,
    NDArray[ScalarDType | StructDType],
]

A type alias which describes all acceptable input forms for parameter values:

ResultT module-attribute

ResultT = TypeVar('ResultT')

The result type of a SimulationFunction.

DeferResultT module-attribute

DeferResultT = TypeVar('DeferResultT')

The result type of a SimulationFunction during deference.

DeferFunctionT module-attribute

DeferFunctionT = TypeVar(
    "DeferFunctionT", bound="BaseSimulationFunction"
)

The type of a SimulationFunction during deference.

Tick

Bases: NamedTuple

Represents a single time-step in a simulation, by analogy to the ticking of a clock. This tuple bundles the related information for a single tick. For instance, each time step corresponds to a calendar day, a numeric day (i.e., relative to the start of the simulation), which tau step this corresponds to, and so on.

sim_index instance-attribute

sim_index: int

Which simulation step are we on? (0,1,2,3,...)

day instance-attribute

day: int

Which day increment are we on? Same for each tau step: (0,0,1,1,2,2,...)

date instance-attribute

date: date

The calendar date corresponding to day

step instance-attribute

step: int

Which tau step are we on, by index? (0,1,0,1,0,1,...)

tau instance-attribute

tau: float

What's the tau length of the current step? (0.666,0.333,0.666,0.333,...)

TickIndex

Bases: NamedTuple

An index identifying tau steps within a day. For example, if a RUME's movement model declares three tau steps, the first six tick indices will be 0, 1, 2, 0, 1, 2. Indices 3 or more would be invalid for this RUME.

step instance-attribute

step: int

The index of the tau step.

TickDelta

Bases: NamedTuple

An offset relative to a tick, expressed as a number of whole days which should elapse and the step on which to end up. In applying this delta, it does not matter which step we start on.

See Also

epymorph.simulation.resolve_tick_delta, the function which combines an absolute tick with a relative delta to get another absolute tick.

days instance-attribute

days: int

The number of whole days.

step instance-attribute

step: int

Which tau step within that day, by index.

Context

Bases: ABC

The evaluation context of a SimulationFunction.

See Also

This class is abstract so you won't instantiate it as a normal class; instead you may use static method epymorph.simulation.Context.of.

name abstractmethod property

The name under which this attribute is being evaluated.

scope abstractmethod property

scope: GeoScope

The simulation GeoScope.

time_frame abstractmethod property

time_frame: TimeFrame

The simulation time frame.

ipm abstractmethod property

The simulation's IPM.

rng abstractmethod property

rng: Generator

The simulation's random number generator.

dim abstractmethod property

Simulation dimensions.

data abstractmethod

data(attribute: AttributeDef) -> AttributeArray

Retrieve the value of an attribute.

Parameters:

Returns:

replace

replace(
    name: AbsoluteName | None = None,
    data: DataResolver | None = None,
    scope: GeoScope | None = None,
    time_frame: TimeFrame | None = None,
    ipm: BaseCompartmentModel | None = None,
    rng: Generator | None = None,
) -> Context

Create a new context by overriding some or all of this context's values.

Parameters:

  • name (AbsoluteName | None, default: None ) –

    The name in which a SimulationFunction is being evaluated.

  • data (DataResolver | None, default: None ) –

    Data attributes which may be required by the function.

  • scope (GeoScope | None, default: None ) –

    The geo scope.

  • time_frame (TimeFrame | None, default: None ) –

    The simulation time frame.

  • ipm (BaseCompartmentModel | None, default: None ) –

    The IPM.

  • rng (Generator | None, default: None ) –

    A random number generator to use.

Returns:

hash

hash(requirements: Sequence[AttributeDef]) -> int

Compute a hash for the context, assuming the given set of requirements. This is used to quickly identify if the context has changed between evaluations.

Parameters:

  • requirements (Sequence[AttributeDef]) –

    The subset of requirements that are important to include when computing the hash. This allows the hash to ignore changes to attributes which aren't critical to a particular use-case.

Returns:

  • int

    The hash value.

of staticmethod

of(
    name: AbsoluteName = NAME_PLACEHOLDER,
    data: DataResolver | None = None,
    scope: GeoScope | None = None,
    time_frame: TimeFrame | None = None,
    ipm: BaseCompartmentModel | None = None,
    rng: Generator | None = None,
) -> Context

Create a new context instance, which may be a partial or complete context.

Parameters:

  • name (AbsoluteName, default: NAME_PLACEHOLDER ) –

    The name in which a SimulationFunction is being evaluated.

  • data (DataResolver | None, default: None ) –

    Data attributes which may be required by the function.

  • scope (GeoScope | None, default: None ) –

    The geo scope.

  • time_frame (TimeFrame | None, default: None ) –

    The simulation time frame.

  • ipm (BaseCompartmentModel | None, default: None ) –

    The IPM.

  • rng (Generator | None, default: None ) –

    A random number generator to use.

Returns:

SimulationFunctionClass

Bases: ABCMeta

The metaclass for SimulationFunction classes; enforces proper implementation.

BaseSimulationFunction

Bases: ABC, Generic[ResultT]

A function which runs in the context of a simulation to produce a value (as a numpy array).

Instances may access the context in which they are being evaluated using attributes and methods present on "self": name, data, scope, time_frame, ipm, rng, and dim, and may use methods like defer to pass their context on to another function for direct evaluation.

This class is generic on the type of result it produces (ResultT).

See Also

Refer to epymorph.simulation.SimulationFunction and epymorph.simulation.SimulationTickFunction for more concrete subclasses.

requirements class-attribute instance-attribute

requirements: Sequence[AttributeDef] | property = ()

The attribute definitions describing the data requirements for this function.

For advanced use-cases, you may specify requirements as a property if you need it to be dynamically computed.

randomized class-attribute instance-attribute

randomized: bool = False

Should this function be re-evaluated every time it's referenced in a RUME? (Mostly useful for randomized results.) If False, even a function that utilizes the context RNG will only be computed once, resulting in a single random value that is shared by all references during evaluation.

class_name property

class_name: str

The class name of the SimulationFunction.

name property

The name under which this attribute is being evaluated.

context property

context: Context

The full context object.

scope property

scope: GeoScope

The simulation geo scope.

time_frame property

time_frame: TimeFrame

The simulation time frame.

ipm property

The simulation IPM.

rng property

rng: Generator

The simulation's random number generator.

dim property

The simulation's dimensional information. This is a re-packaging of information contained in other context elements, like the geo scope.

validate

validate(result: ResultT) -> None

Override this method to validate the function evaluation result. If not overridden, the default is to do no validation. Implementations should raise an appropriate error if results are not valid.

Parameters:

  • result (ResultT) –

    The result produced from function evaluation.

with_context

with_context(
    name: AbsoluteName = NAME_PLACEHOLDER,
    params: Mapping[str, ParamValue] | None = None,
    scope: GeoScope | None = None,
    time_frame: TimeFrame | None = None,
    ipm: BaseCompartmentModel | None = None,
    rng: Generator | None = None,
) -> Self

Constructs a clone of this instance which has access to the given context.

All elements of the context are optional, allowing users who wish to quickly evaluate a function in a one-off situation to provide only the partial context that is strictly necessary. (It's very tedious to create fake context when it isn't strictly needed.) For example, a function might be able to calculate a result knowing only the geo scope and time frame. During normal function evaluation, such as when running a simulation, the full context is always provided and available.

Parameters:

  • name (AbsoluteName, default: NAME_PLACEHOLDER ) –

    The name used for the value this function produces, according to the evaluation context. Defaults to a generic placeholder name.

  • params (Mapping[str, ParamValue] | None, default: None ) –

    Additional parameter values we may need to evaluate this function.

  • scope (GeoScope | None, default: None ) –

    The geo scope.

  • time_frame (TimeFrame | None, default: None ) –

    The time frame.

  • ipm (BaseCompartmentModel | None, default: None ) –

    The IPM.

  • rng (Generator | None, default: None ) –

    A random number generator instance.

Returns:

  • Self

    A clone with new context information.

Raises:

  • MissingContextError

    If the function tries to use a part of the context that hasn't been provided.

with_context_internal

with_context_internal(context: Context) -> Self

Constructs a clone of this instance which has access to the given context.

This method is intended for usage internal to epymorph's systems. Typical usage will use with_context instead.

defer_context

defer_context(
    other: DeferFunctionT,
    scope: GeoScope | None = None,
    time_frame: TimeFrame | None = None,
) -> DeferFunctionT

Defer processing to another instance of a SimulationFunction.

This method is intended for usage internal to epymorph's system. Typical usage will use defer instead.

data

data(attribute: AttributeDef | str) -> NDArray

Retrieve the value of a requirement. You must declare the attribute in this function's requirements list.

Parameters:

  • attribute (AttributeDef | str) –

    The attribute to get, identified either by its name (string) or its definition object.

Returns:

Raises:

  • ValueError

    If the attribute is not in the function's requirements declaration.

SimulationFunction

Bases: BaseSimulationFunction[ResultT]

A function which runs in the context of a RUME to produce a value (as a numpy array). The value must be independent of the simulation state, and they will often be evaluated before the simulation starts.

SimulationFunction is an abstract class. In typical usage you will not implement a SimulationFunction directly, but rather one of its more-specific child classes.

SimulationFunction is generic in the type of result it produces (ResultT).

See Also

Notable child classes of SimulationFunction include epymorph.initializer.Initializer, epymorph.adrio.adrio.ADRIO, and epymorph.params.ParamFunction.

evaluate abstractmethod

evaluate() -> ResultT

Implement this method to provide logic for the function. Use self methods and properties to access the simulation context or defer processing to another function.

Returns:

defer

defer(
    other: SimulationFunction[DeferResultT],
    scope: GeoScope | None = None,
    time_frame: TimeFrame | None = None,
) -> DeferResultT

Defer processing to another instance of a SimulationFunction, returning the result of evaluation.

This function is generic in the type of result returned by the function to which we are deferring (DeferResultT).

Parameters:

  • other (SimulationFunction[DeferResultT]) –

    The other function to defer to.

  • scope (GeoScope | None, default: None ) –

    Override the geo scope for evaluation; if None, use the same scope.

  • time_frame (TimeFrame | None, default: None ) –

    Override the time frame for evaluation; if None, use the same time frame.

Returns:

SimulationTickFunction

Bases: BaseSimulationFunction[ResultT]

A function which runs in the context of a RUME to produce a value (as a numpy array) which is expected to vary over the run of a simulation.

In typical usage you will not implement a SimulationTickFunction directly, but rather one of its more-specific child classes.

SimulationTickFunction is generic in the type of result it produces (ResultT).

See Also

The only notable child class is epymorph.movement_model.MovementClause.

evaluate abstractmethod

evaluate(tick: Tick) -> ResultT

Implement this method to provide logic for the function. Use self methods and properties to access the simulation context or defer processing to another function.

Parameters:

  • tick (Tick) –

    The simulation tick being evaluated.

Returns:

defer

defer(
    other: SimulationTickFunction[DeferResultT],
    tick: Tick,
    scope: GeoScope | None = None,
    time_frame: TimeFrame | None = None,
) -> DeferResultT

Defer processing to another instance of a SimulationTickFunction, returning the result of evaluation.

This function is generic in the type of result returned by the function to which we are deferring (DeferResultT).

Parameters:

  • other (SimulationTickFunction[DeferResultT]) –

    the other function to defer to

  • scope (GeoScope | None, default: None ) –

    override the geo scope for evaluation; if None, use the same scope

  • time_frame (TimeFrame | None, default: None ) –

    override the time frame for evaluation; if None, use the same time frame

Returns:

default_rng

default_rng(
    seed: int | SeedSequence | None = None,
) -> Callable[[], Generator]

Convenience constructor to create a factory function for a simulation's random number generator.

Parameters:

  • seed (int | SeedSequence | None, default: None ) –

    Construct a generate with this random seed. By default, the generator will be "unseeded", that is seeded in an unpredictable way.

Returns:

resolve_tick_delta

resolve_tick_delta(
    tau_steps_per_day: int, tick: Tick, delta: TickDelta
) -> int

Add a delta to a tick to get the index of the resulting tick.

Parameters:

  • tau_steps_per_day (int) –

    The number of simulation tau steps per day.

  • tick (Tick) –

    The tick to start from.

  • delta (TickDelta) –

    A delta to add to tick.

Returns:

  • int

    The result of adding delta to tick, as a tick index.

simulation_clock

simulation_clock(
    time_frame: TimeFrame, tau_step_lengths: list[float]
) -> Iterable[Tick]

Generates the sequence of ticks which makes up the simulation clock.

Parameters:

  • time_frame (TimeFrame) –

    A simulation's time frame.

  • tau_step_lengths (list[float]) –

    The simulation tau steps as fractions of one day.

Returns:

  • Iterable[Tick]

    The sequence of ticks as determined by the simulation's start date, duration, and tau steps configuration.

validate_context_for_shape

validate_context_for_shape(
    context: Context, shape: DataShape
) -> None

Checks that the elements of a context which are required to compute the given shape have been provided in the context. For example, if the shape contains an "N" axis, the context must include a scope or else there's no knowing how long that axis should be.

Parameters:

  • context (Context) –

    The simulation context.

  • shape (DataShape) –

    The shape to check.

Raises: