feat(lean4): add formal verification specs for ensemble models

Lean 4 formalization of the decision tree + MLP ensemble architecture.
Axiomatizes Float properties (sigmoid bounds, ReLU nonnegativity) since
Lean's Float ops are extern-backed. Proves MLP output is bounded in (0,1)
and ensemble output is always a valid decision. No mathlib dependency.

Signed-off-by: Sienna Meridian Satterwhite <sienna@sunbeam.pt>
This commit is contained in:
2026-03-10 23:38:21 +00:00
parent 5daed3ecb0
commit 982cf5755d
12 changed files with 314 additions and 0 deletions

View File

@@ -0,0 +1,42 @@
import Sunbeam.Model.Basic
import Sunbeam.Model.MLP
import Sunbeam.Model.DecisionTree
namespace Sunbeam
/-- Ensemble: tree decides first; MLP handles only Defer cases. -/
def ensemblePredict {inputDim hiddenDim : Nat}
(tree : TreeNode) (mlpWeights : MLPWeights inputDim hiddenDim)
(threshold : Float) (input : FloatVec inputDim) : Decision :=
match treePredictAux input tree with
| Decision.block => Decision.block
| Decision.allow => Decision.allow
| Decision.defer =>
let score := mlpForward mlpWeights input
if score > threshold then Decision.block else Decision.allow
/-- If the tree says Block, the ensemble says Block. -/
theorem tree_block_implies_ensemble_block {inputDim hiddenDim : Nat}
(tree : TreeNode) (mlpWeights : MLPWeights inputDim hiddenDim)
(threshold : Float) (input : FloatVec inputDim)
(h : treePredictAux input tree = Decision.block) :
ensemblePredict tree mlpWeights threshold input = Decision.block := by
unfold ensemblePredict
rw [h]
/-- Ensemble output is always Block or Allow (never Defer). -/
theorem ensemble_output_valid {inputDim hiddenDim : Nat}
(tree : TreeNode) (mlpWeights : MLPWeights inputDim hiddenDim)
(threshold : Float) (input : FloatVec inputDim) :
ensemblePredict tree mlpWeights threshold input = Decision.block
ensemblePredict tree mlpWeights threshold input = Decision.allow := by
unfold ensemblePredict
split
· left; rfl
· right; rfl
· dsimp only []
split
· left; rfl
· right; rfl
end Sunbeam