Skip to content

Repository files navigation

Intelligence from first principles

A dynamic model that starts from a single unit trying not to fall apart, and climbs (by one rule, applied over and over at larger scales) to something that holds a model of its world and of itself in it, acts and plans to stay there, goes looking for what it does not yet know, and, coupled to its kind, becomes a society that divides the labour of knowing.

This is not a metaphor written down. It is a small, runnable dynamical system. Every claim below is measured by run.py a few lines after the code that earns it, and nothing in the list of emergent behaviours was programmed in; each is a side effect of the rule underneath it.

python run.py            # the whole ascent (~2-3 min): prints a report, writes figures/
python run.py --quick    # a faster look

The one principle

Start from the only thing that is true of everything alive:

To persist in a changing world, a thing must act to keep its essential variables inside a viable band; and the cheapest way to do that is to predict what would push it out, and cancel it before it lands.

That is the whole engine. A single unit obeying it is a homeostat. The one non-obvious move is this:

A population of coupled homeostats; each treating the others as part of the world it must stay viable within: is itself a homeostat at the next scale up.

So the rule is recursive. Compose regulators and you get a regulator; compose those and you get another. Make the regulation predictive and stack it deep enough, and the higher reaches of the stack stop looking like thermostats and start looking like minds. The claim of this model is that the distance between those two things is depth, coupling, and scale; not kind.


The ladder

Each rung is literally the rung below it, coupled and made predictive. The right-hand column is a number run.py prints on the default seed.

Level In a body The mechanism Code What emerges (measured)
0 a cell a unit acts to hold its essential variable in band unit.py, gains in hierarchy.py regulation; a self-repairing mesh; units held at their set point
1 a tissue coupled units, each defending only itself unit.py joint viability found in 5 reconfigurations; a lesion re-solved in 2
2–3 organs & cortex the same motif made predictive and stacked hierarchy.py a hidden concept made explicit (0.81 → 0.95); a timescale hierarchy (τ 1 → 22)
4 a brain a workspace that regulates the hierarchy as its body workspace.py, organism.py attention; ignition (2.6× at each scene change); a self-model (0.93)
a body that acts the same descent run backwards: change the world, not the belief body.py, agent.py staying alive (0% → 100%); learning the world's grip (R² 0.74)
a mind that plans the model run forward in imagination, to choose a survivable future planner.py, plan.py surviving a shock no reflex can (peak 0.95 → 0.37); a horizon of foresight
on two timescales a slow planner sets sub-goals for a fast one: reach as the product of horizons hplanner.py, hplan.py reaching a goal past a basin that traps flat search (0/6 → 6/6)
a mind that explores the epistemic half: act to reduce uncertainty, not only to reach safety curiosity.py, explore.py touring the unknown (6/6 vs 2/6); ready for a demanded site (0.06 vs 0.15)
a mind of minds couple whole agents; they communicate and divide the labour society.py, swarm.py a society learns its world 4× faster than one, and tiles it (8/8, none twice)

Level 0: a unit that stays viable · unit.py

A unit has an essential variable and a narrow comfort band. It has no goal handed to it from outside; its only imperative is the tautology of persistence: stay in band or stop being a well-defined thing. It regulates on two timescales: it settles along its dynamics (fast), and if it still sits out of band it re-draws its own wiring at random until it doesn't (slow). That second move (Ashby's ultrastability) is structural self-repair: the unit changes what it is until what it is can persist.

Inside the organism, the same Level-0 imperative lives in every neuron as an intrinsic gain it tunes to hold its own average activity at a set point (homeostatic plasticity). This is not decoration: turn it off and the units drift off their set point (mean activity 0.18 → 0.30) and the code they learn gets worse (identity decodable 0.94 → 0.87). Level 0 pays its way.

homeostasis

Level 1: a mesh that finds, loses, and re-finds joint viability · unit.py

