Skip to main content

An instrument for quantifying structural self-determination across systems.

Project description

autonometrics

Shadows of Self-Determination

An instrument for quantifying structural self-determination across systems.

We see shadows of autonomy, calibrated and reproducible. Whether the cave behind them holds one object or many, this tool does not decide.

Status: alpha — work in progress, API unstable.


What it is

autonometrics is a Python instrument that takes a discrete trajectory — a cellular automaton, a Boolean network, an agent log, a simulation, and as of v0.8.0a0 also a system that publishes its own intended trajectory alongside its realised one — and returns up to five normalised readings of how self-determined its structure looks. Each reading comes from a different scientific tradition; together they form a small atlas of autonomy: a few charts that cover the same territory from different operational angles.

It is a measurement tool, not a new theory of autonomy. The package collects existing measures, normalises them to a shared [0, 1] scale, and lets you compare points from very different substrates in the same space.

The five axes

Axis Question it answers Tradition Reference
closure How much of the system's information is generated from inside? Information theory Shannon (1948); Bertschinger et al. (2008); Albantakis (2021)
memory How much of the system's predictability is carried by its own past? Computational mechanics Crutchfield & Young (1989); Feldman & Crutchfield (2002)
constraint How tightly do the system's constraints enable each other? Theoretical biology Montévil & Mossio (2015)
persistence How well does the system's structure resist a small perturbation? Operational goal-directedness Lee & McShea (2020)
coherence How well does the system's executed trajectory follow its declared one? Akrasia → cognitive dissonance → AI alignment Festinger (1957); Sheeran (2002); Lanham (2023); Turpin (2023)

All five readings live in [0, 1] and can be plotted, correlated and compared across substrates that expose the relevant capability. The first four require only a state / environment trajectory; the fifth additionally requires a parallel (declared, executed) pair, which only adapters with an explicit declarative layer expose. Adapters that do not implement that layer report coherence = None honestly, in line with the same dropout policy already used for constraint_closure (graph-only) and persistence (replay-only).

What the project does not claim

The five axes are not assumed to be shadows of a single underlying quantity. The current empirical picture (v0.8.0a0, 645-point synthetic benchmark) is honest about that:

  • All four v0.7.x pairwise correlations remain below |r| < 0.7 on every sub-zoo where they are jointly defined, so the four prior axes still carry distinct information.
  • The fifth axis (coherence) is empirically distinct from the first four under controlled adapters: when the PromisedCycle reference adapter is driven by two independent sources of variability rather than one, r(closure, coherence) falls from +0.97 to +0.48 and r(coherence, p_env) ≈ 0 confirms the formula's predicted invariance to declarative-side noise. Details and pre-registered analysis in docs/CBA.md and the diagnostic snapshots under docs/benchmarks/.
  • The full five-axis cloud does not exist on the current zoo: each adapter class implements either get_causal_graph (so constraint_closure is defined) or get_declared_executed (so coherence is defined), but never both, leaving n_valid_full = 0/645. The atlas is therefore best read as a mosaic / archipelago of overlapping four-axis sub-charts rather than a single five-dimensional cloud. The verdict is documented in the v0.8.0a0 follow-up of docs/ATLAS_GEOMETRY.md.

So the package ships a measurement framework, a benchmark, the dropouts, and a falsifiable working hypothesis — not a definitive theory of autonomy. The level question (one object or many?) is pulled toward Level 3 (mosaic) by the v0.8.0a0 cycle but not yet decided; the strong validation against behavioural / RAI-style data is deferred to v0.9.0, which is also the natural candidate for a substrate that finally closes the five-axis hole.

The full conceptual statement and the falsification criteria live in docs/PBA.md (English) and docs/PBA.es.md (Spanish). The pre-registered geometry analysis is in docs/ATLAS_GEOMETRY.md; per-axis design notes in docs/CONSTRAINT_CLOSURE.md, docs/RAI.md and docs/CBA.md. The release log lives in CHANGELOG.md.

Installation

From PyPI (recommended)

pip install --pre autonometrics

For the optional plotting / benchmark dependencies:

pip install --pre "autonometrics[viz]"

The --pre flag is required while the package is in alpha. Once a non-alpha release is published, plain pip install autonometrics will be enough.

From source (for development)

git clone https://github.com/bugerchip/Autonometrics.git
cd Autonometrics
pip install -e ".[dev,viz]"

