Skip to main content

latentplant

ci license

Learned world models for industrial process time series. An action-conditioned model of process dynamics that can be rolled forward in imagination, carries calibrated uncertainty, and supports what-if queries, planning and regime-change detection.

What a world model is here, and why it is not a forecaster

A forecaster maps history to a future. A world model maps history and a proposed action sequence to a distribution over futures:

rollout(obs_ctx, act_ctx, exo_ctx, act_fut, exo_fut, n_samples=64)

act_fut is an argument. That single difference is what makes counterfactual questions expressible ("what if we raise the amine dose for the next four hours") and what makes planning possible at all. A model that ignores its action input is a forecaster wearing a costume, so the test suite asserts direction-of-effect on a system with known gain.

The disciplines baked in

Rollout-first evaluation. One-step teacher-forced error is not a world-model metric: on any autocorrelated process series it flatters a model that has learned nothing. Everything in latentplant.metrics is indexed by horizon, and break_even_horizon reports where the model stops beating persistence. That integer belongs next to every headline number.

Two uncertainties, reported separately. uncertainty_split returns aleatoric (process and sensor noise, irreducible) and epistemic (the model does not know this region) as different arrays. A noisy tag and an unfamiliar operating point look identical in a single band and mean completely different things; the epistemic band is what a regime-change alarm should watch.

Cadence is declared, not guessed. An hourly lab assay carried on 20-second rows repeats about 180 times. A model trained without masking those repeats learns to copy the previous row and scores beautifully. PlantSchema takes update_seconds per tag and stale_mask marks the repeats so the loss can ignore them.

Leakage-safe by construction. Episodes never cross an acquisition gap, windows never cross an episode, splits are chronological, and standardization is fitted on train only.

Install

pip install latentplant                 # core: numpy + torch
pip install "latentplant[onnx]"         # ONNX export for a browser inference lane
pip install "latentplant[baselines]"    # sysidentpy / pysindy baseline adapters

Quick start

import numpy as np
from latentplant import (PlantSchema, TagSpec, ProbabilisticEnsemble,
                         split_on_gaps, make_windows, chronological_split)
from latentplant.metrics import rollout_report

schema = PlantSchema(
    tags=(
        TagSpec("silica_conc", "target", "pct", 0.0, 10.0, update_seconds=3600.0),
        TagSpec("pulp_level", "observation", "pct", 0.0, 100.0),
        TagSpec("amina_flow", "action", "m3/h", 0.0, 800.0),
        TagSpec("iron_feed", "exogenous", "pct"),
    ),
    row_seconds=20.0,
)

episodes = split_on_gaps(schema, values, timestamps)      # a plant stop ends an episode
windows = make_windows(schema, episodes, context=24, horizon=12)
train, val, test = chronological_split(windows)

wm = ProbabilisticEnsemble(n_obs=2, n_act=1, n_exo=1, n_members=5)
wm.fit(train, epochs=60, seed=0)

roll = wm.rollout(test.obs_ctx, test.act_ctx, test.exo_ctx,
                  test.act_fut, test.exo_fut, n_samples=64, seed=0)
lo, hi = roll.interval(0.9)
print(rollout_report(roll.samples, test.obs_fut, test.obs_ctx, test.mask_fut))

Counterfactual A/B from the same anchor:

more, less = wm.counterfactual(ctx_obs, ctx_act, ctx_exo, action_a, action_b, exo_fut)
lift = more.mean - less.mean

On real plant data this supports direction-of-effect claims only: logged actions come from a closed loop, so observational data does not identify interventions without assumptions. On a simulator the ground truth exists and the imagination-to-reality gap is measured instead.

Plan against the model, and measure what the plan was worth:

from latentplant import Planner, cvar_cost, target_tracking_cost, imagination_gap

planner = Planner(model=wm, bounds=action_bounds, horizon=24, method="cem")
plan = planner.plan(obs_ctx[:1], act_ctx[:1], exo_ctx[:1], exo_fut[:1],
                    cvar_cost(target_tracking_cost(target), alpha=0.2),
                    action_rate_penalty=2.0)

realized = env.execute(plan.actions)          # only possible where truth exists
print(imagination_gap(plan, realized, persistence_from=obs_ctx[0]))

