Files
proxy/lean4/Sunbeam/Model/Ensemble.lean
Sienna Meridian Satterwhite 982cf5755d 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>
2026-03-10 23:38:21 +00:00

43 lines
1.5 KiB
Lean4
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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