Engineering · 11
Two montages are two views of one carrier
A support could say how many elements it had, never what one was. That distinction turned out to be the difference between 5.6% and 51.7% of the whitened lead field — so the algebra that relates supports refuses to treat it as a reshape.
The question this came from
Take readings from electrode montage A and readings from montage B. Can they inform one higher-dimensional underlying representation, together with a high-resolution connectome?
The honest answer had been not without hand-writing something.
Support — the object describing what a datum physically integrates
over — carried kind, frame, units, psf, extent, n_elements,
resolution and no operators. Two supports could not be
related without a bespoke map. That is why the restriction/prolongation pair in
Engineering · 04 had to be declared as a
one-off rather than derived.
What the algebra refuses, and why that is the design
The first instinct is an algebra that always returns a map. That is worse than having none. A fabricated correspondence between two parcellations is indistinguishable at the type level from a real one — it has the same shape, passes the same checks, and silently becomes part of the result.
So maps are derived only from what the supports actually declare, and everything else raises an error naming the missing declaration:
| situation | outcome |
|---|---|
| different frames | refuse — supply a registration |
| different units | refuse — convert first |
| vector components in different frames | refuse — rotate first |
| two named clocks, no declared relation | refuse — supply a synchronisation record |
| scalar ↔ vector, no orientation field | refuse — see below |
| same frame, finer → coarser | restriction, marked lossy |
| same frame, coarser → finer | prolongation, marked invents |
The refusal that was measured, not assumed
A support says how many elements it has. It never said what one element is. We had no way to express the difference between one number per parcel and three.
That difference is not bookkeeping. Measured on real data: a per-parcel scalar carries 5.6% of the whitened lead field, where three numbers per parcel carry 51.7%.
So collapsing a 3-vector per parcel to a scalar is not a reshape. It is a projection onto an orientation — and which orientation is a physical fact about the cortex, not a layout choice. The algebra refuses to do it unless you hand it an orientation field, and then reports the discarded normal component as the uncertainty it is.
A support whose elements are scalars is a different kind of object from one whose elements are vectors. Anything that cannot tell them apart will eventually average one into the other.
Lossy and invents are different fields
Restriction discards information and is honest about it. Prolongation asserts structure no measurement supports. A pipeline can reasonably tolerate the first; it must declare the second.
They are separate flags, and the constructor enforces the pairing — a
prolongation declaring invents=False cannot be built, because it
would be claiming that upsampling is free:
SupportMap(kind="prolongation", n_in=1, n_out=4, invents=False, ...)
# ValueError: prolongation asserts structure no measurement supports;
# invents=False would claim upsampling is free
Point-spread composes, or it refuses
Mapping through a support smears the datum, so the kernels compose. Two
Gaussians compose in closed form — FWHM adds in quadrature. Two opaque
kernel_refs do not compose from their descriptions; that
needs the assets. Refusing beats approximating, because an approximated
point-spread is exactly the "nominal coordinate substituted for a physical
support" the thesis rejects.
Nominality is contagious: a composed kernel is no more real than its least real factor.
Clocks
5000 Hz EEG against 0.5 Hz BOLD refines onto the faster clock. The fast signal is already there; the slow one is held across the gap — which is invention, and the map says so rather than presenting interpolated values as measurements.
Why the algebra alone does not answer the question
An algebra for relating supports is necessary and not sufficient, and counting the current model says why:
| what | how many |
|---|---|
| source cards declared on disk | 9 |
| of those, involving EEG | 9 |
| EEG views the model can hold | 1 |
The lead field is a buffer registered inside the EEG head —
one L, one L_vec, on a single module. So:
Montage A and montage B cannot coexist, because there is exactly one
L. Adding the second means adding a second head or overwriting the first — and neither of those is "two views of one carrier."
The number of views is fixed by the model's module list rather than by the sources. That is backwards: sources are data and arrive over time, modules are code and should not have to change when they do.
The fix is not to delete the heads — EEGHead holds real physics.
It is that ownership is misplaced. An L describes a
montage; a montage belongs to a source; a source is a card. Move the operator to
the card, leave the head as the thing that applies a view, and the two
montages stop being two modules and become two rows.
That is also the point at which this algebra stops being decorative. Once each source carries its own operator and support, relating two of them is exactly the computation above — and the refusals are what stop two montages being quietly averaged into one another.
What is actually blocking the other sources
"Nine sources, one view" is the abstract statement. The concrete one is a list of three missing operators, each blocking a specific dataset that is already sitting on disk:
| source | what it is | blocked by | needs |
|---|---|---|---|
eegmmidb | 64-channel EEG | enabled | — |
ds002336 | EEG and fMRI, CC0 | BOLD is in scanner space; model state is parcels | a registration |
ds000113 | 7 T fMRI | a 116 mm slab — parcels outside it are unmeasured in every subject | a coverage mask |
sleepedf | 2 EEG derivations | 2 channels cannot constrain a 64-channel head | a montage adapter |
Three of the four measured sources are switched off, and not one of them is switched off by policy. Each is waiting on an operator nobody has written.
These blockers are not interchangeable with permission. A likelihood term over parcels outside the acquisition slab is an imputation. A parcel-space likelihood computed from scanner-space voxels with no registration is not a weaker claim — it is a different quantity. Enabling those sources without the transforms would not be a relaxed standard; it would be a wrong number.
The third row is the one this page is about. Two derivations against
sixty-four is literally montage A and montage B — so
sleepedf is the cheapest of the three to unlock, and the natural
first consumer of the algebra. It is what turns this module from something with
no importers into the thing that admits a second measured dataset.
What this is not, yet
Two limits, stated because an entry marked done is how a half-delivered change stops being visible:
- Nothing imports it. It was written during a live training run and deliberately kept free of consumers, so that a relaunch could not pick up changed code mid-flight. Wiring the observation heads onto it is later work.
- It derives maps; it does not compute them. You get a typed map with element counts, composed point-spread, and uncertainty — not the matrix. For two arbitrary parcellations it refuses rather than inventing a correspondence, so real geometric overlap is still to come.
The refusal is the honest placeholder. The one-off is now visible as a refusal instead of hidden as a hand-written map.
How it was checked
21 tests, most of them watching a refusal fire — and mutation-tested three ways, because a file that is mostly error paths and passes on the first run is the exact thing our register distrusts. Allowing a rank change through, replacing quadrature with a naive sum, and letting opaque kernels be silently approximated each failed the intended test and only that one.