Skip to main content

Approximate Numerics in Applied Transition Environments

ANIATE

pypi python tests website guide licence


Fibonacci squares 1, 1, 2, 3, 5, 8 and 13 tiling a 21 by 13 rectangle, with the golden spiral drawn through them

Reference implementation of aniate, a Python library for finite decision problems: Markov decision processes and problems whose reward depends on the history of the episode.

A problem is specified by its states, actions, transition probabilities, rewards and discount factor. The specification is validated at construction, and a model is rejected when a probability row does not sum to one, when a terminal state continues to move or to accrue reward, or when its value is unbounded. The library computes optimal policies together with their exact values, simulates episodes in batches, and compares any external simulator with the model through per-transition chi-square tests and the value martingale M_t = G_<t + γ^t V(s_t). History-dependent objectives are expressed with event labels and a Mealy automaton, and the exact product model is solved. Every operation writes one structured log line, and every figure is saved as a PDF with embedded Computer Modern fonts. The library can be run in a web browser, without installation, at aniate.com/playground.

Installation

pip install aniate            # numpy and scipy
pip install 'aniate[vis]'     # adds matplotlib, required for plots
pip install 'aniate[gym]'     # adds gymnasium, required for aniate.gym

Verifying the installation

from aniate import ant
ant()

ant() prints the Fibonacci drawing, the installed version of Python and of each dependency, and the result of a self-test that builds, solves, simulates and checks a small model. It returns True when aniate is working. The same report is printed by python -m aniate.

aniate 2.1.0   Approximate Numerics in Applied Transition Environments

python      3.12.4      ok             required, 3.10 or later
numpy       2.1.0       ok             required, 1.24 or later
scipy       1.14.1      ok             required, 1.12 or later
matplotlib  -           not installed  optional, for plots in aniate.vis
pytest      -           not installed  optional, for running the tests
hypothesis  -           not installed  optional, for property-based tests
gymnasium   -           not installed  optional, for the Gymnasium adapter in aniate.gym

self-test   model valid | solved, value 3.20876 | 2,000 episodes simulated | check passed | 13 ms
            plots unavailable; install them with: pip install 'aniate[vis]'

aniate is working.

Quick start

import aniate as an
from aniate import vis

m = an.from_functions(
    states=range(5), actions=["left", "right"],
    transition=lambda s, a: {max(s - 1, 0): 1.0} if a == "left" else {min(s + 1, 4): 0.8, s: 0.2},
    reward=lambda s, a, s_next: 10.0 if s_next == 4 else -1.0,
    gamma=0.9, terminal=[4], initial=0,
)

sol = m.solve()                                   # optimal policy, its exact value, an error bound
runs = an.simulate(m, sol, episodes=10_000)       # 10,000 episodes, run in parallel
report = an.check(m, policy=sol)                  # compares simulated behaviour with the model
vis.save(vis.overview(runs), "overview.pdf")      # four standard plots in one PDF
m.describe()                                      # the model as a JSON-compatible dict

Each operation writes one line to standard error:

aniate | model    | 5 states | 2 actions | gamma 0.9 | horizon inf | 14 transitions | valid
aniate | solve    | policy_iteration | 4 iterations | 2.8 ms | start value 3.20876 | bound 8.9e-15
aniate | simulate | 10,000 episodes | 49,768 steps | 4 ms | mean return 3.23989 +/- 0.014 | 10,000 terminated | 0 truncated
aniate | check    | PASSED | 300 episodes | 1,505 steps | 4 pairs tested | return 3.1863 vs model 3.2088
aniate | vis      | saved overview.pdf

Validation

Construction fails, and the error names each offending state and action, if any of the following hold:

code condition
row_sum a row of transition probabilities does not sum to 1
dead_end a state-action pair has no successor
terminal_not_absorbing a terminal state moves to another state or pays a reward
unbounded_value the discount factor is 1 and no terminal state is reachable

an.check(model, env=simulator) runs episodes through an external simulator and reports impossible_transition, transition_frequency, reward_mismatch, termination_mismatch and return_mismatch. These properties are verified by runtime checks and by the test suite; they are not formally proved.

History-dependent rewards

from aniate import nmdp

world  = an.problems.gridworld(rows=5, cols=5, goals=((0, 4),), start=(4, 0))
labels = nmdp.Labels(world).at("r4c4", "A").at("r0c4", "B")
task   = an.NMDP(world, labels, nmdp.Ordering(["A", "B"], violation_penalty=-1))
policy = task.solve()        # a MemoryPolicy: policy.step(state) returns the next action

