Skip to main content

aniate

Approximate Numerics in Applied Transition Environments

pypi python tests 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.

Installation

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

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.0.2   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

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.

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
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.0.2},
  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.0.2.tar.gz (89.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.0.2-py3-none-any.whl (72.7 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for aniate-2.0.2.tar.gz
Algorithm Hash digest
SHA256 8628e1f8ab25f30b09f21682f59811a8d69d836b4f54772cf7f502c9541b0c8a
MD5 4beeea088ea7ebd6a660c8d22820ba0f
BLAKE2b-256 520d0a18a87d7098a64b1a6ed4f5eda81eb11631fe47a822a799ae4bdb2c4526

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for aniate-2.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 48a80621704a1cbf118d249fb9449cb590da32d548acf1c9bd064feaa8ff7394
MD5 91730be5c6a11a642a14fe7281635cea
BLAKE2b-256 f47579c21af21a8c01bcab44768d340799208c8415c45da9fdf64f8b1e872eca

See more details on using hashes here.

Release history Release notifications | RSS feed

2.1.0

2 files

This release

2.0.2 This release

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