Requires Python 3.10 or later. The core package depends only on numpy. The optional viz extra adds matplotlib, used by the benchmark plotting scripts.

Quickstart

Measuring a synthetic automaton

import numpy as np
from autonometrics import Autonometer, SimpleAutomaton

rng = np.random.default_rng(0)
env = rng.integers(0, 3, size=3000).astype(np.int64)

system_a = SimpleAutomaton.from_self_generated_rules(n_states=4, env=env, seed=0)
system_b = SimpleAutomaton.from_external_rules(n_states=4, env=env, seed=0)

meter = Autonometer(metrics=["albantakis", "memory"])
profile_a = meter.measure(system_a)
profile_b = meter.measure(system_b)

print(profile_a.ratio_endo_total, profile_a.memory_endo_ratio)
print(profile_b.ratio_endo_total, profile_b.memory_endo_ratio)

Measuring a CSV trajectory you already have

from autonometrics import Autonometer, CSVTrajectory

trajectory = CSVTrajectory.from_path("my_log.csv")  # header: state,env
profile = Autonometer(metrics=["albantakis", "memory"]).measure(trajectory)

my_log.csv is a two-column file with discrete integer labels:

state,env
0,1
2,1
2,0
1,0

Running the bundled demos

python examples/automaton_demo.py   # clockwork vs mixed vs noise-driven automata
python examples/csv_demo.py         # round-trip through a CSV file

Metrics

Three metrics ship in the current alpha. All three follow the PBA internal over total shape, all three live in [0.0, 1.0], and all three are exposed as pure numpy functions wired into Autonometer:

ratio_endo_total — Albantakis / Bertschinger closure

Normalised conditional mutual information of the system's next state on its own past, controlling for the environment:

$$A ;=; \frac{I(S_{t+1};,S_t \mid E_t)}{H(S_{t+1} \mid E_t)}$$

  • A = 0: the next state, given the environment, is independent of the system's own previous state (no closure, pure drift).
  • A = 1: the next state, given the environment, is fully determined by the system's own previous state (closed dynamics).

memory_endo_ratio — distributed structural memory

Fraction of the structural memory present in the joint (system, environment) trajectory that is carried by the system itself, computed via Crutchfield's excess entropy on each component and then normalised:

$$M ;=; \frac{E(\text{states})}{E(\text{states}) + E(\text{env})}$$

with E(.) estimated via block-entropy saturation E = H(L) - L · h_μ, where h_μ = H(L) - H(L-1). The working block length is capped by a Grassberger-style rule so every possible block gets about ten samples on average.

  • M = 0: the joint memory lives entirely in the environment (or, by convention, neither sequence carries memory at all).
  • M = 1: the joint memory lives entirely in the system.
  • M ≈ 0.5: memory is shared roughly equally between system and environment.

This replaces the absolute-bit structural_memory shipped in v0.3.x. Returning a magnitude in bits broke the unifying ratio shape of the package; memory_endo_ratio recovers PBA coherence by applying the same excess-entropy estimator to both components and returning the fraction carried by the system.

constraint_closure — Montévil & Mossio-style organisational closure

Fraction of the system's update functions (constraints) that lie on at least one simple directed cycle of length 2 or 3 in the causal-dependency graph. The metric reads only the topology of the graph: it is deliberately information-theory-free, so any empirical correlation with the two axes above is structural rather than algebraic.

$$C ;=; \frac{|\{i : \exists \text{ simple cycle of length } 2 \text{ or } 3 \text{ through } i\}|}{n}$$

with n the number of constraints in the system and the dependency matrix exposed by each adapter via get_causal_graph().

  • C = 0: no constraint is sustained by another distinct constraint of the same system through a short feedback loop. Single-node systems (a periodic cycle, a SimpleAutomaton) and pure feed-forward chains land here.
  • C = 1: every constraint is on at least one such loop. Periodic-ring cellular automata land here because each cell is read by both of its neighbours, which read it back.
  • Length-1 cycles (self-loops) and length ≥ 4 cycles do not count: the metric targets the local "membrane ↔ metabolism" shape Montévil & Mossio describe, and the short-cycle restriction prevents systems that close only after a long detour from getting free credit.

Operationalisation choices, falsification predictions and the domain-of-applicability discussion live in docs/CONSTRAINT_CLOSURE.md.

All three scores are returned in a single AutonomyProfile with Optional[float] fields, so unrequested metrics stay None. Adapters that cannot expose a causal graph (e.g. CSVTrajectory, where only trajectories are available) make the orchestrator record None for constraint_closure rather than abort the whole measurement.