nmdp.Ordering, nmdp.Budget and nmdp.Deadline cover common patterns, and nmdp.Mealy expresses any finite-memory rule.

Notebooks

In Jupyter, a model, solution, set of episodes, check report, automaton or non-Markovian task that ends a cell is displayed as a table. A long table is shortened, and the number of omitted rows is stated.

Gymnasium

from aniate import gym

env = gym.make(m)                               # a gymnasium.Env with Discrete spaces
obs, info = env.reset(seed=0)
obs, reward, terminated, truncated, info = env.step(env.action_space.sample())

gym.register("aniate/Corridor-v0", lambda: m)   # gymnasium.make("aniate/Corridor-v0") then builds it

Transitions are sampled from the model with the seeded generator of Gymnasium, so equal seeds give equal episodes, and the environment passes the Gymnasium environment checker. The adapter requires pip install 'aniate[gym]'.

Interface

call purpose
ant() report installed dependencies and run a self-test
an.from_functions(states, actions, transition, reward, gamma, terminal=, initial=) define a model with Python functions
an.Builder(gamma) define a model one transition at a time
an.MDP(P, R, gamma) define a model from matrices
m.solve() optimal policy and exact value
an.evaluate(m, policy) exact value of any policy
an.simulate(m, policy, episodes) batched episodes, returned as Episodes
m.env() a Gym-style environment with reset and step
an.check(m, env=simulator, policy=) statistical comparison of a simulator with the model
an.NMDP(world, labels, automaton) a problem whose reward depends on history
gym.make(m), gym.register(id, model) the model as a Gymnasium environment
vis.overview(runs), vis.graph(m), vis.grid(m, sol) plots; vis.save(fig, "name.pdf") writes a PDF
obj.describe() a JSON-compatible summary of any model, solution, report or set of episodes
an.verbosity("quiet") set the log level

A decision tree for choosing among these calls, the package layout and the conventions for extending the library are given in tree.md.

Worked examples

folder problem result verified by the tests
tests/stsp stochastic travelling salesman with randomly blocked roads the exact solution equals the best of all 24 tours, with expected cost 17.6227
tests/gaussian Gaussian random walk between two absorbing edges the hitting probability is 0.5 by symmetry and 0.956 under drift; Monte Carlo estimates agree
tests/heavy_tail travel time with power-law delays the value equals the closed form, the martingale mean is constant, and an incorrect simulator is detected
pip install -e '.[dev]'
pytest                               # all tests
python tests/stsp/plot.py            # writes route.pdf and overview.pdf into tests/stsp

Importing aniate prints a Fibonacci rectangle to standard error once per process; ANIATE_BANNER=0 disables it.

Citation

@software{murjani2026aniate,
  author  = {Murjani, Kabir},
  title   = {aniate: Approximate Numerics in Applied Transition Environments},
  year    = {2026},
  version = {2.1.0},
  url     = {https://github.com/Kcbir/aniate}
}

Licence

Released under the MIT Licence.

Download files

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

Source Distribution

aniate-2.1.0.tar.gz (85.4 kB view details)

Uploaded Source

Built Distribution

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

aniate-2.1.0-py3-none-any.whl (79.9 kB view details)

Uploaded Python 3

File details

Details for the file aniate-2.1.0.tar.gz.

File metadata

  • Download URL: aniate-2.1.0.tar.gz
  • Upload date:
  • Size: 85.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.6

File hashes

Hashes for aniate-2.1.0.tar.gz
Algorithm Hash digest
SHA256 11fb6ab380c6c2613268ff748d1c42da341fe1abdebcb53213827027ca7941b7
MD5 1301a4e91c54074834bce80675b992f7
BLAKE2b-256 56f8507f3f3b7f9e76d8ceb44c6607cc772e6b859d49e0cf7d0940b11a6906da

See more details on using hashes here.

File details

Details for the file aniate-2.1.0-py3-none-any.whl.

File metadata

  • Download URL: aniate-2.1.0-py3-none-any.whl
  • Upload date:
  • Size: 79.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.6

File hashes

Hashes for aniate-2.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4223684a3e9e7c17e5d98e72a188e997b9c3e76c516185a05cd71818c78fd0cc
MD5 dd495f0c6ab763ed6f077c3119c935ea
BLAKE2b-256 52416cc67b91edc462f77c08cda467ec3b71412c05a7b054dd2a1e76c80e6367

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

2.1.0 This release

2 files

2.0.2

2 files

2.0.1

2 files

2.0.0

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