LookupTable#
- class torchsim.LookupTable(acquisition=None, *, combine=None, monotonic=True)[source]#
Bases:
EstimatorRead one unknown back from a monotonic signal curve.
Where a model has a single unknown, a dictionary match degenerates: the atoms lie on a curve rather than filling a space, and the nearest one is found by looking along it. Interpolating between the two nearest atoms then costs nothing and removes the grid spacing from the answer entirely, which is what a matched estimate is otherwise limited by.
This is how an MP2RAGE T1 map is made [1]. The two inversion-recovery blocks are combined into one ratio per voxel, that ratio is a monotonic function of T1 over the range a brain spans, and the map is the inverse of that function.
- Parameters:
acquisition (Simulator, optional) – The sequence being inverted: a simulator that ships with TorchSim, one written by subclassing
Simulator, or any otherSimulator. Every tissue property that is neither unknown nor measured separately is fixed on it beforehand, with the constructor orbind(). Leave it out to fit from signals handed tofit()directly.combine (callable, optional) – Reduce a model’s contrasts to the one number the curve is in, called as
combine(signals)on(..., contrasts)and returning(...). Which combination makes a curve monotonic is a property of the sequence, not of the table, so it is stated here rather than assumed – for MP2RAGE it is the unified image. A model with a single contrast needs none.monotonic (bool, optional) – Restrict the table to the longest monotonic run of the curve. A signal curve that turns back on itself has no inverse where it turns, and the turning points lie outside the range of interest.
Notes
A lookup is a binary search and one linear blend per voxel, so this estimator runs where its signals already are. Streaming a volume to a card for it would spend more time on the transfer than on the search.
References
Examples
import torch from torchsim.estimators import LookupTable from torchsim.simulators import MP2RAGESimulator protocol = dict( TI=(800.0, 2700.0), flip=(4.0, 5.0), TRspgr=6.7, TRmp2rage=6000.0, nshots=128, ) T1 = torch.arange(50.0, 5000.0, 50.0) blocks = MP2RAGESimulator(**protocol).simulate( T1=T1, inv_efficiency=0.96 ) unified = (blocks[:, 0] * blocks[:, 1]) / blocks.square().sum(-1) table = LookupTable().fit(signals=unified[:, None], parameters=T1[:, None]) print(table.points, "points spanning", [round(v, 3) for v in table.span]) print(table(torch.tensor([[0.1], [-0.2]])).flatten().tolist())
75 points spanning [-0.5, 0.49] [1086.536376953125, 1721.1234130859375]
Methods
fitFit the estimator over a sampling of the tissue it will meet.
from_coefficientsMap coefficients that are already in this estimator's basis.
mapEstimate the tissue a measurement came from.
training_setSimulate a training set: signals, unknowns, and knowns.
uncertainty_ofThe standard deviation the measurement noise leaves on each map.
- property fitted#
Whether the table holds a curve.
- property points#
How many points the table keeps.
- property span#
The signal range the table covers, low to high.
A measurement outside it is read as the nearer endpoint, so a wide span is what stops a noisy background from pinning the map to a value the model never produced.