Skip to content

libmath: add jets for Chebyshev variants of libmath#63

Open
sigilante wants to merge 28 commits into
mainfrom
sigilante/transcendental-jets
Open

libmath: add jets for Chebyshev variants of libmath#63
sigilante wants to merge 28 commits into
mainfrom
sigilante/transcendental-jets

Conversation

@sigilante

Copy link
Copy Markdown
Collaborator

First slice of the transcendental jetting effort: wire the first jetted
math.hoon arm (@rd exp) and establish the structure + cross-repo mirror the
rest will follow.

The Hoon transcendentals themselves already merged; this PR adds only the
jet-anchoring structure and the vere-side mirror. (math.hoon's large diff
is almost entirely the ++ math re-indent — review with whitespace hidden; the
substantive change is ~18 lines.)

What changed

  • libmath/desk/lib/math.hoon — wrap the width doors in a %math engine
    door under the shared %non chapter, mirroring /lib/lagoon's
    %non/%lagoon jet structure. =< math keeps the /+ math + rd:math /
    ~(exp rd:math [%n rtol]) API unchanged. ~/ hints on the rd door and exp
    arm.
  • libmath/vere/ (new) — hand-maintained mirror of the runtime jet code
    (jets/i/math.c, the tree.c registration snippet, README). The jets live in
    urbit/vere pkg/noun; a matching PR there will follow.
  • libmath/tools/rd_exp_check.c (new) — SoftFloat-f64 reference that proves
    the jet is bit-exact to the Hoon (not merely faithful).

The gotcha (documented in the README)

A ~/-hinted engine core must be a door (^| =+ [rnd] ~/ %math |%), not a
bare |%: a sample-less ~/-core anchors its parent to the dashboard root,
so %math and everything under it miss the hot dashboard — the core registers
but no C jet ever attaches. Found by tracing _cj_hot_mean in the runtime
(math par=0 MISSmath par=non FOUND once it's a door).

Verified

exp:rd:math .~10x4005.bf0a.8b14.576a (bit-exact), 34 µs jetted vs
~970 µs interpreted; the rest of math.hoon (other fns/widths, the rounding-mode
door idiom) unchanged.

Follow-on

The remaining 14 fns × 4 widths follow this exact mold (one u3wi_ body + tree.c
entry + bit-exact harness each), plus the matching urbit/vere runtime PR.

🤖 Generated with Claude Code

sigilante and others added 6 commits June 11, 2026 10:28
Wrap math.hoon's width doors in a %math engine DOOR under the shared
%non chapter (=< math preserves the /+ math + rd:math API), mirroring
/lib/lagoon's %non/%lagoon jet structure, with ~/ hints on the rd door
and exp arm. The engine MUST be a door (^| =+ [rnd] ~/ %math |%): a
sample-less ~/-core anchors its parent to the dashboard root, so the
jet never attaches (found by tracing _cj_hot_mean in the runtime).

Mirror the vere-side C jet into libmath/vere/ (jets/i/math.c +
tree-registration.snippet.c + README) for hand-maintained cross-repo
sync -- the runtime jets live in urbit/vere (PR to follow). Add
libmath/tools/rd_exp_check.c, the SoftFloat-f64 reference proving the
jet is bit-exact to the Hoon.

@rd exp verified jetted (34us vs ~970us interpreted), bit-exact
0x4005.bf0a.8b14.576a.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add @rd log as the second jetted transcendental, and refactor the vere
master (libmath/vere/jets/i/math.c) so the SoftFloat algorithm cores
(_rd_exp, _rd_log) are shared between the runtime jet and a standalone
bit-exact harness (libmath/vere/test/, via -DMATH_JET_HARNESS) -- the C
the test runs is byte-for-byte the C the jet runs, so they can't drift.

log transcribes math.hoon ++rd ++log (2^e*m reduction + degree-9 atanh
Horner); ~/ %log hint added. Verified bit-exact to the Hoon incl the
subnormal and sqrt(2)-boundary branches, and jetted on-ship
(log:rd:math .~2 = 0x3fe6.2e42.fefa.39ef).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-ship)

