Skip to content

Commit de7d4aa

Browse files
authored
Merge pull request #9257 from kim-em/agent/interval-pnt-log-two
feat(interval): replay pinned PNT log two bounds
2 parents 51c97d7 + 70e325c commit de7d4aa

11 files changed

Lines changed: 821 additions & 10 deletions

File tree

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
/-
2+
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Kim Morrison
5+
-/
6+
7+
module
8+
9+
public import HexInterval.Experiment.PolicySession
10+
11+
@[expose] public section
12+
13+
/-!
14+
# Mathlib-free PNT+ logarithm-table probe
15+
16+
This package is a deliberately small acceptance vertical for the first two
17+
entries of PNT+'s pinned `LogTables.lean`: the lower and upper bounds on
18+
`log 2`. The executable side knows neither real logarithms nor decimal
19+
semantics. It only propagates a package-owned finite fact from an exact-input
20+
fact. `HexIntervalMathlib` supplies and checks the mathematical meaning.
21+
22+
The finite fact domain is intentionally local to the probe. It demonstrates
23+
the generic watched-input planning and replay boundary without pretending to
24+
be the eventual arbitrary-precision dyadic logarithm package.
25+
-/
26+
27+
namespace Hex.Interval.Experiment.PntLogTable
28+
29+
open Propagator PayloadArena
30+
31+
/-- Facts needed by the source-pinned `log 2` acceptance probe. -/
32+
inductive Bound where
33+
| all
34+
| two
35+
| logTwoWindow
36+
| empty
37+
deriving DecidableEq, Repr
38+
39+
namespace Bound
40+
41+
/-- Exact intersection for the probe's finite fact lattice. -/
42+
def meet : Bound → Bound → Bound
43+
| .empty, _ | _, .empty => .empty
44+
| .all, right => right
45+
| left, .all => left
46+
| .two, .two => .two
47+
| .logTwoWindow, .logTwoWindow => .logTwoWindow
48+
| .two, .logTwoWindow | .logTwoWindow, .two => .empty
49+
50+
def code : Bound → Nat
51+
| .all => 0
52+
| .two => 1
53+
| .logTwoWindow => 2
54+
| .empty => 3
55+
56+
def ofCode? : Nat → Option Bound
57+
| 0 => some .all
58+
| 1 => some .two
59+
| 2 => some .logTwoWindow
60+
| 3 => some .empty
61+
| _ => none
62+
63+
end Bound
64+
65+
def factDomain : FactDomain Bound where
66+
top _ := .all
67+
narrow _ current proposed :=
68+
let installed := current.meet proposed
69+
if installed == current then .noChange
70+
else if installed == .empty then .contradiction installed
71+
else .improved installed
72+
73+
def real : DomainId := { index := 0 }
74+
75+
def sourceKey : OpKey := { name := "pnt-log-table.source" }
76+
def logKey : OpKey := { name := "pnt-log-table.log" }
77+
def logRuleKey : RuleKey := { name := "pnt-log-table.log-two" }
78+
79+
def sourceOperation : Operation :=
80+
{ key := sourceKey, inputs := [], output := real }
81+
82+
def logOperation : Operation :=
83+
{ key := logKey, inputs := [real], output := real }
84+
85+
def operations : Array Operation := #[sourceOperation, logOperation]
86+
87+
def node (index : Nat) : NodeId := { index }
88+
def payload (index : Nat) : PayloadId := { index }
89+
90+
def sourceInstruction : Node :=
91+
{ domain := real, op := { index := 0 }, args := [] }
92+
93+
def logInstruction : Node :=
94+
{ domain := real, op := { index := 1 }, args := [node 0] }
95+
96+
/-- Caller graph for the closed expression `Real.log 2`. -/
97+
def program : Program :=
98+
{ operations, nodes := #[sourceInstruction, logInstruction] }
99+
100+
def logRule : Registration :=
101+
{ key := logRuleKey
102+
head := logKey
103+
kind := .forward
104+
watches := [.argument 0]
105+
writes := [.result] }
106+
107+
def factFormat : ReplayFormat :=
108+
{ role := .fact
109+
schema := 1
110+
validateBody := fun body =>
111+
match body with
112+
| [code] => Bound.ofCode? code == some .logTwoWindow
113+
| _ => false }
114+
115+
/-- The source-pinned table entry applies only when the watched input is
116+
known to be exactly two. -/
117+
def logPlan (request : RuleRequest Bound) : Plan Bound :=
118+
match request.inputs, request.writes with
119+
| [input], [target] =>
120+
if input.fact == .two then
121+
{ outcome :=
122+
.success
123+
[{ node := target, fact := .logTwoWindow, payload := payload 0 }]
124+
[] { arithmeticWork := 1, estimatedProofNodes := 1 }
125+
drafts :=
126+
[{ label := payload 0
127+
role := .fact
128+
schema := 1
129+
body := [Bound.logTwoWindow.code] }] }
130+
else
131+
{ outcome := .noChange {}, drafts := [] }
132+
| _, _ => { outcome := .failed 1, drafts := [] }
133+
134+
def sourcePackage : Package Bound :=
135+
{ Cache := Unit
136+
cache := ()
137+
operations := #[sourceOperation]
138+
handlers := #[] }
139+
140+
def logPackage : Package Bound :=
141+
{ Cache := Unit
142+
cache := ()
143+
operations := #[logOperation]
144+
handlers := #[Handler.statelessPlanned logRule logPlan #[factFormat]] }
145+
146+
def packages : Array (Package Bound) := #[sourcePackage, logPackage]
147+
148+
def engineLimits : Propagator.Limits :=
149+
{ maxOperations := 2
150+
maxNodes := 3
151+
maxRules := 1
152+
maxRegistryEntries := 8
153+
maxReplayFormats := 2
154+
maxArity := 1
155+
maxScopeNodes := 1
156+
maxApplications := 2
157+
maxQueueEntries := 8
158+
maxActions := 4
159+
maxMatcherVisits := 2
160+
matcherBatchSize := 2
161+
maxAcceptedFacts := 2
162+
maxRetainedSuggestions := 0
163+
maxEffort := 0
164+
maxObservationValue := 8
165+
maxDiagnosticValue := 300
166+
maxOutcomeCandidates := 1
167+
maxOutcomeSuggestions := 0
168+
maxProposalItems := 1
169+
maxInstances := 0
170+
maxGeneration := 0
171+
maxNodeDepth := 2
172+
maxEqualities := 0
173+
splitEndpointLimit :=
174+
{ maxEndpointHeight := 8, maxAlignmentShift := 4 } }
175+
176+
def policyLimits : Propagator.Policy.Limits :=
177+
{ maxDecisions := 8
178+
maxTraversal := 32
179+
maxLiveOffers := 8 }
180+
181+
def arenaLimits : PayloadArena.Limits :=
182+
{ maxEntries := 4
183+
maxBodyCells := 4
184+
maxDrafts := 2
185+
maxDraftCells := 2
186+
maxAtom := 8
187+
maxSchema := 1
188+
maxUses := 2 }
189+
190+
def limits : PolicySession.Limits :=
191+
{ engine := engineLimits, policy := policyLimits, arena := arenaLimits }
192+
193+
def start : Except PolicySession.StartError (PolicySession.Session Bound) :=
194+
PolicySession.Session.start factDomain program packages #[.two, .all] limits
195+
196+
end Hex.Interval.Experiment.PntLogTable

HexInterval/SPEC/hex-interval.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3208,6 +3208,16 @@ generic expression search.
32083208

32093209
#### Certified logarithm tables
32103210

3211+
The initial source-pinned PNT+ probe is intentionally narrower than this
3212+
table-building target. A Mathlib-free package recognizes the exact input fact
3213+
for `2` and emits a package-owned opaque fact through the generic policy
3214+
session. Its Mathlib companion interprets that fact as PNT+'s six-decimal
3215+
two-sided `log 2` window and replays the event from stronger existing Mathlib
3216+
point bounds. This validates exact-input dependency, package-owned fact replay,
3217+
and ordinary theorem closure. It is not a generic logarithm propagator, does
3218+
not compute a series, and does not satisfy any of the precision, batching,
3219+
ordering, or cache requirements below.
3220+
32113221
The table-building acceptance program constructs enclosures for
32123222

32133223
`Real.log (1 + (i : ℝ) / 256)`, for every `i : ℕ` with `i ≤ 256`,

0 commit comments

Comments
 (0)