Skip to content

anypinn.cli.scaffold.lotka_volterra.ode_synthetic

Lotka-Volterra predator-prey — mathematical definition.

ALPHA_KEY = 'alpha' module-attribute

BETA_KEY = 'beta' module-attribute

DELTA_KEY = 'delta' module-attribute

GAMMA_KEY = 'gamma' module-attribute

NOISE_FRAC = 0.02 module-attribute

POP_SCALE = 100.0 module-attribute

TRUE_ALPHA = 0.5 module-attribute

TRUE_BETA = 0.02 module-attribute

TRUE_DELTA = 0.01 module-attribute

TRUE_GAMMA = 0.5 module-attribute

T_TOTAL = 50 module-attribute

X0 = 40.0 module-attribute

X_KEY = 'x' module-attribute

Y0 = 9.0 module-attribute

Y_KEY = 'y' module-attribute

validation: ValidationRegistry = {BETA_KEY: lambda x: torch.full_like(x, TRUE_BETA)} module-attribute

create_data_module(hp: ODEHyperparameters)

Source code in src/anypinn/cli/scaffold/lotka_volterra/ode_synthetic.py
def create_data_module(hp: ODEHyperparameters):
    from anypinn.catalog.lotka_volterra import LotkaVolterraDataModule

    def LV_unscaled(x: Tensor, y: Tensor, args: ArgsRegistry) -> Tensor:
        prey, predator = y
        b = args[BETA_KEY]
        alpha = args[ALPHA_KEY]
        delta = args[DELTA_KEY]
        gamma = args[GAMMA_KEY]
        dx = alpha(x) * prey - b(x) * prey * predator
        dy = delta(x) * prey * predator - gamma(x) * predator
        return torch.stack([dx, dy])

    gen_props = ODEProperties(
        ode=LV_unscaled,
        y0=torch.tensor([X0, Y0]),
        args={
            ALPHA_KEY: Argument(TRUE_ALPHA),
            BETA_KEY: Argument(TRUE_BETA),
            DELTA_KEY: Argument(TRUE_DELTA),
            GAMMA_KEY: Argument(TRUE_GAMMA),
        },
    )

    return LotkaVolterraDataModule(
        hp=hp,
        gen_props=gen_props,
        noise_frac=NOISE_FRAC,
        validation=validation,
        callbacks=[DataScaling(y_scale=[1 / POP_SCALE, 1 / POP_SCALE])],
    )

create_problem(hp: ODEHyperparameters) -> ODEInverseProblem

Source code in src/anypinn/cli/scaffold/lotka_volterra/ode_synthetic.py
def create_problem(hp: ODEHyperparameters) -> ODEInverseProblem:
    props = ODEProperties(
        ode=lotka_volterra,
        y0=torch.tensor([X0, Y0]) / POP_SCALE,
        args={
            ALPHA_KEY: Argument(TRUE_ALPHA),
            DELTA_KEY: Argument(TRUE_DELTA),
            GAMMA_KEY: Argument(TRUE_GAMMA),
        },
    )

    fields = FieldsRegistry(
        {
            X_KEY: Field(config=hp.fields_config),
            Y_KEY: Field(config=hp.fields_config),
        }
    )
    params = ParamsRegistry(
        {
            BETA_KEY: Parameter(config=hp.params_config),
        }
    )

    def predict_data(x_data: Tensor, fields: FieldsRegistry, _params: ParamsRegistry) -> Tensor:
        x_pred = fields[X_KEY](x_data)
        y_pred = fields[Y_KEY](x_data)
        return torch.stack([x_pred, y_pred], dim=1)

    return ODEInverseProblem(
        props=props,
        hp=hp,
        fields=fields,
        params=params,
        predict_data=predict_data,
    )

fourier_encode(t: Tensor) -> Tensor

Source code in src/anypinn/cli/scaffold/lotka_volterra/ode_synthetic.py
def fourier_encode(t: Tensor) -> Tensor:
    features = [t]
    for k in range(1, 7):
        features.append(torch.sin(k * t))
    return torch.cat(features, dim=-1)

lotka_volterra(x: Tensor, y: Tensor, args: ArgsRegistry) -> Tensor

Scaled Lotka-Volterra ODE. Populations scaled by POP_SCALE, time by T_TOTAL.

Source code in src/anypinn/cli/scaffold/lotka_volterra/ode_synthetic.py
def lotka_volterra(x: Tensor, y: Tensor, args: ArgsRegistry) -> Tensor:
    """Scaled Lotka-Volterra ODE. Populations scaled by POP_SCALE, time by T_TOTAL."""
    prey, predator = y
    b = args[BETA_KEY]
    alpha = args[ALPHA_KEY]
    delta = args[DELTA_KEY]
    gamma = args[GAMMA_KEY]

    dx = alpha(x) * prey - b(x) * prey * predator * POP_SCALE
    dy = delta(x) * prey * predator * POP_SCALE - gamma(x) * predator

    dx = dx * T_TOTAL
    dy = dy * T_TOTAL
    return torch.stack([dx, dy])