Finish the @rd jet port begun with exp/log: add faithful softfloat cores +
u3 wrappers for sin/cos/tan/atan/atan2/asin/acos/sqt/cbt/pow/pow-n/log-2/log-10,
each transcribing its Hoon arm's exact reduction/coefficients/Horner order so
jet output is bit-identical to the pure-Hoon reference, not merely faithful.

- math.hoon: ~/ hints on all 15 @rd arms under the %math door anchor.
- jets/i/math.c: 15 algorithm cores shared with the harness via
  -DMATH_JET_HARNESS, plus u3 ABI wrappers. Fix the 2-arg wrappers
  (atan2/pow/pow-n) to use brace-enclosed u3r_mean pairs {axis,&ptr} —
  the flat form failed -Werror=missing-braces and never compiled.
- test/rd_check.c: add emit2() + atan2/pow/pow-n vectors.
- test/verify_clean.sh: one-query-at-a-time on-ship diff, NO C-c.
  (SIGINT mid-event corrupts the loom; the old verify.sh's C-c spam
  was crashing the serf and masquerading as a jet bug.)

Verified bit-exact on a fresh fakeship: 234/234 vectors, 0 DIFF
(198 single-arg via verify_clean.sh, 36 two-arg via gen/m2.hoon in one
event). sin x 200k under %bout = 431ms (~2.1us/call) confirms jetting.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mirror /lib/lagoon's layout: maintain both runtimes' vendored jet files under
libmath/, in noun/jets/ form. The two math.c copies differ by exactly two lines
-- the two-arg u3r_mean form (brace-pair {axis,&p} on 64-bit vere-ml64 vs flat
varargs on 32-bit vere), because that macro's API diverged between the runtimes.
Everything else (15 algorithm cores, 12 single-arg wrappers, helpers) is
byte-identical: marshalling is chub-based and word-size-agnostic.

- libmath/vere/   noun/jets/{i/math.c,135/tree.c,q.h,w.h} -- 32-bit
- libmath/vere64/ noun/jets/{i/math.c,135/tree.c,q.h,w.h} -- 64-bit (+ test/)

Both built and verified bit-exact: full -test suite (math-exp/log/sqrt/ainv/
atan/tan/trig/derived) passes ok=%.y on a jetted 32-bit AND 64-bit fakeship,
plus the standalone harness's 234 single+two-arg vectors. Vendor 135 only (the
stock test ships' hoon-version; apply to 136/137 only if a target needs them).

Drop the now-redundant tree-registration.snippet.c (the full vendored tree.c
plus the rewritten README supersede it). README documents the 2-line divergence,
per-word-size apply steps, the door-anchor gotcha, -test verification, and the
SIGINT-corrupts-the-loom warning.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add all 15 @rs (single-precision) transcendental jets, single-precision twins
of the @rd cores (same reductions/coeffs, SoftFloat f32, chub marshalling so
they stay word-size-agnostic).  Registered under non/math/rs in 135/tree.c,
q.h/w.h decls, and ~/ hints on the rs door arms.  74 harness vectors bit-exact;
full -test %/tests/lib passes ok=%.y on both the 32- and 64-bit jetted runtimes.

Also fix a latent rounding-mode bug (affected @rd atan2/pow/pow-n from #63, and
the new @rs atan2/pow/pow-n/tan): the math doors carry r=?(%n %u %d %z) whose
bunt is %z, and the composite arms used bare door ops (mul:^rd, (div y x)) that
silently bound that %z bunt instead of honoring r.  The transcendental KERNELS
correctly hardcode ~(mul ^rd %n); only the composite assembly was wrong.

  - Hoon: thread r into the door helper arms (sun/san/toi/drg/grd/add/sub/mul/
    div/fma -> ~(op ^rd r)) for the rd and rs doors, so pow/atan2/tan/pow-n
    honor the door's rounding mode.  Kernels keep their explicit %n.
  - Jets: a file-static _math_rnd, set from the door's r (gate axis 60, mapping
    'n'/'u'/'d'/'z' -> SoftFloat near_even/max/min/minMag), brackets the bare
    ops in the composite cores; kernel calls run at near_even.
  - test-pow-3-2h's expected was baked from the old %z behavior (its pd door is
    %n); corrected to the near-even value (exact arithmetic: 2.5*log3 -> ...43ce
    -> exp -> ...5643).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sigilante sigilante changed the title math: jet-anchor @rd exp + vere jet mirror libmath: add jets for Chebyshev variants of libmath Jun 12, 2026