Fix an overconfident model's intervals without retraining it:

from latentplant import fit_conformal, calibration_report

conf = fit_conformal(cal_roll, cal.obs_fut, level=0.9, mask=cal.mask_fut)
print(calibration_report(conf, test_roll, test.obs_fut, mask=test.mask_fut))

Documentation

Full docs in docs/: concepts (what a world model is, the plant contract, windows and leakage), models (probabilistic ensemble, RSSM, ensembled RSSM), evaluation (rollout metrics, conformal calibration) and planning (imagination, the imagination-to-reality gap).

Status

0.03.000, alpha. Shipping now: the ingestion contract with the multi-rate observation operator, episodes/windows/leakage-safe splits, the probabilistic ensemble (PETS-class, TS-inf propagation), the vector RSSM, the ensembled RSSM with the aleatoric/epistemic split, the rollout metric suite, split-conformal interval calibration, and CEM/MPPI planning with the imagination-to-reality gap. On the roadmap: ONNX export for a browser inference lane, a Gymnasium imagination env, and baseline adapters.

Not to be confused with

phenoforge, the sibling engine, which fits and ensembles closed-form phenomenological equations. latentplant learns latent dynamics from data. Same industry, different object.

References

The design follows: Chua et al. 2018, Deep RL in a Handful of Trials with Probabilistic Dynamics Models, arXiv:1805.12114 (probabilistic ensembles, TS-inf); Lakshminarayanan et al. 2017, Simple and Scalable Predictive Uncertainty Estimation using Deep Ensembles, arXiv:1612.01474; Hafner et al. 2019, Learning Latent Dynamics for Planning from Pixels, arXiv:1811.04551 (RSSM); Hafner et al. 2023, Mastering Diverse Domains through World Models, arXiv:2301.04104; Janner et al. 2019, When to Trust Your Model, arXiv:1906.08253 (rollout horizon and compounding error); Che et al. 2016, Recurrent Neural Networks for Multivariate Time Series with Missing Values, arXiv:1606.01865 (cadence and masking); Romano et al. 2019, Conformalized Quantile Regression, arXiv:1905.03222 (interval calibration); Williams et al. 2017, Information Theoretic Model Predictive Control, arXiv:1707.02342 (MPPI); Levine et al. 2020, Offline Reinforcement Learning: Tutorial, Review, and Perspectives, arXiv:2005.01643 (why the planner refuses to issue setpoints).

Developed by Felipe Santibanez-Leal. MIT licensed.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

latentplant-0.4.0.tar.gz (53.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

latentplant-0.4.0-py3-none-any.whl (43.5 kB view details)

Uploaded Python 3

File details

Details for the file latentplant-0.4.0.tar.gz.

File metadata

  • Download URL: latentplant-0.4.0.tar.gz
  • Upload date:
  • Size: 53.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for latentplant-0.4.0.tar.gz
Algorithm Hash digest
SHA256 4e413769a7298d4ea113679045bed105df724c06a42b3e70f1ebeaa448d16e24
MD5 acbc22f983dfa085a3bea2abdf4db87b
BLAKE2b-256 381985abfff017b0bcafc4da4f291c723d826551b938cc68ed654db0d4fa1d99

See more details on using hashes here.

Provenance

The following attestation bundles were made for latentplant-0.4.0.tar.gz:

Publisher: release.yml on fsantibanezleal/CAOS_LatentPlant

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file latentplant-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: latentplant-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 43.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for latentplant-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8c21f2416d777f3e34371c63564f7a84dc597194c51ac3cc48af6bfba76a8719
MD5 21e7319365850bd2025705010d4a5d79
BLAKE2b-256 75594e485000acab9695f12545f6e7670fe78f507087c7b26b4dcff00d2e7bcd

See more details on using hashes here.

Provenance

The following attestation bundles were made for latentplant-0.4.0-py3-none-any.whl:

Publisher: release.yml on fsantibanezleal/CAOS_LatentPlant

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.10.0

2 files

0.8.0

2 files

0.7.2

2 files

0.7.1

2 files

0.7.0

2 files

0.6.0

2 files

0.5.0

2 files

This release

0.4.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page