generated from amazon-archives/__template_Apache-2.0
-
Notifications
You must be signed in to change notification settings - Fork 27
Add recursive functions to Strata Core #499
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 23 commits
Commits
Show all changes
41 commits
Select commit
Hold shift + click to select a range
bebccfc
Add recursive info to LFunc
8fef085
Merge branch 'main' into josh/rec-fun
0a92744
Add generation of axioms for recursive functions
78f2df0
Add metadata and error handling
57cadf4
Add SMT encoding (axioms) for recursive functions
b47f014
Add tests for SMT encoding, fix annotation issue
4b13671
Change to decreases expr, partial support in Translate
204007f
Add DDM scopeSelf to support recursive functions
3ecacd5
Fix typechecker recursive issue
8970297
Merge branch 'main' into josh/rec-fun
9a75f02
Tests for recursive functions
b8435d3
Merge branch 'main' into josh/rec-fun
34e842b
Merge branch 'main' into josh/rec-fun
a2cca5e
Combine Translate logic, ensure recfun supports preconditions
7dca6b2
Small change to test
533ed2d
Simplify scopeSelf, add error checks for non-supported features
892ac60
Add comments to Env.addFactoryFunction
4d73ff1
Add documentation about @[scopeSelf]
fb7e418
Merge branch 'main' into josh/rec-fun
87258c8
Fix errors from merge
b460dd7
Update small-step semantics for ITE
0c7bea0
Fix comment with invariant
5c7b753
Merge branch 'main' into josh/rec-fun
0344ec3
Improve comments and error messages
344ede6
Fix tests
fceb805
Change "recursive" to "rec"
caedcbc
Change decreases to @[cases] annotation on parameter
2361d26
Remove references to "decreasing"
cd1daa7
Merge branch 'main' into josh/rec-fun
991d207
Update test output from safe destructors
abc8e7f
Merge branch 'main' into josh/rec-fun
MikaelMayer 4720ef8
Fix test output
a3c78c2
Merge branch 'main' into josh/rec-fun
bf459e0
Merge branch 'main' into josh/rec-fun
7249808
Merge branch 'main' into josh/rec-fun
659575b
Address review comments
c3b6c67
Merge branch 'main' into josh/rec-fun
a4b8788
Add top-level info to RecursiveFunctions.md
4244c7e
Remove boogie references in docs
5c01fcc
Fix concrete syntax in doc
6fa35f1
Merge branch 'main' into josh/rec-fun
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| /- | ||
| Copyright Strata Contributors | ||
|
|
||
| SPDX-License-Identifier: Apache-2.0 OR MIT | ||
| -/ | ||
|
|
||
| import Strata.DL.Lambda.Factory | ||
| import Strata.DL.Lambda.TypeFactory | ||
| import Strata.DL.Util.List | ||
|
|
||
| /-! | ||
| ## Axiom Generation for Recursive Functions | ||
shigoel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| Given a recursive function with a `decreases` parameter over an algebraic datatype, | ||
| generates per-constructor axioms. Each axiom is a quantified equation: | ||
|
|
||
| ∀ (other_params..., fields...). f(..., C(fields...), ...) = PE(f(..., C(fields...), ...)) | ||
|
|
||
| The LHS is left unevaluated (it serves as the trigger pattern). The RHS is obtained by | ||
| passing the LHS to the partial evaluator, which inlines the function (since the recursive | ||
| argument is a constructor application) and reduces. | ||
MikaelMayer marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| -/ | ||
|
|
||
| namespace Lambda | ||
|
|
||
| open Std (Format format) | ||
| open Strata.DL.Util (FuncAttr) | ||
|
|
||
| /-- Check well-formedness of a recursive function and extract the components | ||
| needed for axiom generation: recParam index and datatype. | ||
| The `inlineIfConstr` attribute must have been previously set by `addFactoryFunc` | ||
| (which resolves the `decreases` expression to a parameter index). -/ | ||
| def checkRecursiveFunc [DecidableEq T.IDMeta] | ||
| (func : LFunc T) (tf : @TypeFactory T.IDMeta) | ||
| : Except Format (Nat × LDatatype T.IDMeta) := do | ||
| if func.inputs.isEmpty then | ||
| .error f!"Recursive function {func.name} must have at least one parameter" | ||
| let recIdx ← FuncAttr.findInlineIfConstr func.attr |>.elim | ||
| (.error f!"Recursive function {func.name} has no inlineIfConstr attribute") .ok | ||
| let inputTys := func.inputs.values | ||
| let recTy ← inputTys[recIdx]? |>.elim | ||
| (.error f!"Recursive function {func.name}: recParam index {recIdx} out of bounds") .ok | ||
| let dtName ← match recTy with | ||
| | LMonoTy.tcons n _ => .ok n | ||
| | _ => .error f!"Recursive function {func.name}: decreases parameter type is not a datatype" | ||
| let dt ← tf.getType dtName |>.elim | ||
| (.error f!"Recursive function {func.name}: datatype {dtName} not found") .ok | ||
| return (recIdx, dt) | ||
|
|
||
| /-- Generate per-constructor axiom LExprs for a recursive function. | ||
| Assumes the function is well-formed (use `checkRecursiveFunc` first). | ||
| The PE must have the function in its factory with `inlineIfConstr`. -/ | ||
| def mkRecursiveAxioms [Inhabited T.Metadata] [DecidableEq T.Metadata] [DecidableEq T.IDMeta] | ||
| (func : LFunc T) (recIdx : Nat) (dt : LDatatype T.IDMeta) | ||
| (pe : LExpr T.mono → LExpr T.mono) (m : T.Metadata) | ||
| : Except Format (List (LExpr T.mono)) := | ||
| let formals := func.inputs.keys | ||
| let inputTys := func.inputs.values | ||
| dt.constrs.mapM fun c => do | ||
| let numFields := c.args.length | ||
MikaelMayer marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| let totalBvs := numFields + formals.length - 1 | ||
| -- Binding order (outermost → innermost): other params, then constructor fields. | ||
| -- Example: lookup(key:int, xs:IntList) with recIdx=1, Cons(hd,tl): | ||
| -- ∀ key:int. ∀ hd:int. ∀ tl:IntList. lookup(key=%2, Cons(hd=%1, tl=%0)) = ... | ||
| let dtTy : LMonoTy := .tcons dt.name [] | ||
| let constrTy := c.args.foldr (fun (_, argTy) acc => .arrow argTy acc) dtTy | ||
| let constrApp := c.args.foldlIdx (fun acc i _ => | ||
| .app m acc (.bvar m (numFields - 1 - i)) | ||
| ) (.op m c.name (.some constrTy) : LExpr T.mono) | ||
| let otherIdx (idx : Nat) : Nat := if idx < recIdx then idx else idx - 1 | ||
| let formalExpr (idx : Nat) : LExpr T.mono := | ||
| if idx == recIdx then constrApp | ||
| else .bvar m (totalBvs - 1 - otherIdx idx) | ||
| -- LHS: f(bvars..., C(fields...), bvars...) — not PE'd (serves as trigger) | ||
| let lhs := formals.foldlIdx (fun acc idx _ => | ||
| .app m acc (formalExpr idx) | ||
| ) (LFunc.opExpr func) | ||
| -- RHS: PE inlines the function since the recursive arg is a constructor | ||
| let rhs := pe lhs | ||
| if lhs == rhs then | ||
| .error f!"Recursive function {func.name}: PE did not reduce axiom for \ | ||
| constructor {c.name}. Ensure the function is in the factory with inlineIfConstr." | ||
MikaelMayer marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| let eq : LExpr T.mono := .eq m lhs rhs | ||
| -- Wrap in quantifiers innermost-first: fields (with trigger on innermost), | ||
| -- then other params. | ||
| let allTys := (c.args.map (·.snd)).reverse ++ (inputTys.eraseIdx recIdx).reverse | ||
| match allTys with | ||
| | [] => .ok eq | ||
| | ty :: rest => | ||
| let inner := LExpr.quant m .all (.some ty) lhs eq | ||
| .ok (rest.foldl (fun body ty => | ||
| .quant m .all (.some ty) (LExpr.noTrigger m) body | ||
| ) inner) | ||
|
|
||
| /-- Generate per-constructor axiom LExprs for a recursive function, | ||
| including well-formedness checking. -/ | ||
| def genRecursiveAxioms [Inhabited T.Metadata] [DecidableEq T.Metadata] [DecidableEq T.IDMeta] | ||
| (func : LFunc T) (tf : @TypeFactory T.IDMeta) | ||
| (pe : LExpr T.mono → LExpr T.mono) (m : T.Metadata) | ||
| : Except Format (List (LExpr T.mono)) := do | ||
| let (recIdx, dt) ← checkRecursiveFunc func tf | ||
| mkRecursiveAxioms func recIdx dt pe m | ||
|
|
||
| end Lambda | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.