sigilante and others added 22 commits June 12, 2026 08:29
Add all 15 @rh jets.  Every @rh arm is narrow-sh(rs_fn(widen-hs(x))): widen
f16->f32 (exact = f16_to_f32), compute in the @rs cores, narrow f32->f16
(= f32_to_f16).  No new algorithm cores -- the @rs cores are reused.  16-bit
chub marshalling keeps them word-size-agnostic.

Per the refinement, @rh now inherits the door's rounding mode r instead of
pinning %n (consistent with @rd/@rs):
  - Hoon: the arms thread r into the @rs delegation (~(exp rs [r ...])), so
    the @rs composites honor r; and narrow-sh, formerly a hardcoded
    round-half-to-even, now does directed rounding per r (overflow ->
    inf/max-finite, underflow -> 0/min-subnormal, with an exact-zero guard).
  - Jets: the wrapper sets _math_rnd from the door's r (axis 60); the cores
    run the rs kernels at near-even and narrow via f32_to_f16 at r.

A harness spike (rd_check.c emit_narrow) confirmed the hand-rolled narrow-sh is
bit-exact to SoftFloat f32_to_f16 across all four rounding modes and the edge
cases (subnormals, the e>=143 overflow, the 0x7e00 NaN) -- it caught exactly one
bug (directed rounding of exact zero), now fixed.

Registered rh under non/math in 135/tree.c, q.h/w.h decls, ~/ hints on the @rh
door.  Full -test %/tests/lib (incl math-rh) passes ok=%.y on both the 32- and
64-bit jetted runtimes; jets fire (us) and honor r.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Establish the @rq (quad, 128-bit) jet pipeline, proven bit-exact on exp:
  - Two-chub float128_t marshalling (read u3r_chub(0/1) into v[0..1]); stays
    word-size-agnostic, sidestepping the c3_w*[n=2|4] divergence of rq.c.
  - This SoftFloat build has only pointer-based f128M_*; thin by-value wrapper
    inlines (_rqm/_rqa/_rqs/_rqd/_rqq/_rqeq/...) keep the cores as readable as
    the @rd ones.
  - _rq_exp: Cody-Waite + degree-24 minimax (25 f128 coeffs, extracted from the
    Hoon programmatically), bias 16383.  Bit-exact to (exp:rq:math ...) for
    1/2/-1/0.1 (verified on-ship + harness emit exp-q).
  - Rounding dispatch: thread r into the @rq door helper arms (sun/san/toi/drg/
    grd/add/sub/mul/div/fma -> ~(op ^rq r)) so the composite arms honor r, as in
    @rd/@rs.  -test %/tests/lib still ok=%.y (no regression).

Remaining: the other 14 @rq cores (log/trig/atan/ainv/sqt/cbt/derived) + the rq
wrappers, registration, and ~/ hints -- mechanical, same pattern.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fix the @rq pow/pow-n/atan2 arms to use the bare door ops (mul/div/add/sub/toi/
san) instead of hardcoded ~(op ^rq %n), so they honor the door's r like the
@rd/@rs composites do (tan already used a bare div).  The transcendental kernels
and log-2/log-10/lr keep their explicit %n, matching @rd/@rs.

Verified: @rq div(1,3) gives ...5556 at %u vs ...5555 at %d/%n (honors r); full
-test %/tests/lib still ok=%.y (the math-rq tests use %n doors, where bare ops ==
the old explicit %n, so no regression).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nd-nearest

Explain why a correct/faithful transcendental fixes its internal arithmetic to
round-nearest-even and takes no rounding-mode axis (the faithfulness bound is
defined w.r.t. nearest; directed-rounding the true result is the Table-Maker's
Dilemma), while the door's r governs only the composite arithmetic that assembles
already-rounded kernel outputs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- @rq pow-n was missing the `?> &((gth n .0) (is-int n))` guard that @rd/@rs
  have, so e.g. pow-n(2,-2) returned garbage (8.0) via its @s counter loop. Give
  it the same guard + float-countdown structure as @rd/@rs; negatives/non-integers
  now crash loudly instead of returning nonsense.
