1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
;;; Copyright (c) 2026 Nicholas Vermeulen
;;; SPDX-License-Identifier: AGPL-3.0-or-later
;; units.lisp — dimensional-consistency checking as a STATIC gate. Pure Lisp,
;; zero interpreter changes; a walker over the same restricted numeric AST
;; subset as `grad` / `check-effects` / `check-types` (numbers, symbols,
;; + - * / expt sqrt, the numeric unary fns, comparisons, if).
;;
;; A DIMENSION is a 7-vector of integer exponents over the SI base dimensions
;; [ M L T I Θ N J ] = (mass length time current temperature amount
;; luminous). `check-units` derives the dimension of every subexpression and
;; refuses a dimensionally illegal one (`m + s`, `sin(m)`, …) as DATA — an
;; `(unit-error …)` list, never a raise — so it composes as a cheap gate
;; placed BEFORE the numeric work (check-exhaustive / defrust) runs.
;;
;; Claim discipline: "dimensionally consistent on this AST", per the
;; bounded-verification rule — NOT "physically correct". A subset caveat:
;; only MULTIPLICATIVE units (no temperature offsets like °C/°F — those aren't
;; a pure scaling and would need an affine model); exponents are INTEGER, so
;; `sqrt` of an odd-exponent dimension is refused rather than faked as
;; fractional. Everything is symbol/integer data — deterministic.
;; ── Dimension algebra (7 integer exponents) ──────────────────────────────
; k integer (expt)
;; ── Unit table: name -> dimension vector (base + a few derived) ──────────
; hertz 1/s
;; Reverse lookup for readable output: a known unit name, else the vector.
;; ── The walker ────────────────────────────────────────────────────────────
;; expt/sqrt are special: expt's exponent is a literal, not a quantity.
;; Operator families (all operands' dimensions already derived, error-free).
; equal dims -> that dim
; dimensionless -> dimensionless
; 1 arg, dim unchanged
; equal dims -> dimensionless
;; ── Convenience ──────────────────────────────────────────────────────────
; empty variable env
;; Build a variable env from (var unit-name) declarations.
;; ── Multiplicative conversion + an EXHAUSTIVE round-trip proof ───────────
;; Scale table: name -> (dim factor) where factor is the size in the finest
;; unit of that dimension (INTEGER, so a multiply-first round-trip is exact).
;; Prove that converting to a finer unit and back is the identity over a
;; finite integer grid — a real check-exhaustive 'verified (multiply-first is
;; exact for integers). from must be the COARSER unit (multiply first).