The autonomy plane

Thinking of the two metrics together, rather than reducing autonomy to a single number, gives a richer picture. Both axes share the PBA ratio shape and live in [0, 1], so (closure, memory) defines a canonical autonomy plane [0, 1] × [0, 1]. The four quadrants fall out of a single 0.5 threshold on each axis:

memory ↓ / closure → low closure (< 0.5) high closure (≥ 0.5)
low memory (< 0.5) drift (noise-driven) clockwork regularity
high memory (≥ 0.5) turbulence / chaos candidate autopoietic region
  • Drift (low closure, low memory): the system tracks the environment and keeps nothing.
  • Clockwork (high closure, low memory): determined by its own past, but the environment also carries comparable memory; the system's contribution to joint memory is modest.
  • Turbulence (low closure, high memory): the environment shapes the system, and the bulk of the joint memory still ends up associated with the system's trajectory rather than the environment's — long-range but non-self-generated structure.
  • Autopoietic region (high closure, high memory): closed dynamics and the joint memory is dominated by the system itself — the empirically interesting corner for systems with non-trivial self-organisation.

The package does not claim to prove autopoiesis. It gives a two-coordinate reading on a homogeneous plane and lets the interpreter argue.

Benchmark

v0.5.0a0 shipped the first reference benchmark on two axes; v0.6.0a0 extended it to the third axis (constraint_closure); v0.7.0a0 added the fourth axis (rai_proxy_persistence) without changing the system zoo. v0.7.2a0 (this release) re-runs the four-axis benchmark with n_seeds raised from 5 to 30 to clear the 200-valid-point floor pre-registered in docs/ATLAS_GEOMETRY.md for the atlas-geometry analysis. Adapter classes and parameter values are unchanged, so all results are directly comparable with the two prior baselines. The intent is not to score one system as "more autonomous" than another. It is to check whether the four axes carry distinct information for the systems we can generate today, before adding a fifth axis to PBA.

Reproducing the run:

pip install -e ".[dev]"
python examples/benchmark_demo.py        # writes docs/benchmarks/v0.7.2a0.csv
pip install -e ".[dev,viz]"
python examples/benchmark_plot.py        # writes docs/benchmarks/v0.7.2a0.png

Headline numbers from the snapshot shipped here (docs/benchmarks/v0.7.2a0.csv):