- @rh pow-n was delegating to @rs (widen->rs pow-n->narrow) -- a cross-door call.
  Make it native @rh repeated-multiply (it's exact integer multiplication, no
  polynomial, so no need for @rs).  Threads the @rh door helpers for this.

pow-n stays public (Saloon's %pow-n array op dispatches to pow-n:rX:math).
Verified on-ship: pow-n(2,3)=8 (@rq and @rh), pow-n(2,-2) now rejects; -test ok=%.y.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Begin the @rh-native rewrite (no cross-door @rs calls).  exp and log now compute
natively in f16 with derived half-precision minimax (cheb_check.py retargeted to
f16, mpmath-designed, exhaustively verified <=1 ULP):
  - exp: Cody-Waite + deg-4 minimax.  LOG2E=0x3dc5 LN2HI=0x3980 LN2LO=0x1dc8,
    c0..c4=0x3c00 0x3c00 0x3800 0x3160 0x295c.  Two-branch scale2 (overflow split
    k>=16, subnormal split k<-14; f16 can't use 2^24 like @rs -- uses 2^11/2^10),
    overflow k>=17, underflow k<=-25.
  - log: 2^e*m reduction + deg-1 atanh [0x3555,0x3266].  SQRT2=0x3da8, subnormal
    pre-mul 2^10 (not 2^24).
Both explicit %n throughout (kernels take no rounding axis) -- which fixes a real
bug the old delegating arms had: narrow-sh honored the door's r, so the default
%z bunt leaked into exp/log (e.g. exp(1) gave 0x416f toward-zero instead of the
correct nearest 0x4170).  -test %/tests/lib/math-rh ok=%.y.

(Native @rh jets + remaining 11 arms still to come; binary still has the old
delegating jets, so jetted exp:rh/log:rh lag the Hoon until rebuilt.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Native f16 sin/cos via fdlibm ksin/kcos kernels (2 coeffs each: sc=[0xb155,
0x2044] cc=[0x2955,0x95b0]) + 3-part pi/2 reduction (INVPIO2=0x3918, P=0x3e00/
0x2c80/0x0fed).  All explicit %n.  Replaces the @rs delegation.  -test math-rh
ok=%.y.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…terals

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Completes the native f16 @rh door -- no cross-door delegation remains (only
widen-hs/narrow-sh conversions). tan is the sin/cos ratio; atan2/pow honor the
door r via bare composite ops; cbt/log-2/log-10 reuse the native exp/log
kernels; sqt is the stdlib f16 root; lr is the f16 log reduction. Updated
test-tan-1 vector 0x3e3b->0x3e3a (native sin/cos ratio, 0.79 ULP, faithful).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The 15 _rh_* cores now compute entirely in half-precision (SoftFloat f16 ops),
mirroring the native Hoon arms op-for-op -- f16 minimax coeffs, lower poly
degrees (sin/cos/atan/ainv shorter, ainv no denominator, acos no tiny branch).
Verified bit-exact to all 20 math-rh.hoon vectors (test/rh_check.c) and faithful
(<=1.01 ULP) across all 64k finite f16 inputs for exp/log/atan/asin/acos/sqt;
sin/cos faithful for small |x|, lossy for large |x| exactly as the Hoon reduction
intends (test/rh_sweep.c).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Identical to vere64 except the 4 two-arg u3r_mean lines (flat varargs vs brace
pairs), preserving the documented 32/64-bit invariant.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The native f16 kernels read the global softfloat_roundingMode (via f16_mul/add
etc.), but the @rh wrappers only set _math_rnd -- so a kernel called after a %z
door op ran under round-toward-zero, corrupting sin/cos (exp/atan survived by
luck).  Mirror the @rd/@rs wrappers: _rh_jet/_rh_jet2 and the 15 u3qi_rh_*
softpaths now set softfloat_roundingMode = near_even (kernels) and _math_rnd =
door r (composites).  Verified on a fresh fakeship (clean jet dashboard): sin
0x3abb, cos 0x3853, exp 0x4170, tan 0x3e3a(%n)/0x3e39(%z), -test ok=%.y.
Hardened rh_check.c to pre-dirty the global mode so it catches this class.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The full-Horner exp was ~1.10 ULP (not faithful) -- finely sampled vs MPFR it
rounds the dominant ~1.0 result through the whole Horner chain.  Replace with
fdlibm's compensated form exp(r) = 1 - ((lo - r*c/(2-c)) - hi), c = r - t*P(t),
keeping the leading 1+r out of the rounded sum.  P is a deg-10 even minimax in
t=r^2 (11 coeffs, fewer than the 25-term Taylor it replaces).

Result: 0.87 ULP (faithful), validated against MPFR (tools/rq_check.c).
cbt(-27) now lands on exactly -3 (was 1 ULP short); test vector updated.
Derivation + the exact reduction constants live in tools/cheb_check.py exp-rq.
All math-rq tests pass on a fresh fakeship.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fine-sampled audit completes the @rq kernel surface (rq_check.c covers exp/log/
sin/cos/sqrt vs MPFR; this covers atan/asin/acos via a 113-bit mpmath model,
parsing the coeff lists straight out of math.hoon).

Full @rq audit result -- every kernel faithful (<=1 ULP):
  exp 0.836  log 0.854  sin 0.752  cos 0.763  sqrt 0.500
  atan 0.812  asin 0.975  acos 0.853
exp was the lone arm that needed fixing (the fdlibm reconstruction, prior
commit); nothing else flagged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Brings the @rq exp jet core in line with the new Hoon arm (fdlibm rational form,
deg-10 even minimax P).  Verified via tools harness: exp(1) = the correctly-
rounded e, exp(2)=e^2, exp(0)=1.0.  (First core of the @rq jet port; the
remaining 13 + wrappers + registration follow, modeled on the vere32 @rd jet --
f128/2-chub is the structural twin of f64/2-word on a 32-bit runtime.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
log/lr/log-2/log-10, sin/cos/trig kernels, tan (=div sin/cos), atan/atan2,
asin/acos/ainv, sqt/cbt, pow/pow-n -- native f128, mirroring the @rd cores with
the f128 minimax coeffs read from the Hoon (no cross-door calls; composites call
the internal _rq_* C functions directly).  Coeff arrays generated straight from
math.hoon to avoid transcription error.

Verified bit-exact to the math-rq.hoon vectors via test/rq_cores.c (13/13):
log/log2/sin/cos/atan/asin/acos/sqt/cbt/pow/tan all match; tan confirmed against
the live Hoon under the %n door.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
_rq_in/_rq_out (2-chub f128 I/O), _rq_jet/_rq_jet2 (1- and 2-arg, set
softfloat_roundingMode=near-even + _math_rnd from axis 60), and u3qi/u3wi for
all 15 @rq fns.  Models the @rh wrappers (kernels near-even, composites honor
door r) -- carries the softfloat_roundingMode-not-_math_rnd fix from the start.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
15 harms + the _135_non__math_rq_d core + the rq entry in _135_non__math_d,
mirroring @rh; q.h/w.h declare the 15 u3qi_rq_*/u3wi_rq_*.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Identical to vere64 except the 5 two-arg u3r_mean lines (flat varargs).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Updates the stale '@rh/@rq not yet jetted' note; documents the @rq fdlibm exp
reconstruction and the library-wide flat-Horner exp ULP caveat (deferred
retrofit for @rd/@rs/@rh).
Adds the 16 ~/ hints for the @rq door (engine %rq + 15 arm hints),
completing the hint set across all four math doors.

Documents (vere64/README) that the math transcendental jets do NOT
currently attach on-ship -- a structural issue, not kelvin. A lagoon
control (mmul, the sibling userspace jet in the same `non` chapter)
fires on the same hoon-version-136 ship; math does not. Cause: the
`math` engine core makes the width doors grandchildren of the `non`
chapter (chapter->engine->door->arm, 3-deep) vs the standard
chapter->door->arm (lagoon's `la`, kernel two->by/two->in). The jet C
code itself is correct (test/rq_cores.c harness 13/13); only on-ship
attachment is blocked. Fix direction pending core-dev review.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant