Skip to content

Commit 887b1c9

Browse files
authored
Merge pull request #3 from LeanMachineLearning/autoInstance
Add attribute to derive IsMarkov instance
2 parents 0c2b643 + 1ee85b1 commit 887b1c9

2 files changed

Lines changed: 80 additions & 0 deletions

File tree

‎RandomDo.lean‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public import RandomDo.Monad.ForInInstances
77
public import RandomDo.Monad.Instances
88
public import RandomDo.Monad.MeasurableSpace
99
public import RandomDo.Monad.Notation
10+
public import RandomDo.Tactic.Deriving
1011
public import RandomDo.Tactic.Elab
1112
public import RandomDo.Tactic.Examples
1213
public import RandomDo.Tactic.ForInStep

‎RandomDo/Tactic/Deriving.lean‎

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/-
2+
Copyright (c) 2026 Rémy Degenne. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Rémy Degenne
5+
-/
6+
module
7+
8+
public import RandomDo.Tactic.Elab
9+
10+
/-!
11+
# The `@[is_markov]` attribute
12+
13+
Writing an `rdo` program and then stating that it is a Markov kernel are two separate steps, and
14+
the second is mechanical: it is what `is_markov` does. This attribute runs it at the declaration,
15+
so a program carries its own instance:
16+
17+
```
18+
@[is_markov]
19+
noncomputable def centred (c : ℝ) : Measure ℝ := rdo
20+
let x ← gaussianReal c 1
21+
return x
22+
```
23+
24+
## Which statement is generated
25+
26+
A program's *last* argument is read as the kernel's parameter when it is explicit, giving
27+
`IsMarkov`. Otherwise the program denotes one fixed distribution and the statement is
28+
`IsProbabilityMeasure`. So `centred` above yields `IsMarkov centred`, while a parameterless program
29+
yields `IsProbabilityMeasure` of it, and a program whose trailing arguments are instance-implicit —
30+
`(μ : Measure ℝ) [IsProbabilityMeasure μ]` — yields `IsProbabilityMeasure` of it too, with those
31+
arguments bound.
32+
-/
33+
34+
public meta section
35+
36+
open Lean Meta Elab Term MeasureTheory
37+
38+
namespace RDo.Tactic
39+
40+
/-- The statement to prove for `declName`, as described in the module docstring. -/
41+
def isMarkovStatement (declName : Name) : MetaM Expr := do
42+
let info ← getConstInfo declName
43+
forallTelescope info.type fun args body ↦ do
44+
unless body.isAppOfArity ``MeasureTheory.Measure 2 do
45+
throwError "`IsMarkov` can only be derived for a declaration valued in `Measure`, but \
46+
{declName} is valued in{indentExpr body}"
47+
let f := mkAppN (mkConst declName (info.levelParams.map .param)) args
48+
if h : 0 < args.size then
49+
let last := args[args.size - 1]
50+
if (← last.fvarId!.getDecl).binderInfo.isExplicit then
51+
return ← mkForallFVars args.pop (← mkAppM ``IsMarkov #[← mkLambdaFVars #[last] f])
52+
mkForallFVars args (← mkAppM ``MeasureTheory.IsProbabilityMeasure #[f])
53+
54+
/-- Prove `isMarkovStatement declName` with the `is_markov` tactic and register it as an
55+
instance. -/
56+
def addIsMarkovInstance (declName : Name) : TermElabM Unit := do
57+
let goal ← isMarkovStatement declName
58+
let proof ← Term.elabTerm (← `(by intros; is_markov)) (some goal)
59+
Term.synthesizeSyntheticMVarsNoPostponing
60+
let info ← getConstInfo declName
61+
let instName := declName ++ `isMarkov
62+
addDecl (.thmDecl { name := instName, levelParams := info.levelParams, type := goal,
63+
value := ← instantiateMVars proof })
64+
Meta.addInstance instName .global 1000
65+
66+
/-- The `@[is_markov]` attribute. -/
67+
initialize registerBuiltinAttribute {
68+
name := `is_markov
69+
descr := "prove that this `rdo` program is a Markov kernel, and register it as an instance"
70+
applicationTime := .afterCompilation
71+
add := fun declName _stx kind ↦ do
72+
unless kind == AttributeKind.global do
73+
throwError "`is_markov` must be a global attribute"
74+
(addIsMarkovInstance declName).run'.run'
75+
}
76+
77+
end RDo.Tactic
78+
79+
end

0 commit comments

Comments
 (0)