Quantity Value
Configurations swept 405
Fully-valid points 247
Configurations dropped (n/a) 158 (39%)
Pearson r(closure, memory) +0.27
Pearson r(closure, constraint) +0.04
Pearson r(closure, persistence) -0.61
Pearson r(memory, constraint) -0.52
Pearson r(memory, persistence) -0.33
Pearson r(constraint, persistence) -0.07
Spearman r(closure, memory) +0.47
Spearman r(closure, constraint) -0.20
Spearman r(closure, persistence) -0.47
Spearman r(memory, constraint) -0.34
Spearman r(memory, persistence) -0.33
Spearman r(constraint, persistence) -0.01
Falsification threshold `
Aggregate diagnosis OK

The 158 dropped configurations correspond to systems whose focal trajectory collapses to a constant or to a value fully determined by the environment, in which case H(S_{t+1} | E_t) = 0 and the closure ratio is undefined by construction. They concentrate on ECASystem (55% adapter-internal dropout) and KauffmanNetwork (51%); PeriodicCycle and SimpleAutomaton have zero dropouts. The pattern is itself a structural finding — the metric set has a joint blind spot selective for the cellular and network adapters — and is documented in docs/ATLAS_GEOMETRY.md. Dropouts are kept in the CSV with empty metric columns so the dropout is visible rather than hidden.

All six pairwise Pearson correlations stay below the |r| < 0.7 falsification threshold documented in docs/PBA.md, now on the extended sample of 247 valid points. The aggregate flag is the worst of the six pairwise flags so a single overlap is enough to raise it.

The three pairs involving the persistence axis sit inside the |r| < 0.7 band on the extended sample as well: closure-persistence at −0.61, memory-persistence at −0.33, and constraint-persistence at −0.07. This is the empirical correlation gate pre-registered in docs/RAI.md ("Empirical correlation |r| < 0.7 on the benchmark zoo"). Together with the static no-cross-import audit baked into compute_rai_proxy_persistence, it is the falsification criterion the fourth axis had to clear before being considered a fourth dimension of the autonomy atlas rather than a re-skin of an existing axis. The closure–persistence correlation has tightened from −0.44 (v0.7.0a0) to −0.61 (v0.7.2a0) on the larger sample, but still sits below the falsification threshold; the same closure–persistence pair also flips to −0.07 within KauffmanNetwork and to −1.00 within SimpleAutomaton, raising the Simpson's-paradox health flag analysed in docs/ATLAS_GEOMETRY.md.

The third axis cleanly breaks the closure-saturation wall identified in v0.5.0a0: single-node periodic cycles and self-generated SimpleAutomaton systems, which previously sat indistinguishably from ECA rings on the vertical line closure = 1.0, now drop to constraint = 0.0 while ECA rings stay at constraint = 1.0. The wall is therefore not resolved (closure still saturates by construction in fully-observed deterministic systems) but it is no longer the only readable signal.

A scatter rendering of the same CSV — points placed on the (closure, memory) plane, with marker size proportional to the constraint axis — is shipped at docs/benchmarks/v0.7.2a0.png, and the captured stdout of the reference run lives at docs/benchmarks/v0.7.2a0.log.txt for traceability. The persistence axis is reported in the CSV's fourth metric column and is rendered separately as a domain-of- applicability curve under docs/benchmarks/persistence_v0.7.0.png. The two-axis baseline from v0.5.0a0 (csv / png), the three-axis snapshot from v0.6.0a0 (csv / png), and the four-axis short-sample snapshot from v0.7.0a0 (csv / png) are kept under docs/benchmarks/ for traceability.

Atlas geometry analysis (v0.7.2a0)

v0.7.2a0 ships a pre-registered geometric audit of the four-axis cloud, designed before any extended-sweep data was seen. The full pre-registration, threshold table, implementation report, and verdict live in docs/ATLAS_GEOMETRY.md. Headline indicators on the 247 valid points:

Indicator Value Pre-registered band
λ_1 0.469 [0.40, 0.70) — inconclusive
λ_1 + λ_2 0.809 [0.65, 0.85) — partial low-D
s(k* = 5) (silhouette, k-means) 0.642 ≥ 0.50 — strong cluster
Adapter-class alignment 4 of 5 clusters dominated by one class

The combination is not a clean fit to any of the three pre-registered outcomes (Level 2 reinforced, inconclusive, Level 3 suspected); per the resolution rule pre-registered in docs/ATLAS_GEOMETRY.md, the verdict is

Inconclusive on the level question (PCA reading), with a Level-3-suggestive overlay (clustering reading).

A Simpson's-paradox health flag is also raised: several global pairwise correlations are partly artefacts of the substrate composition of the zoo (the most extreme case is closure–persistence, global −0.61 vs −1.00 within SimpleAutomaton alone). The level question — Level 2 (one multidimensional object) vs Level 3 (several objects sharing a label) — is therefore genuinely under-determined on the structural domain and is pushed to v0.9.0's behavioural validation against transcript-based RAI for a clean arbitration.

Reproducing the analysis:

pip install -e ".[dev]"
python examples/atlas_geometry.py        # writes docs/benchmarks/atlas_geometry_v0.7.2a0.json
pip install -e ".[dev,viz]"
python examples/atlas_geometry_plot.py   # writes docs/benchmarks/atlas_geometry_v0.7.2a0.png

The biplot (docs/benchmarks/atlas_geometry_v0.7.2a0.png) renders the PCA scree (with the pre-registered λ_1 ≥ 0.70 reference line) and the PC1/PC2 projection of the standardised 4-D cloud with axis loadings drawn as labelled arrows. t-SNE / UMAP panels are deliberately omitted; the pre-registration flagged them as illustrative-only because they can manufacture visual clusters from isotropic noise.

Saturation diagnostic (v0.5.1a0)

The most visible feature of the scatter above is the vertical wall of points at closure = 1.0. The v0.5.1a0 diagnostic shows that this wall is a theorem about the metric, not a flaw: any deterministic system whose observed (S, E) pair already covers every variable the transition rule depends on satisfies H(S_{t+1} | S_t, E_t) = 0, which forces I(S_{t+1}; S_t | E_t) = H(S_{t+1} | E_t), which forces closure = 1.0. Three of the four adapter classes in the benchmark (ECA, PeriodicCycle, self-generated SimpleAutomaton) satisfy those preconditions; the fourth (KauffmanNetwork) breaks them on purpose, which is why it is the only adapter whose closure values vary continuously across the unit interval.

To verify the theorem empirically, the diagnostic injects Bernoulli bit-flip noise into the focal trajectory of a saturating ECA (rule 110) at probabilities p ∈ {0, 0.01, …, 0.50} and re-measures closure. The expected behaviour is a smooth, monotonic fall off the wall.

pip install -e ".[dev]"
python examples/saturation_diagnostic.py        # writes docs/benchmarks/saturation_v0.5.1.csv
pip install -e ".[dev,viz]"
python examples/saturation_plot.py              # writes docs/benchmarks/saturation_v0.5.1.png

Headline numbers from the snapshot shipped here (docs/benchmarks/saturation_v0.5.1.csv, 10 noise levels × 5 seeds = 50 valid points):

Noise probability p closure (mean ± std) memory (mean ± std)
0.00 1.000 ± 0.000 0.569 ± 0.033
0.01 0.810 ± 0.051 0.536 ± 0.021
0.05 0.434 ± 0.055 0.405 ± 0.016
0.10 0.234 ± 0.032 0.284 ± 0.045
0.20 0.059 ± 0.010 0.121 ± 0.030
0.50 0.001 ± 0.001 0.070 ± 0.010

The full curve is rendered at docs/benchmarks/saturation_v0.5.1.png. Two practical reads:

  • The wall at closure = 1.0 is fragile, not robust. A 1 % per-step bit-flip rate already drops closure to 0.81, and closure converges to zero by p ≈ 0.3.
  • A closure value strictly below 1.0 is therefore informative. In practice it signals partial observation, stochastic dynamics or measurement noise — exactly the three failure modes the metric is designed to detect.

The formal statement of the theorem and its consequences for PBA live in docs/PBA.md § "Domain of applicability" (Spanish: docs/PBA.es.md).

Constraint-closure density diagnostic (v0.6.1a0)

The constraint-closure axis introduced in v0.6.0a0 carries its own pair of boundary regions, formalised as theorems and verified with the same diagnostic-grade rigour the closure axis got in v0.5.1a0:

  • Theorem A — single-constraint trivial-zero. Any system with n = 1 update function returns constraint = 0.0 by construction (a simple cycle of length 2 or 3 requires at least two distinct nodes). Covers PeriodicCycle and SimpleAutomaton.
  • Theorem B — symmetric-neighbour saturation. Any graph in which every node reads at least one node that reads it back returns constraint = 1.0 by construction (every node sits on a length-2 cycle). Covers ECASystem on any non-trivial periodic ring.

To verify both theorems jointly, the diagnostic sweeps the connection density of a controllable system. For each K ∈ {1, …, n − 1} it generates several Kauffman networks of size n and computes constraint_closure directly from the causal graph (no trajectory needed; the metric is purely topological).

pip install -e ".[dev]"
python examples/constraint_density_diagnostic.py        # writes docs/benchmarks/constraint_density_v0.6.1.csv
pip install -e ".[dev,viz]"
python examples/constraint_density_plot.py              # writes docs/benchmarks/constraint_density_v0.6.1.png

Headline numbers from the snapshot shipped here (docs/benchmarks/constraint_density_v0.6.1.csv, 9 K values × 10 seeds = 90 measurements at n = 10):

Input degree K constraint (mean ± std)
1 0.140 ± 0.120
2 0.520 ± 0.236
3 0.790 ± 0.138
4 0.950 ± 0.067
5 0.980 ± 0.060
6 1.000 ± 0.000
7 1.000 ± 0.000
8 1.000 ± 0.000
9 1.000 ± 0.000

The full curve is rendered at docs/benchmarks/constraint_density_v0.6.1.png.

Two practical reads:

  • The metric is a monotone sigmoid in connection density. At K = 1 it sits near Theorem A's lower boundary; at K ≥ 6 (with n = 10) every seed identically saturates at 1.0 (std = 0), reaching Theorem B's upper boundary.
  • A constraint-closure value of 0.0 does not mean "no autonomy". On a single-constraint adapter the metric is silent by Theorem A; the system simply sits outside its discriminative domain. Symmetrically, 1.0 does not mean "fully autonomous" — on a dense periodic ring it is forced by Theorem B regardless of dynamical content.

Both theorems and the diagnostic are documented in docs/CONSTRAINT_CLOSURE.md § "Domain of applicability" and reflected in docs/PBA.md § "Domain of applicability" (Spanish: docs/PBA.es.md).

Persistence-vs-coupling diagnostic (v0.7.0a0)

The persistence axis added in v0.7.0a0 ships with a first domain-of-applicability run that sweeps the focal coupling of a KauffmanNetwork. The naïve expectation was a monotone rise ("low coupling → focal flip propagates → low persistence; high coupling → focal flip invisible → high persistence"). The diagnostic falsified that expectation and revealed a U-shape with two trivial-absorption boundary regimes flanking a non-trivial middle.

pip install -e ".[dev]"
python examples/persistence_diagnostic.py        # writes docs/benchmarks/persistence_v0.7.0.csv
pip install -e ".[dev,viz]"
python examples/persistence_plot.py              # writes docs/benchmarks/persistence_v0.7.0.png

Headline numbers from the snapshot shipped here (docs/benchmarks/persistence_v0.7.0.csv, 11 coupling levels × 10 seeds at n = 10, k = 3):

Focal coupling persistence (mean ± std) n_valid / n_total
0.00 1.000 ± 0.000 6 / 10
0.10 1.000 ± 0.000 6 / 10
0.20 – 0.50 0.556 ± 0.453 8 / 10
0.60 – 0.80 0.415 ± 0.465 9 / 10
0.90 0.665 ± 0.406 9 / 10
1.00 0.665 ± 0.406 9 / 10

The full curve is rendered at docs/benchmarks/persistence_v0.7.0.png. Two practical reads:

  • Low-coupling boundary (coupling ≈ 0). Most seeds drop because the focal trajectory collapses to a constant (a 1-bit rule generally has a fixed point). The seeds that survive score persistence ≈ 1 not because the system defends its trajectory, but because the perturbation is absorbed by the fixed point in one step. This is trivial absorption by collapse, not autonomy.
  • High-coupling boundary (coupling ≈ 1). The focal node ignores its own previous value, so the focal flip never enters the rule that computes the focal at t_star + 1. The metric returns persistence ≈ 1 by construction. This is trivial absorption by invisibility, again not autonomy.

The non-trivial useful range of the metric on Kauffman networks sits in the intermediate couplings, where actual perturbation propagation is observed. The U-shape is the persistence analogue of the closure-saturation theorem (v0.5.1a0) and the symmetric-neighbour saturation theorem for constraint-closure (v0.6.1a0): the metric has structurally trivial regions at the edges of its parameter space and a non-trivial useful range in the middle. Formalising the two boundary theorems for persistence (jointly with the deferred perturbation-magnitude sweep) is the planned content of the v0.7.1 maintenance cycle.

Adapters

  • SimpleAutomaton — two factory constructors (from_self_generated_rules, from_external_rules) for synthetic toy systems.
  • CSVTrajectory — loads a user-supplied two-column CSV with discrete integer state and env columns.
  • LLM transcript — planned for a later alpha.

Any object implementing get_state_history() and get_env_history() (both returning 1D integer np.ndarray) satisfies the AutonomySystem protocol and can be passed to Autonometer.measure.

Theoretical grounding

autonometrics does not introduce a new theory of autonomy. It operationalises a recurring ratio of internal over total shape that already runs through several traditions in the structural self-determination literature. The intended scope and the falsification criteria for that unifying claim are stated in docs/PBA.md; the references the current axes build on are:

  • Bertschinger, N., Olbrich, E., Ay, N., & Jost, J. (2008). Autonomy: An Information-Theoretic Perspective. BioSystems — introduces the conditional-information core measured by the closure axis.
  • Albantakis, L. (2021). Quantifying the Autonomy of Structurally Diverse Automata: A Comparison of Candidate Measures. Entropy — comparative review and the normalisation form used here.
  • Crutchfield, J. P., & Young, K. (1989). Inferring statistical complexity. Physical Review Letters — introduces excess entropy, the engine behind the memory axis.
  • Feldman, D. P., & Crutchfield, J. P. (2002). Measures of Statistical Complexity: Why?. Physics Letters A — formal critique of LMC-style "balance" measures that drove the migration done in v0.3.0-alpha.
  • Farnsworth, K. D. (2018). How Organisms Gained Causal Independence and How It Might Be Quantified. Biology — argues that autonomous agency requires two jointly necessary features (organisational closure and an internalised objective-function providing a 'goal'), and proposes Integrated Information Theory as a possible quantification. The two-axis shape of the plane here is inspired by this dual-feature thesis, not a literal implementation of it: the memory ratio is a structural proxy for ongoing activity, not an objective-function measurement.
  • Montévil, M., & Mossio, M. (2015). Biological organisation as closure of constraints. Journal of Theoretical Biology — formal framework where biological organisation is read as mutual dependence among constraints (each both produced by and producing the others). Reference for the constraint_closure axis shipped in v0.6.0a0; the operational mapping from the paper's primitives to the package's discrete-graph implementation is documented in docs/CONSTRAINT_CLOSURE.md.

Related work

autonometrics overlaps with several adjacent toolkits. The relevant difference is framing, not the underlying mathematics: none of the tools below collects information-theoretic measures under a single internal-over-total ratio convention, and most are either deeper (and substrate-bound) or more general (and unframed).

  • Albantakis/autonomy — toolbox for comparing autonomy measures on small simulated agents represented as transition probability matrices. Authored by the same researcher whose 2021 review article this package builds on. Requires PyPhi, runs on Linux and macOS only, and outputs a multi-column DataFrame intended for cross-measure comparison rather than a single normalised reading. autonometrics does not depend on it: the closure-axis formula is reimplemented in pure numpy so the package runs on Linux, macOS and Windows alike, and so it accepts arbitrary discrete trajectories instead of pre-built transition probability matrices.
  • JIDT — Java toolkit for information-theoretic measures (transfer entropy, active information storage, predictive information / excess entropy, mutual information). The numerical engine many adjacent papers build on; cross-language but not a unified autonomy index.
  • PyInform — Python wrapper on the Inform C library. Provides active_info, block_entropy, entropy_rate, transfer_entropy and related building blocks.
  • PyPhi — reference IIT implementation (Φ, MIP) on transition probability matrices. A different formalism from the closure axis used here; a possible optional dependency for an IIT-based axis later in the roadmap.
  • dit — general discrete information theory toolkit (PID, divergences, multivariate measures). A candidate numerical dependency for future axes that need partial information decomposition.

The cross-platform, dependency-light stance is deliberate. The package targets researchers, students and applied users who want a working measurement on whatever machine they have, including Windows. Pure-numpy implementations are preferred over heavier dependencies until a future axis genuinely needs them; if that ever happens, the heavy dependency will be opt-in via extras_require rather than mandatory.

Roadmap

Each future alpha adds one more [0, 1]-valued ratio drawn from the structural self-determination literature, keeping the same PBA convention so all axes remain comparable. The order below prioritises empirical validation of the existing axes before broadening them: the first benchmark run shipped in v0.5.0a0 established that closure and memory carry distinct information on the current adapter zoo, the v0.5.1a0 diagnostic mapped the closure = 1.0 saturation wall, v0.6.0a0 added the third axis to break that wall while preserving pairwise independence, v0.6.1a0 mapped the two saturating regions of constraint_closure, v0.7.0a0 added the fourth axis (rai_proxy_persistence) and revealed its U- shaped domain of applicability, v0.7.2a0 ran a pre-registered geometric audit of the four-axis cloud whose verdict pushed the Level 2 vs Level 3 question to v0.9.0, and v0.8.0a0 added the fifth axis (coherence / Theil's U) together with its reference adapter PromisedCycle, ran the Session B diagnostic block (independence audit + causal experiment with p_env) that overrode the pre-registered hard gate on causal grounds, and shipped the mosaic-atlas verdict (n_valid_full = 0/645: no system in the current zoo has all five axes simultaneously, so the atlas is best read as overlapping four-axis sub-charts rather than a single five-dimensional cloud).

  • v0.5.0-alpha: benchmark suite + scatter plot. Reference systems (ECASystem, KauffmanNetwork, PeriodicCycle) wired into a sweep that measures (closure, memory) over multiple seeds and reports correlation against the PBA falsification threshold.
  • v0.5.1-alpha: saturation diagnostic. Bernoulli bit-flip noise sweep on a saturating ECA, formal statement of the closure-saturation theorem, and the "domain of applicability" section in docs/PBA.md.
  • v0.6.0-alpha: third axis — constraint_closure (Montévil & Mossio-style). Per-adapter causal-graph implementations, three-axis benchmark snapshot with three pairwise correlations, and an independence-by-design audit.
  • v0.6.1-alpha: domain-of-applicability diagnostic for constraint_closure. Formal statement of the single-constraint trivial-zero theorem and the symmetric-neighbour saturation theorem; Kauffman density sweep snapshot under docs/benchmarks/constraint_density_v0.6.1.*.
  • v0.7.0-alpha: fourth axis — rai_proxy_persistence (Lee & McShea-style perturbation persistence, RAI-style structural proxy). Adapter-side replay_from_perturbation protocol, four-axis benchmark snapshot with six pairwise correlations (all |r| < 0.7), and a first persistence-vs-coupling diagnostic that revealed the U-shape boundary regimes. Pre-registered in docs/RAI.md.
  • v0.7.1-alpha: domain-of-applicability cycle for rai_proxy_persistence. Formal statement of the two boundary theorems (low-coupling collapse and high-coupling invisibility), perturbation-magnitude sweep already deferred there in docs/RAI.md, and the same diagnostic-grade rigour the prior axes already enjoy. Intentionally skipped in the chronological release order; the boundary theorems and the magnitude sweep land here.
  • v0.7.2-alpha: pre-registered atlas-geometry analysis. PCA
    • k-means + silhouette + conditional correlations on the extended four-axis benchmark (n_valid = 247). Pre-registered in docs/ATLAS_GEOMETRY.md. Verdict: inconclusive on the level question (PCA reading), with a Level-3-suggestive overlay (clustering reading); the level question is pushed to v0.9.0's behavioural validation.
  • v0.8.0-alpha (current): fifth axis — coherence-based alignment (cba_theil_u, Theil's U on declared vs executed trajectories with Miller-Madow bias correction). New reference adapter PromisedCycle with optional independent declared-channel noise (p_env); new optional protocol method get_declared_executed; new AutonomyProfile.cba_theil_u field. Pre-registered in docs/CBA.md. Five-axis benchmark snapshot at docs/benchmarks/v0.8.0a0.{csv,log.txt}. Session B ships three diagnostic snapshots: cba_independence_v0.8.0a0.{json,png,log.txt} (stratified audit, Simpson's-paradox visualisation), cba_env_decouple_v0.8.0a0.{json,png,log.txt} (causal experiment with p_env, r(closure, coherence) falls from +0.97 to +0.48 and r(coherence, p_env) = +0.0007 confirms Theil's U invariance), and the v0.8.0a0 follow-up of ATLAS_GEOMETRY.md (Step 7 verdict: n_valid_full = 0/645, atlas is a mosaic of overlapping four-axis sub-charts). Pre-registered hard gate (|r| ≥ 0.9) was triggered by the headline +0.96 and then overridden on causal grounds with the override documented in the post-mortem section of docs/CBA.md. Level question pulled toward Level 3, decided (or stays open) at v0.9.0.
  • v0.9.0-alpha: LLM transcript adapter (bring-your-own labels) and additional public-dataset benchmarks. Behavioural validation pass: arbitrates Level 2 vs Level 3 against transcript-based RAI, the test the structural geometry cannot run alone.
  • v1.0.0 (without alpha marker): PyPI publication once five ratios, three adapters, and the full benchmark battery are stable.

License

MIT. See LICENSE.

Project details


Download files

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

Source Distribution

autonometrics-0.8.0a0.tar.gz (1.2 MB view details)

Uploaded Source

Built Distribution

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

autonometrics-0.8.0a0-py3-none-any.whl (56.1 kB view details)

Uploaded Python 3

File details

Details for the file autonometrics-0.8.0a0.tar.gz.

File metadata

  • Download URL: autonometrics-0.8.0a0.tar.gz
  • Upload date:
  • Size: 1.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for autonometrics-0.8.0a0.tar.gz
Algorithm Hash digest
SHA256 1a975b2980178edada68efb735e80a56f01caa316e19f4f34c28949413234570
MD5 6dc3a36411d99366a32b5ccf06ac8f04
BLAKE2b-256 1d0baad1a52517d9571a2b9a7fb23b0ed586c3e780b8ddfdecec4137a5930fb9

See more details on using hashes here.

File details

Details for the file autonometrics-0.8.0a0-py3-none-any.whl.

File metadata

File hashes

Hashes for autonometrics-0.8.0a0-py3-none-any.whl
Algorithm Hash digest
SHA256 4eb0c04931fb9d4624247bceeac1c4e302ae9e612c527152996f4c1f13adef4b
MD5 f9f473483695abe3309e98b00d7f71fd
BLAKE2b-256 e4472b0cda081b51cafbe3a301549d26235c55173d2493ed2dd04a2a49b0dfaa

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page