Five sample policies
Examples
A few examples trained on synthetic data, with graphs drawn from the real compiler. Sample output from real runtime and Seabiscuit Cloud platform.
01 · shelf.sb
Shelf sag
A phone scan of a shelf also catches the wall behind it and the brackets under it, at whatever heading the phone started. The wall is the biggest flat thing in the room, so it goes first. The user says roughly how high the shelf is, and that height becomes a prior: each point is weighted by how plausible its height is, and the weighted plane fit finds the board’s top.
A slice across the board, square to the wall, and a LOWESS curve along it give the sag, measured from the straight line between its ends, so a shelf that is merely tilted doesn’t count as sagging.
The pass rule is ordinary code with units: sag under span/360, and level within half a degree.
policy(scan: Cloud, shelf_height: Length, height_sd: Length = 5 cm) -> (sag: Length, tilt: Angle, ok: Bool) wall = scan |> largest_plane(threshold: 1 cm) |> fit_plane # the biggest flat thingboard = scan |> discard(near(wall, within: 2 cm)) # the wall, and the brackets on it |> weight(by: .z, prior: gaussian(shelf_height, sd: height_sd)) |> largest_plane(threshold: 5 mm) # the board's toptop = fit_plane(board)cut = slice(board, plane(origin: top.origin, normal: wall.normal), thickness: 2 cm)line = lowess(cut, span: 0.3) # along the board, end to enda, b = line.domainlow = argmin(line)chord = line(a) + (line(b) - line(a)) * (low - a) / (b - a)sag = chord - line(low)tilt = abs(atan2(line(b) - line(a), b - a)) # either end may be the high oneok = sag < (b - a) / 360 and tilt < 0.5° # span/360, and levelA synthetic phone scan of an 80 cm wall shelf that sags 3 mm in the middle and is 0.2° off level: the 18 mm board, two steel brackets, the wall behind it and some stray points from the room, at a random heading. The user guessed the shelf's height to within 2.4 cm.
loaded shelf
- scan
- 51,003 points
- shelf_height
- -27.4 cm (true: -25.0 cm)
- sag
- 2.7 mm
- tilt
- 0.20°
- ok
- false
02 · plant.sb
Greenhouse plant height
A LOWESS curve through the top of a vertical slice finds the crown, and a second one finds the pot rim. Their difference is the geometry you can write down.
What you can’t write down is how much of the plant the scanner misses: thin tips and a smoothed peak. That is one tensor, lift, trained against measured heights, with a learned noise level next to it.
policy(scan: Cloud) -> height: Gaussian[Length]optimiser cma_es(sigma0: 0.3)loss { height: nll }metrics { err: abs_error(height, y.height) } lift = tensor(1 cm, lower: 0 cm, upper: 10 cm) # tips the scanner missessd = tensor(5 mm, lower: 1 mm) plant = scan |> remove_outliers(sigma: 3) |> center(axis: "x") |> center(axis: "y")sec = slice(plant, plane(origin: (0 m, 0 m, 0 m), normal: forward), thickness: 4 cm)crown = lowess(keep(sec, top(.v, 0.25)), span: 0.3)pot = lowess(keep(sec, bottom(.v, 0.05)))peak = argmax(crown)height = crown(peak) - pot(peak) + lift + noise(sd)24 synthetic plant scans (30–60 cm tall) with hand-measured heights. The scanner misses the thinnest 1.5 cm of tips, so the crown curve reads short.
| entry | scan | height (measured) | height (held-out prediction) |
|---|---|---|---|
| plant-00 | 13,397 points | 48.8 cm | 49.1 cm ± 4.5 mm |
| plant-01 | 13,440 points | 55.8 cm | 55.3 cm ± 4.3 mm |
| plant-02 | 13,434 points | 53.2 cm | 52.9 cm ± 4.1 mm |
| plant-03 | 13,418 points | 50.9 cm | 50.9 cm ± 4.5 mm |
| plant-04 | 13,247 points | 36.5 cm | 36.4 cm ± 3.0 mm |
| plant-05 | 13,426 points | 51.4 cm | 51.2 cm ± 4.5 mm |
show all 24 entries ↓hide ↑
| entry | scan | height (measured) | height (held-out prediction) |
|---|---|---|---|
| plant-06 | 13,188 points | 33.4 cm | 34.0 cm ± 4.1 mm |
| plant-07 | 13,390 points | 47.1 cm | 47.1 cm ± 4.1 mm |
| plant-08 | 13,449 points | 57.3 cm | 56.3 cm ± 3.0 mm |
| plant-09 | 13,201 points | 32.8 cm | 33.0 cm ± 3.0 mm |
| plant-10 | 13,246 points | 37.8 cm | 38.0 cm ± 4.5 mm |
| plant-11 | 13,366 points | 43.7 cm | 43.7 cm ± 4.3 mm |
| plant-12 | 13,310 points | 39.7 cm | 40.1 cm ± 4.5 mm |
| plant-13 | 13,405 points | 44.6 cm | 44.5 cm ± 4.3 mm |
| plant-14 | 13,372 points | 46.0 cm | 46.2 cm ± 4.1 mm |
| plant-15 | 13,302 points | 39.3 cm | 39.6 cm ± 4.3 mm |
| plant-16 | 13,443 points | 59.2 cm | 58.1 cm ± 3.0 mm |
| plant-17 | 13,401 points | 54.8 cm | 54.4 cm ± 4.1 mm |
| plant-18 | 13,342 points | 41.2 cm | 41.6 cm ± 3.0 mm |
| plant-19 | 13,355 points | 42.2 cm | 42.6 cm ± 4.3 mm |
| plant-20 | 13,403 points | 47.5 cm | 47.7 cm ± 4.5 mm |
| plant-21 | 13,359 points | 43.0 cm | 43.5 cm ± 4.1 mm |
| plant-22 | 13,372 points | 49.5 cm | 49.3 cm ± 4.3 mm |
| plant-23 | 13,387 points | 47.1 cm | 47.0 cm ± 3.0 mm |
Trained · 4-fold cross-validation, cma_es · 24 entries
- lift
- 20.5 mm
- sd
- 4.0 mm
- err (held out)
- 3.3 mm ± 1.2 mm
a new plant, 47.0 cm tall
- scan
- a synthetic scan
- height
- 47.0 cm ± 4.0 mm
03 · fuse.sb
Sensor fusion
The wall unit is a prior; the probe is a likelihood. bayes_update is a single node that returns the posterior and the evidence, and the posterior’s sd is exact for Gaussians.
The evidence is the density of the probe reading under the prior, so its negative log is a ready-made disagreement score.
# Temperatures in °C are plain Scalars: ° on its own means an angle.policy(wall: Scalar, probe: Scalar, wall_sd: Scalar = 0.8, probe_sd: Scalar = 0.3) -> (temp: Gaussian[Scalar], surprise: Scalar) prior = gaussian(wall, sd: wall_sd)temp, evidence = bayes_update(prior, likelihood(probe, noise: probe_sd))surprise = -log(evidence) # large when the two disagreeTwo readings in °C, with the default noise levels (0.8 and 0.3).
readings agree
- wall
- 21.9
- probe
- 21.2
- temp
- 21.3 ± 0.281
- surprise
- 1.1
the wall unit sits in the sun
- wall
- 26.0
- probe
- 21.2
- temp
- 21.8 ± 0.281
- surprise
- 16.5
04 · parcel.sb
Package dimensioning
Two vertical slices through the centred cloud, with u pointing up. In each, a LOWESS curve over height tracks a wall’s mean position, so the scanner’s noise averages out instead of widening the box. wall is a fn, so each of its four calls is its own group in the graph.
Every number has a unit, so the planes, thicknesses and noise all type-check. The outputs are Gaussians: sigma rides along through the arithmetic, and the ± is exact Gaussian algebra, not a rule of thumb.
# The capture app crops the scan to the parcel; this measures it.policy(scan: Cloud, sigma: Length = 1.5 mm) -> (length: Gaussian[Length], width: Gaussian[Length], height: Gaussian[Length]) box = scan |> remove_outliers(sigma: 2.5) |> centero = (0 m, 0 m, 0 m)z = (0 m, 0 m, 1 m)xs = slice(box, plane_through_line(o, z, normal: right), thickness: 1 cm) # u: up, v: xys = slice(box, plane_through_line(o, z, normal: forward), thickness: 1 cm) # u: up, v: y # a wall's mean position, as a curve over height, read 5 cm below the centrefn wall(sec: Section, lo: Length, hi: Length) -> Length { lowess(keep(sec, .u < 0 m and lo < .v < hi))(-5 cm)} z0, z1 = lowess(xs).domainlength = wall(ys, 0 m, 1 m) - wall(ys, -1 m, 0 m) + noise(sigma)width = wall(xs, 0 m, 1 m) - wall(xs, -1 m, 0 m) + noise(sigma)height = z1 - z0 + noise(sigma) + noise(sigma) # two extreme points, two errorsOne synthetic phone scan of a 42 × 31 × 22 cm parcel: four sides and the lid, 1.5 mm of sensor noise, in the phone's own frame.
parcel scan
- scan
- 18,000 points
- sigma
- 1.5 mm (the default)
- length
- 42.0 cm ± 1.5 mm
- width
- 30.9 cm ± 1.5 mm
- height
- 22.0 cm ± 2.1 mm
05 · pallet.sb
Pallet stacking risk
linear has a built-in fitter, so under optimiser delegate it solves its own coefficients in closed form. Features are made dimensionless explicitly (height / 1 m), so the coefficients come out in centimetres.
The metrics block is evaluated only on held-out folds. The output is a distribution, so the risk of sliding past 3 cm is a cdf away.
policy(height: Length, lean: Angle, load: Scalar) -> (shift: Gaussian[Length], risk: Scalar)optimiser delegateloss { shift: nll }metrics { err: abs_error(shift, y.shift) cover: coverage(shift, y.shift) # inside the 90% interval?} w = tensor([0 cm, 0 cm, 0 cm])shift = linear((height / 1 m, lean / 1°, load / 100), coef: w, intercept: tensor(0 cm), noise: tensor(1 cm, lower: 0 cm))risk = 1 - cdf(shift, 3 cm) # P(the top layer slides > 3 cm)60 synthetic pallets with a measured slide after a vibration test, 2–4 mm of it unexplained noise.
| entry | height | lean | load | shift (measured) | shift (held-out prediction) |
|---|---|---|---|---|---|
| pallet-00 | 94.1 cm | 1.50° | 601 | 31.3 mm | 32.7 mm ± 3.3 mm |
| pallet-01 | 96.3 cm | 2.78° | 203 | 35.1 mm | 37.1 mm ± 3.4 mm |
| pallet-02 | 184.3 cm | 1.87° | 427 | 43.3 mm | 44.2 mm ± 3.4 mm |
| pallet-03 | 152.9 cm | 0.83° | 253 | 33.0 mm | 31.5 mm ± 3.2 mm |
| pallet-04 | 153.7 cm | 1.54° | 763 | 45.9 mm | 42.6 mm ± 3.5 mm |
| pallet-05 | 187.9 cm | 0.61° | 565 | 36.0 mm | 39.8 mm ± 3.0 mm |
show all 60 entries ↓hide ↑
| entry | height | lean | load | shift (measured) | shift (held-out prediction) |
|---|---|---|---|---|---|
| pallet-06 | 118.9 cm | 1.77° | 326 | 29.0 mm | 35.0 mm ± 3.4 mm |
| pallet-07 | 175.4 cm | 0.39° | 500 | 33.9 mm | 35.0 mm ± 3.2 mm |
| pallet-08 | 89.1 cm | 2.69° | 472 | 36.7 mm | 37.8 mm ± 3.5 mm |
| pallet-09 | 154.1 cm | 0.61° | 826 | 35.3 mm | 38.7 mm ± 3.0 mm |
| pallet-10 | 83.6 cm | 0.60° | 409 | 18.7 mm | 24.4 mm ± 3.3 mm |
| pallet-11 | 179.7 cm | 2.09° | 404 | 44.7 mm | 45.1 mm ± 3.5 mm |
| pallet-12 | 97.6 cm | 2.99° | 495 | 44.4 mm | 41.0 mm ± 3.0 mm |
| pallet-13 | 86.0 cm | 0.10° | 784 | 21.4 mm | 26.7 mm ± 3.0 mm |
| pallet-14 | 114.0 cm | 0.95° | 217 | 28.0 mm | 28.2 mm ± 3.3 mm |
| pallet-15 | 82.7 cm | 2.52° | 500 | 36.5 mm | 36.5 mm ± 3.0 mm |
| pallet-16 | 161.3 cm | 0.59° | 196 | 32.2 mm | 32.0 mm ± 3.4 mm |
| pallet-17 | 178.5 cm | 0.08° | 754 | 41.6 mm | 37.9 mm ± 3.0 mm |
| pallet-18 | 90.2 cm | 0.05° | 370 | 25.7 mm | 19.0 mm ± 3.2 mm |
| pallet-19 | 134.2 cm | 2.56° | 313 | 42.0 mm | 40.8 mm ± 3.3 mm |
| pallet-20 | 108.4 cm | 2.93° | 856 | 42.4 mm | 46.5 mm ± 3.0 mm |
| pallet-21 | 128.0 cm | 0.94° | 710 | 34.5 mm | 35.3 mm ± 3.5 mm |
| pallet-22 | 87.4 cm | 1.21° | 334 | 34.9 mm | 25.7 mm ± 3.2 mm |
| pallet-23 | 161.6 cm | 1.64° | 646 | 49.2 mm | 42.1 mm ± 3.4 mm |
| pallet-24 | 165.9 cm | 2.78° | 262 | 44.5 mm | 45.6 mm ± 3.3 mm |
| pallet-25 | 95.8 cm | 1.33° | 740 | 35.8 mm | 33.3 mm ± 3.4 mm |
| pallet-26 | 163.5 cm | 0.11° | 420 | 28.6 mm | 31.9 mm ± 3.5 mm |
| pallet-27 | 189.9 cm | 0.43° | 333 | 39.7 mm | 35.2 mm ± 3.2 mm |
| pallet-28 | 86.7 cm | 2.61° | 627 | 37.6 mm | 38.7 mm ± 3.4 mm |
| pallet-29 | 134.8 cm | 0.24° | 608 | 27.4 mm | 31.0 mm ± 3.5 mm |
| pallet-30 | 84.3 cm | 0.35° | 566 | 23.6 mm | 22.5 mm ± 3.2 mm |
| pallet-31 | 115.7 cm | 1.93° | 414 | 35.8 mm | 36.0 mm ± 3.3 mm |
| pallet-32 | 114.7 cm | 1.19° | 834 | 28.8 mm | 37.1 mm ± 3.0 mm |
| pallet-33 | 89.5 cm | 1.68° | 873 | 40.3 mm | 35.9 mm ± 3.3 mm |
| pallet-34 | 157.0 cm | 0.20° | 755 | 39.4 mm | 35.9 mm ± 3.0 mm |
| pallet-35 | 95.8 cm | 1.39° | 187 | 24.7 mm | 26.3 mm ± 3.2 mm |
| pallet-36 | 159.0 cm | 2.41° | 720 | 49.4 mm | 47.3 mm ± 3.3 mm |
| pallet-37 | 166.9 cm | 0.75° | 253 | 33.2 mm | 34.1 mm ± 3.4 mm |
| pallet-38 | 134.8 cm | 0.86° | 604 | 31.5 mm | 34.9 mm ± 3.0 mm |
| pallet-39 | 106.4 cm | 1.87° | 418 | 42.8 mm | 34.4 mm ± 3.3 mm |
| pallet-40 | 111.9 cm | 2.40° | 461 | 41.0 mm | 38.6 mm ± 3.3 mm |
| pallet-41 | 154.1 cm | 1.56° | 343 | 31.0 mm | 38.2 mm ± 3.0 mm |
| pallet-42 | 90.6 cm | 0.97° | 562 | 29.6 mm | 29.1 mm ± 3.4 mm |
| pallet-43 | 97.0 cm | 2.40° | 738 | 42.3 mm | 40.0 mm ± 3.2 mm |
| pallet-44 | 179.2 cm | 2.27° | 374 | 44.1 mm | 45.5 mm ± 3.3 mm |
| pallet-45 | 117.4 cm | 2.25° | 439 | 39.7 mm | 38.6 mm ± 3.4 mm |
| pallet-46 | 176.4 cm | 2.07° | 709 | 51.8 mm | 46.9 mm ± 3.4 mm |
| pallet-47 | 166.1 cm | 1.34° | 574 | 38.4 mm | 41.0 mm ± 3.5 mm |
| pallet-48 | 141.1 cm | 2.44° | 679 | 42.4 mm | 45.8 mm ± 3.2 mm |
| pallet-49 | 134.6 cm | 2.64° | 231 | 39.5 mm | 40.7 mm ± 3.5 mm |
| pallet-50 | 120.8 cm | 0.27° | 614 | 31.3 mm | 27.9 mm ± 3.2 mm |
| pallet-51 | 127.1 cm | 2.56° | 253 | 42.4 mm | 39.5 mm ± 3.5 mm |
| pallet-52 | 125.5 cm | 1.58° | 525 | 36.8 mm | 36.9 mm ± 3.0 mm |
| pallet-53 | 136.3 cm | 2.59° | 278 | 39.5 mm | 41.1 mm ± 3.5 mm |
| pallet-54 | 87.4 cm | 1.38° | 881 | 34.0 mm | 33.7 mm ± 3.2 mm |
| pallet-55 | 189.0 cm | 1.61° | 240 | 43.8 mm | 41.7 mm ± 3.5 mm |
| pallet-56 | 102.8 cm | 2.14° | 556 | 37.0 mm | 37.2 mm ± 3.4 mm |
| pallet-57 | 108.1 cm | 2.60° | 725 | 39.3 mm | 42.5 mm ± 3.5 mm |
| pallet-58 | 124.6 cm | 2.21° | 878 | 41.6 mm | 43.4 mm ± 3.3 mm |
| pallet-59 | 97.5 cm | 1.09° | 531 | 34.6 mm | 28.8 mm ± 3.2 mm |
Trained · 5-fold cross-validation, delegate (closed form) · 60 entries
- w
- (12.7 mm, 5.8 mm, 1.1 mm)
- intercept
- 5.6 mm
- noise
- 3.3 mm
- err (held out)
- 2.8 mm ± 0.7 mm
- cover (held out)
- 0.83 ± 0.10
a 1.2 m stack, leaning 1°, 400 kg
- height
- 1.2 m
- lean
- 1°
- load
- 400
- shift
- 31.1 mm ± 3.3 mm
- risk
- 0.63
In the field
Where it started.
Seabiscuit runs in production at Equimorphic, which fits saddles from phone scans of horses. A few pictures from that work, featuring Gerald.