Couple the units (each one's output is part of what every other one senses) and something appears that no unit contains. By nothing but each unit locally defending its own band, the mesh as a whole searches for a configuration in which all of them are viable at once, and finds it. Pin one unit out of band (a lesion) and the disturbance propagates, knocks neighbours out, and the mesh re-converges on a new joint solution. Collective regulation and self-healing, from purely local imperatives, with nothing that could be called a controller.

mesh

Levels 2–3: the same motif, made predictive · hierarchy.py

A homeostat that only reacts is always a step behind the world. The move that turns regulation into intelligence is to predict the disturbance and cancel it in advance. Stack units that each predict the layer below and pass up only their residual: the part they got wrong. Two things then happen without being asked:

  • Abstraction. The world here hides one thing worth knowing: which object is present, a slow latent, buried in fast noise, that a single frame cannot settle. A high layer can only cancel the error rising from below by discovering that latent, so it is pressured into representing a concept nobody supplied. Identity is barely readable in the raw signal (0.81) and nearly perfect two layers up (0.95).

  • A hierarchy of timescales. Inference is warm-started from the previous instant: a representation, once found, persists until contradicted. A layer that has locked onto a slow cause therefore barely moves, while the layer clamped to the raw signal jitters with the noise. Slow abstractions ride on fast detail, for free, out of persistence alone (τ climbs 1 → 11 → 20 → 22, the top matching the world's object dwell).

Learning is local and Hebbian (error-below × activity-above); there is no backpropagation and no global teacher.

abstraction

The descending predictions are not passive read-outs; they are set-points. The value a higher level expects becomes the target the level below is measured against, and together they regenerate the hidden, noise-free cause of the sensory stream (R² = 0.51). Silence the hierarchy and that prediction is zero: the organism would face every noisy detail unarmed. The abstract levels are doing the concrete level's regulation for it; which is exactly what a goal is.

reconstruction

Level 4: the workspace: the regulator of the regulator · workspace.py

A body has one budget and can fall apart only once, so something must arbitrate across the whole hierarchy: decide, moment to moment, which sub-problem most threatens the organism, and throw the shared resources at it. That is all this level is: the same homeostat once more, one scale up, with the hierarchy itself as the body it keeps viable. It does four things, all facets of that one job.

  • Attention is precision. It watches the surprise streaming out of every level and pours a limited precision budget onto whichever level is most surprising, turning up the gain on that level's errors so they dominate the next round of inference. Attention is where the body spends itself.

  • Ignition. When one level's surprise sharply dominates, the allocation collapses onto it and the whole system briefly reorganises around that one thing. Every time the world changes what it presents, a wave of ignition sweeps the workspace (2.6× above rest, right at onset) then subsides as the hierarchy re-explains the scene. A local event, made globally available.

ignition

  • A self-model. It keeps a running estimate of global viability and a compact summary of the organism's own top-level state: a model the system holds of itself, in the only terms that matter to it: am I, as a whole, holding together? When a brand-new object; one it has no representation for, appears, the organism gives it a distinct top-level code at once (recall 0.94, chance 0.20), its self-modelled viability dips the moment the newcomer is present, and its self-state linearly reports "I am facing something new" at 0.93 accuracy (chance 0.50).

  • Open-ended adaptation, and honest limits. Does it merely detect the new, or assimilate it? That depends on signal-to-noise, and the model says so cleanly. When the newcomer clears the noise floor, its surprise relaxes back toward baseline as the organism builds a model of it (ultrastability, now at the scale of the whole animal). Near the noise floor, it can only flag it. The failure is graceful, not catastrophic; and the SNR-graded transition is itself a prediction of the model, not a knob.

self-model


Closing the loop: action, the efferent half · body.py, agent.py, act.py

Everything above is afferent: the organism fitting its beliefs to the world. But the founding principle has two halves: a thing persists by keeping its essential variables in band, and it does so by acting. A homeostat that can only perceive is half a regulator. So give the organism a body: an internal milieu e with an innate set-point, which whichever object is present pushes in a direction of its own. Left alone, e walks out of its viable band and the organism, in the only sense this model knows, dies. Its one lever is action; and the right action depends on which object is present, which is exactly the hidden thing the hierarchy learned to infer. Here, at last, is what all that modelling was for.

Action is the same free-energy descent run the other way. Instead of changing its beliefs to match the world, the organism changes the world to match its beliefs; and its innate belief is I expect to be at my set-point, so acting on it just is acting to stay alive. Each instant it perceives the object, predicts how the object is about to push the body (a forward model learned by living), and exerts the effort that cancels that push (the one-step free-energy-minimising action). Two ablations price each half of the loop:

  • Cut action. A flawless perceiver, unable to act, watches its milieu diverge and dies: 0% alive. Knowing the world does not, by itself, keep you in it.
  • Cut perception. The agent survives on reflex alone (correcting the error it already has) but permanently one step behind the world, at twice the strain (mean discomfort 0.26 vs 0.12). Only the whole loop anticipates.

And by living, the agent learned the world's grip on its own body: its predicted push matches the true one at R² = 0.74.

agency value

Then ultrastability returns, now on the action side. Reverse the world's grip (prism goggles for the body, where the effort that helped now hurts) and the learned model is suddenly, exactly backwards. Discomfort spikes past the edge of viability (peak 0.64, band 0.55); and then the very same local relearning that healed the mesh at Level 1 inverts the forward model, and the agent recovers control of its body.

adaptation


Planning: imagining futures, and acting now to survive them · planner.py, plan.py

The agent of the last chapter is still a reflex: it cancels the push in front of it and never looks past the next instant. But a reflex cannot act before a disturbance, and some disturbances cannot be survived any other way. Give the body inertia, and let the world deliver a shock five times larger than a single effort can absorb. React to it and you are thrown clean out of the viable band. The only way through is to see it coming and brace.

That bracing is planning, and planning here is nothing new; it is the generative model run forward, off-line, in imagination. The agent rolls out many candidate courses of action through its model of its own body and the coming world, scores each imagined future by how far it strays from the set-point (expected free energy), and acts on the first step of the best one. Three things follow:

  • A reflex dies where a planner lives. Reacting, the shock throws the body to 0.95: well past the band (0.60), and in this model, dead. Foreseeing it, the planner braces early and peaks at just 0.37, never leaving the band.
  • Foresight is worthless without a model of what's coming. A planner that looks ahead but imagines a calm future (blind to the shock) does no better than the reflex; it does worse (peak 1.38), lulled into complacency. Perception and planning are one system: you can only plan around what your model says is coming.
  • The deeper you look, the better you cope: up to the lead the shock demands. One step of foresight is a reflex and dies; about four steps clears the band; beyond that, more lookahead only steadies it. A horizon of foresight: the action-side echo of the hierarchy of timescales perception grew.

planning

The trajectory says it best: the planner (blue) dips the wrong way just before each shock (building the counter-velocity the shock will cancel) and rides through inside the band, while the reflex spikes out the top a moment too late.

horizon

Deeper still: a hierarchy of horizons · hplanner.py, hplan.py

Flat foresight has a ceiling. Set the goal far away, behind a stretch of costly ground, and a single horizon fails two ways at once: a short one is too myopic to see past the hazard, and a long one is a search through so many futures at once that it rarely finds the way across. On a landscape with a local basin guarding a distant goal, the flat short planner sits trapped in the basin (0 of 6 runs reach the goal); the flat long planner (six times the horizon, a 36-dimensional search) at equal budget sits trapped too (0 of 6); and neither is cheap.

The fix is the one perception already used for depth: stack timescales. A slow, far-sighted planner strides over the whole task in coarse steps (aware of the hazard, choosing where to head) and hands the next sub-goal to a fast, near-sighted planner that drives the body there, free of the second-guessing that traps the flat search. Their reach is the product of their horizons, not the sum. It reaches the goal 6 of 6, every time, out of two short horizons.

hierarchical

The cost landscape says why: a local basin sits between the start and the goal, and flat search (short or long) settles into it. The hierarchy's coarse level strides over the barrier; its fine level executes the crossing.

landscape

Deciding where and deciding how, on two timescales: the action-side image of the cortex's slow causes riding its fast detail. Foresight, like abstraction before it, grows by stacking timescales; and that, at last, is a mind that can pursue what it cannot yet see.


Curiosity: the other half of the principle · curiosity.py, explore.py

Every drive so far minimises one thing: surprise about states the agent can already model. But the free-energy story has a second half. Expected free energy is

G(plan)  =  expected cost           −   expected information gain
            (pragmatic: reach safety)    (epistemic: resolve uncertainty)

and the second term is curiosity: an agent should act not only toward the safe but toward the unknown, because that is where acting teaches it most. Give it the epistemic term and, with no threat in sight, it goes looking.

The world is a row of sites, each hiding how it would push the body; the agent holds a belief about every one (an estimate and an uncertainty) and refines it, Bayes-optimally, whenever it visits. A curious agent (epistemic weight above zero) plans toward wherever it is most uncertain and tours the unknown until it is known, driving total uncertainty 6.0 → 0.05 and covering 6/6 sites. A pragmatic one (weight zero) has no such pull and sits in what it was handed (2/6, uncertainty stays 4.0). A random walker explores, but blindly (4/6); curiosity is directed, not mere motion.

curiosity

Then the world asks: a site is activated and must be met at once. The curious agent, which spent the quiet time learning, answers well for any site (mean error 0.06, against 0.27 for knowing nothing); the pragmatic one is caught blank on all it never sought (0.15). Curiosity is what a homeostat does with the slack between threats; it spends it buying the knowledge the next threat will demand.

payoff

Avoiding the unpredictable and seeking it are the same imperative on two horizons: minimise surprise now, and minimise the surprise you will meet later by going, now, to where your model is weakest. It is also the Level-4 novelty drive turned outward; not merely noticing the new, but setting out to find it. This is why a mind, safe for the moment, does not sit still.


Active sensing: curiosity, turned on the senses · senses.py, sense.py

Perception, everywhere above, was passive: the whole sensory vector arrived, free, each instant. Real senses are neither free nor whole: an eye foveates, a hand palpates, attention is a narrow aperture that must be pointed. With only a few channels readable per glance, seeing well stops being a matter of processing what comes in and becomes a matter of choosing what to look at. And the choice has a right answer, the exact mirror of curiosity's: curiosity moved the body toward where the world was uncertain; active sensing moves the gaze toward where the evidence would most resolve the question, the channel on which the still-plausible causes most disagree.

The organism knows what the objects look like; it must find which is present by reading a narrow aperture of the 24-channel signal. Three ways to point it, all doing identical Bayesian updating; they differ only in where they look:

aperture (channels/glance) active: look where it counts random fixed
2 of 24 5.5 glances 13.8 25.2
3 of 24 4.1 9.7 11.2
6 of 24 2.8 5.1 8.2

Looking where the evidence is identifies the object in a fraction of the glances; and the tighter the aperture, the more the choosing is worth (2.5× faster than random at k=2, still 1.8× at k=6). The reason is direct: the channels the active senser reads are 1.85× as informative as an average one, while random reads land on average.

sensing informative

Perception need not be something that happens to a mind; it can be something the mind does. Given a limited aperture and a question, the informative glance is worth many blind ones: the same active-inference move that chose where to act, now choosing where to look.


Metacognition: knowing when you don't know · metacognition.py, meta.py

Every belief in this model has carried, all along, a second number beside its best guess: how sure it is. So far that number only worked from the inside (active sensing stopped glancing once it was high; habit deliberated once surprise made it low). Metacognition is a system reading that number about itself and deciding what to do with a belief it might be wrong about.

The oldest use of self-doubt is whether to act at all. The organism identifies a hidden object from a few noisy glances, then may commit to its guess (right +1, wrong −2) or decline (a certain 0). Three ways to choose:

policy (2-glance budget; ~68% accurate overall) reward / trial
reckless: commit to every guess +0.07
timid: decline everything 0
metacognitive: commit only when sure +0.32

The metacognitive agent wins, and the reason is that its confidence is honest: a Bayesian belief is calibrated, so how sure it feels really does track how often it is right. It therefore answers the questions it knows (86% correct on the trials it chooses, against 68% overall) and abstains on the ones it doesn't. And the worse the evidence, the more this is worth: on a single glance the reckless agent runs a loss (−0.33) while the metacognitive one, declining what it cannot tell, still profits (+0.09).

metacognition knows

The number was always there: the confidence beside every guess. Metacognition is a mind turning that number on itself, and because the confidence is honest, the holding-back is wise. Knowing the limits of your knowing is itself a kind of knowing.


Memory & replay: dreaming · memory.py, dream.py

Until now the organism learned each moment once and let it go: online, forward, irreversible. Brains do not: they keep a store of what happened and, in sleep and quiet rest, run it again. In this model's own terms, replay is nothing new. Planning ran the generative model forward over imagined futures; replay runs the same model back over remembered pasts. Dreaming is imagination pointed at what already happened, and its purpose is to learn from it again.

Give the organism an episodic memory and, between bouts of real experience, let it replay.

A little experience becomes a lot of learning. Real experience is expensive; replay is cheap. From the same 3,000 real frames, an online learner (one pass) reaches a world-model of reconstruction quality 0.37; a dreamer (replaying five remembered episodes per waking one) reaches 0.59; and reaches the online learner's final competence in a third of the real experience. (Prioritising replay by surprise adds little here: on a near-homogeneous world, that it dreams matters more than what it dreams about.)

dreaming

Dreaming rescues the rare. What a single pass most fails to consolidate is the rare: the objects seldom met slip past once and are gone. On an imbalanced world (one common object, three rare), the online learner never learns the rare ones (mean reconstruction 0.27); the dreamer re-lives them and does (0.54). Memory is how a mind gives its fleeting experience a second, third, and fourth chance to teach it.

rare

Replay ties the model's threads together: the world-model of perception, improved by the imagination of planning, run over the memories a mind keeps precisely so a moment can teach it more than once. A mind that dreams needs less of the world to understand it.


Affect: a feeling that decides · affect.py, feel.py

The workspace keeps a viability estimate; affect is the trend of it: a single scalar, stress, that rises when something threatens the organism and falls when it is safe. That scalar does the oldest job a feeling has: deciding, moment to moment, whether now is a time to explore or a time to take cover.

An agent lives among things worth learning, all out away from home, under an intermittent threat: while it is present, being far from home costs the agent. There is one body and one choice (it cannot both study a distant thing and shelter at once) so the trade is real and unavoidable, and no fixed policy escapes it. An agent that always explores learns nearly everything and is battered (learned 2.75/3, 840 exposed steps); one that always shelters is never touched and learns nothing (0/3, 0).

The affect-driven agent lets stress decide: high stress damps curiosity and pulls it home; as the threat passes and stress subsides, curiosity returns and it ventures out. From that one signal it gets what neither fixed policy can: learned 2.98/3 at just 103 exposed steps, ~8× less harm than the explorer for more learning, because it studies the world in the safe spells and shelters in the dangerous ones.

affect tradeoff

Feeling, here, is not decoration on top of cognition; it is the control signal cognition needs when the body is finite and the world is not safe: read off the organism's own viability, the same regulatory move as everything below it, now reaching down to retune the whole system at once. (The same stress is wired to raise plasticity and precision too, as the brain's neuromodulators do; this toy world is stable enough that those levers change little, so the demonstrated effect is the one that bites here: the reallocation of behaviour.)


Habit: caching thought, and knowing when to think again · habit.py

Every planning agent so far re-derives, from scratch, the same action it derived a moment ago. Brains don't pay that twice: a move made often enough is cached into a habit, a fast fixed response that runs without deliberation, freeing the expensive machinery for what is new. That's the model-free/model-based divide, and it needs nothing beyond what's already here: the planner is the deliberator, and the habit is its own past outputs, remembered (a phase-indexed cache of the anticipatory brace the planner adds beyond a built-in stabilising reflex).

On the inertial-body shock task (where a bare reflex dies and planning earns its keep) the cached habit meets each shock as well as the planner, for a fraction of the cost. But a habit is rigid: reverse the world's grip and the cached brace is now exactly wrong.

meeting the shock survives before survives after the reversal deliberation
always deliberate (planner) 100% 100% 100%
habit, then frozen 100% 2%: battered, no longer thinking 15%
arbitrated (surprise decides) 100% 98% 18%

The remedy is arbitration, and its signal is the one affect already provides: surprise. While the habit works, surprise stays low and the agent coasts on it, cheaply; when it fails, surprise spikes, control returns to deliberation, the habit is relearned, and control hands back. The arbitrated agent keeps the habit's economy and the planner's resilience: near-planner reliability at a fifth of the thinking, recovering from a change a frozen habit never survives.

habit arbitration

A mind that only planned would be wise and slow; one that only cached would be quick and brittle. Between them (think when it is new, coast when it is not) it is both. (The one unavoidable cost: a single hit at the change, to detect it; a habit is rigid until proven wrong.)


Motivation: several needs, and wanting the one you most lack · drives.py, motive.py

Every embodied agent so far had a single essential variable. But a body is kept alive by several at once (energy, water, warmth, safety) each falling on its own, each restored at its own source, and any one hitting zero is fatal. With one body that can be in only one place, the needs compete: to tend one is to neglect the rest. Deciding which need is most pressing, moment to moment, is motivation; and it is not a new principle, it is the old one counting past one. Because a deep deficit costs more than a shallow one, minimising total need is pursuing the neediest; as needs fall, refill, and a sudden demand strikes, the pursuit switches on its own. Drive reduction, made precise, looks from outside exactly like wanting.

Three needs, one body, and every 130 instants a demand shock drains a random need. Three ways to choose:

policy keeps all needs alive
homeostatic: tend the neediest (commit, but preempt for urgency) 16/16 seeds (full run)
routine: fixed rotation, equal turns 0/16 (dies ~279)
fixated; one need only 0/16 (dies ~139)

Only the homeostatic agent survives. The fixated agent starves the needs it ignores within moments; the routine agent is caught when a shock lands on a need its rota won't revisit in time: by which point that need is dead. The homeostatic agent, watching total need rather than a schedule, drops what it is doing and rushes to the shock, every time.

motivation survival

Nothing here was told to prefer one need over another; the preference falls out of keeping the total deviation small. Motivation is the good-regulator move counting past one: a mind that changes its mind about what it wants, exactly when it should.


Theory of mind: inference, turned on another mind · theory_of_mind.py, tom.py

The whole model has been one move made over and over: infer the hidden cause behind what you observe. The senses infer the object behind the signal; the hierarchy the slow cause behind the fast. Point the same move at another agent, and its hidden cause is not an object but a mind: what it believes, and so what it will do. Theory of mind needs no new principle, only a new thing to be uncertain about.

An actor is heading for a resource it saw earlier; but the resource has since moved, unseen, so the actor holds a false belief. An observer watches a few of the actor's steps and must predict where it will end up. The theory-of-mind observer treats the actor as rational and infers, from its movement, what it must believe (inverse planning): false belief and all. The belief-blind observer assumes the actor knows what the observer knows, and predicts the resource's true location.

trials theory of mind (infers the belief) belief-blind (assumes shared knowledge)
true-belief 89% 100%
false-belief 88% 0%

When the actor is right, both do well. When the actor is wrong, the belief-blind observer fails completely; it predicts where the resource is, the actor goes where it believes, and the two never meet. Only the observer reading the false belief off the behaviour gets it right. This is the Sally-Anne false-belief test, the classic line for theory of mind; and it falls out of nothing more than the model's oldest move, with another agent's belief as the hidden cause.

theory of mind reading a mind

To infer the cause of what you see is perception; to infer it when the cause is another agent's belief is theory of mind. And because that belief can be false, a mind that can read it can do the thing minds most need from each other: understand someone who is wrong.


A society of minds: the recursion closing · society.py, swarm.py

The whole model turns on one move: couple regulators and a regulator appears one scale up. It was shown at the very bottom (coupled homeostats self-heal into a mesh (Level 1)) and every level since has been that move again. The last step is to make it at the top, with whole minds as the units: several curious agents, each the perceiving, acting, planning, exploring animal built up over every file before this, dropped into one world and coupled.

They couple two ways. They communicate: what one learns enters a belief the others read, so a discovery made once is made for all. And they coordinate; each is pushed softly off the ground a peer already works, so no two crowd the same spot. From nothing but those local couplings, a division of labour appears: from a standing start at the centre, the agents fan out and partition the unknown between them, one region each.

Three ways to meet an unknown world: one mind, a crowd of four uncoupled, and a society of four coupled. Four minds beat one (learning the world (uncertainty below 0.5) in 17 steps against 39) but the uncoupled crowd wins only speed and wastes most of it, piling onto the same sites. The coupled society spends no effort twice: it learns fastest (9 steps) and most completely (final 0.02), because it organises.

society

The division of labour is something no one designed; it falls out of communicating and keeping apart. The four coupled agents tile all eight sites, one region each; the crowd's four each wander the whole line, re-learning what the others already knew.

labour

Its shared ignorance is an essential variable no single agent regulates: the society is a homeostat, made of homeostats, made of homeostats, all the way down. A unit defended its band; coupled units defended a joint band; coupled minds regulate a variable none of them owns. The same move at every scale: put regulators in each other's way and a larger regulator appears. Intelligence was never in the unit; it was always in the coupling.


Stretching the world: language, conflict, open-endedness · stretch.py

The six acts complete the arc. Three more push it sideways, into what a society meets once it is more than a metaphor. (python stretch.py.)

Language. The society's "communication" was a shared belief, granted for free. Make it earned: a speaker emits an arbitrary symbol, a listener must have learned its meaning, and neither is given the code. Reinforcing only their accidental agreements (with a little lateral inhibition), a dyad drives communication from chance to perfect (accuracy 0.14 → 1.00) and a clean, injective lexicon locks in. Scaled up, groups fragment into dialects (accuracy 0.93 / 0.87 / 0.76 for 2 / 3 / 4 agents): a real hazard of population-wide agreement.

language

Conflict. Knowledge is non-rival; food is not. In a commons of depletable, regenerating patches, a greedy crowd piles onto the richest and the harvest suffers; the same avoidance that divided the labour of knowing now divides the spoils of having, lifting the collective harvest +16%: a sustainable territory instead of a tragedy.

conflict

Open-endedness. Every knob so far was tuned by hand. Remove the hand: a population of foraging strategies, a heritable coordination trait, and selection alone. A greedy population is selected into the coordinated regime and its fitness locks in (≈56 → ≈64): coordination rediscovered, from the outside, by variation and selection, with no designer.

evolution

Each is the recursion pushed outward: coupling that must now negotiate meaning, scarcity, and survival. The one principle keeps paying out.


Deepening the world: is abstraction compositional? · composite.py, compose.py

The model's central claim, shown at Levels 2–3, is that a predictive hierarchy discovers the hidden cause of its world. Every test of it used holistic objects that shared nothing. Here is the hardest question that claim can be asked. Give the world compositional objects (two factors of three values, so nine objects built from six reusable parts) and train the hierarchy on only six of the nine combinations. Then ask, of the top layer, how well each factor can be read on the three combinations it was never trained on. Does it discover the factors and understand a novel combination, or did it merely memorise the ones it saw?

top-layer factor decode (chance 0.33) trained combinations held-out combinations
compositional world (shared parts) 0.92 0.82
holistic control (independent objects) 0.91 0.33: chance

The abstraction is genuinely compositional. On the held-out combinations, both factors stay almost as readable as on the trained ones (0.82): far above the raw signal (0.57) and far above chance. And the control proves it is no artifact: run the same experiment in a holistic world where objects share no parts, and the generalisation collapses to chance (0.33), same hierarchy, same denoising, but nothing to compose. The model did not memorise nine objects; it discovered six parts and recombines them into an object it never saw (it even partially rebuilds its signal, R² 0.18, where the holistic control cannot at all, −0.91).

compositional generalize

Composition was never designed in; it is simply what discovering the true hidden causes of a compositional world amounts to. The model's central claim survives the hardest test it can be posed; and with local, Hebbian learning, no backpropagation.


Synthesis: the one principle, measured · synthesis.py

The whole model makes one claim: each level is the same move as the one below, a regulator driving its essential variable from out-of-band back to viability. That has been narrated the whole way up. Here it is measured. From six different substrates (a unit relaxing into its band, a cortex learning its world, a body being regulated, an agent resolving its ignorance, a society resolving its own, and a language converging) one quantity each is pulled: the gap between where the system is and where it must be to persist. Each is in its own units, on its own clock. Normalise every gap to start at one and end at zero, put each system's own adaptive time on a common axis, and overlay them.

They trace the same descent to viability; each at its own pace (a unit in a few dozen relaxation steps, a cortex over thousands), but the same fall, agreeing to within ±0.13 of their shared shape. That shared descent is the closest this model comes to a proof of its own first principle: intelligence is not a thing it contains at some level; it is a move, and the same move, composed and made predictive, is every level of it.

synthesis


Reproducibility: not one lucky seed · verify.py

Every number above comes from a single seed, and a single seed is an anecdote. verify.py re-runs the load-bearing claims across several seeds, reports each as a distribution (mean ± std), and asserts that it holds: turning the narration into a regression-guarded test suite that exits non-zero if anything breaks.

python verify.py            # ~5 min; 18 claims across 4 seeds

Each claim is stated as something that must be true every seed: usually a paired comparison (this beats that, on the same seed), which cancels seed variance. Across 4 seeds, all eighteen reproduce: abstraction rises up the hierarchy (+0.13 ± 0.02), reconstruction (R² 0.48), homeostasis holds at 0.18, action is life (+1.00, no-action always dies), planning survives a shock the reflex dies to, hierarchical planning crosses where flat search can't, curiosity tours the unknown, active sensing identifies ~2.3× faster than random, metacognition's self-doubt out-earns commit-always, theory of mind passes the false-belief test where belief-blindness fails, abstraction generalises to unseen combinations only with shared parts, dreaming out-learns one online pass, affect learns like the explorer at ~8× less harm, arbitration recovers where a frozen habit collapses, motivation keeps every need alive where a routine starves, a coupled society beats a lone mind, and coordination out-harvests a greedy crowd. The one claim that is reliable but not certain (a dyad inventing a shared language) is asserted as such (it must hold in most seeds, not all), because that is what the model honestly shows. The narration is the model's behaviour, not a fortunate run.

reproducibility


Watching it run: the model as its own simulation · viz/

Everything above narrates what the model did, in figures. But every claim here is a claim about motion (surprise sweeping a workspace and subsiding, a slow layer holding still while a fast one boils, a planner dipping the wrong way just before a shock, four agents fanning out to tile a line) and a still is a poor witness to any of it.

python -m viz.run_scene stack      # the predictive hierarchy, both currents flowing
python -m viz.run_scene milieu     # act.py's three ablations, in one sphere
python -m viz.run_scene imagine    # the futures the planner tries on
python -m viz.run_scene society    # one mind, a crowd, and a society

The model is the simulation. The numpy code above runs live and streams each instant to a browser, which draws it. Nothing is re-implemented in JavaScript: a second implementation would be a second source of truth, and verify.py cannot see it. There are, correspondingly, no numbers in the renderer: every figure on screen arrives in the frame it belongs to, and every non-linear visual transform is declared in that frame and printed in the legend.

That rule has teeth. python verify.py now runs viz/verify_viz.py after the eighteen claims above, and it asserts each scene's trajectory is bit-identical to the driver's own functions (act.live, run.collect, plan.run, swarm.run) so a scene cannot drift from what it depicts. The scenes reproduce the headline numbers live: the full loop at ‖e‖ 0.12 and 100% in band while the inert agent leaves the sphere; identity decodable 0.95 at the third layer against a chance of 0.25; timescales climbing τ 1 → 9 → 21 → 27; ignition at 2.64× rest; the reflex thrown to 0.93 where foresight peaks at 0.34; and the coupled society learning its world in 9 steps against a crowd's 17 and a lone mind's 39.

python -m viz.build all bakes any scene into a single self-contained page: no server, no network request, nothing installed. See viz/README.md for the design and BLUEPRINT_3D.md for the plan it implements, which is also an honest record of the eight places that plan corrected itself on contact with the thing it described.


The mathematics, in one box

The hierarchy is a hierarchical Gaussian model. With states r_l, a readout g(r) = tanh(γ·r), generative weights W_l, and precisions π_l, the free energy is

F  =  Σ_l  (π_l / 2) · || r_l − W_{l+1} g(r_{l+1}) ||²      (+ a weak prior at the top)

and the three timescales of the model are three gradient flows on that one quantity:

inference    ṙ_l  ∝ −∂F/∂r_l          infer the causes of this instant  (warm-started)
learning     Ẇ_l  ∝ −∂F/∂W_l          a local Hebbian rule, error × activity
homeostasis  γ̇_l  ∝ (ρ − ⟨|g(r_l)|⟩)  each unit holds its own activity at set point ρ
action       ȧ    ∝ −∂F/∂a            change the world, not the belief, to cancel the error
planning     a*   = argmin_a  𝔼[G | a]  over an imagined roll-out of the model forward
curiosity    𝔼[G] = (expected cost)  −  (expected information gain)   ← the epistemic term

The first three descend F by changing the organism; action descends the same F by changing the world; planning descends expected G by running the model forward and choosing the future it prefers; and that objective has two parts: reach preferred states (pragmatic) and reduce uncertainty (epistemic, i.e. curiosity). The workspace closes yet another loop, setting the π_l from where surprise is highest (attention) and reading −F as viability (the self-model). Minimising surprise about your own states (now, and in the futures you could cause) is minimising the chance the world does something you can't survive. Perception, action, planning, and curiosity are its four voices: explaining the present, correcting it, choosing among futures, and seeking out what it does not yet understand.


What this is, and what it isn't

  • It is a demonstration that regulation, coordination, self-repair, abstraction, temporal hierarchy, goal-directed top-down control, attention, a functional self-model, goal-directed action, planning (imagining futures and choosing a survivable one) curiosity (going, unforced, to learn what it does not yet know) and, when whole agents are coupled, a society that divides its labour, can all fall out of one recursively-composed rule, with no piece of the intelligence hand-coded. The numbers above are reproducible from run.py, act.py, plan.py, hplan.py, explore.py, and swarm.py.
  • It isn't a brain. It is a few dozen units on a toy world. The "self-model" is a control-theoretic self-model (a representation the system uses to regulate itself) and nothing here licenses a claim about subjective experience. The gap to biology is depth, embodiment, richness of world, and scale. The wager of the model is only that it is a gap of degree.
  • It is honest about its edges. Assimilation of the genuinely novel works only above the noise floor; below it the system detects but cannot yet model. The model shows you exactly where it breaks, and breaks gently.

Standing on shoulders

Ashby (ultrastability, requisite variety, the good-regulator theorem) · Friston (the free-energy principle, active inference, predictive coding) · Rao & Ballard (hierarchical predictive coding) · Simon (near-decomposability) · Minsky (a society of agents) · Hawkins (a cortex of predictive columns) · Baars & Dehaene (a global workspace, ignition) · Maturana & Varela (autopoiesis). The synthesis (one homeostatic motif, made predictive and composed from cell to self) is the thread this code pulls through all of them.

Files

mind/
  world.py       the world: a slow hidden cause behind fast noise, and a novelty event
  composite.py   a compositional world: objects built from reusable parts (held-out combinations)
  unit.py        Level 0-1: the viable unit and the self-healing homeostat mesh
  hierarchy.py   Level 2-3: the predictive hierarchy, local learning + per-neuron homeostasis
  workspace.py   Level 4: attention-as-precision, ignition, the viability self-model
  organism.py    the perceiving animal — the afferent levels composed into one loop
  body.py        the essential variable the world pushes on and action must defend
  agent.py       the efferent half — perception and action closing into active inference
  planner.py     imagination — the model rolled forward to choose a survivable future
  hplanner.py    a hierarchy of horizons — a slow planner sets sub-goals for a fast one
  curiosity.py   the epistemic drive — a belief with uncertainty, and a planner that seeks it
  senses.py      active sensing — a belief refined by choosing which few channels to read
  metacognition.py  a self-monitor — commit to a belief or decline, from its own confidence
  memory.py      an episodic store — remembered experience to replay (dreaming)
  affect.py      a neuromodulator — stress read off viability, retuning plasticity/precision/exploration
  drives.py      a multi-drive body — several essential variables, each decaying and replenished
  theory_of_mind.py  a mind-reader — inferring another agent's belief from its behaviour
  society.py     couple whole agents — a shared belief, and soft avoidance, into a division of labour
  language.py    a Lewis signalling game — a shared code invented from reinforced agreement
  conflict.py    a rival commons — depletable patches, greedy crowding vs coordinated territory
  evolution.py   selection over a heritable trait — the good strategy discovered, not designed
  demo.py        `python -m mind.demo` — run all six acts in sequence
  metrics.py     outside-the-system measurements (never fed back in)
run.py           grows one organism and narrates the perceptual ascent (Levels 0-4), with figures
compose.py       compositional perception — does abstraction generalise to unseen combinations?
act.py           closes the loop into agency — action, its ablations, and prism adaptation
plan.py          adds foresight — reflex vs planning, and how deep the agent must imagine
hplan.py         hierarchical planning — reaching a goal flat foresight can't, over a hazard
explore.py       curiosity — acting to reduce uncertainty, and the pay-off when the world asks
sense.py         active sensing — pointing a narrow aperture where the evidence is
meta.py          metacognition — the value of knowing when you don't know (opt-out)
dream.py         memory & replay — sample efficiency, and dreaming's rescue of the rare
feel.py          affect — stress deciding explore-vs-defend, and the tradeoff it wins
habit.py         habit — caching the planner into a cheap reflex, and arbitrating by surprise
motive.py        motivation — several competing needs kept alive by tending the neediest
tom.py           theory of mind — the false-belief test: predicting a mistaken agent
swarm.py         a society of minds — solo vs crowd vs coupled, and the division of labour that emerges
stretch.py       language, conflict, and open-endedness — the society's outward stretch
synthesis.py     the capstone — the same descent to viability, measured at six scales and overlaid
verify.py        the regression guard — every headline claim re-run across seeds, asserted to hold
                 (and it runs viz/verify_viz.py too, so the live scenes cannot drift either)
viz/             the model, watched while it runs — see viz/README.md
  tap.py         a single-slot mailbox for the newest frame, and a control queue
  server.py      stdlib transport: server-sent events down, POST up. No new dependency
  run_scene.py   the launcher — per-scene warm-up and tick rate
  build.py       bake a scene into one self-contained page (no server, no network)
  verify_viz.py  the guard: each scene bit-identical to its driver, and no asserted numbers
  scenes/        one module per scene, importing its driver's constants rather than retyping them
  static/        one renderer per scene
BLUEPRINT_3D.md  the design viz/ implements, and where it corrected itself on contact
figures/         run.py (1-6), act.py (7-9), plan.py (10-11), hplan.py (12-13), explore.py (14-15), sense.py (31-32), meta.py (33-34), dream.py (22-23), feel.py (25-26), habit.py (27-28), motive.py (29-30), tom.py (35-36), swarm.py (16-17), stretch.py (18-20), compose.py (37-38), synthesis.py (21), verify.py (24)

See TOUR.md for a guided walk-through and intelligence_modeling_log.md for the development log.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages