-
Notifications
You must be signed in to change notification settings - Fork 0
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
feat: implement ac_nf'
, an alternative normalizer that takes terms shared across both sides of an equality into account
#43
base: master
Are you sure you want to change the base?
Conversation
…shared across both sides of an equality into account
2a3cea9
to
f30abf7
Compare
Currently, I've deliberately implemented the new This was deliberate, as I'd expect changes to ac_nf to invite additional scrutiny in review, but it does mean we're wasting some time by computing similar things twice. Then again, as the benchmark showed, tactic runtime is not a bottleneck at all, so this might be entirely fine. We might be able to also generate a more optimized proof-term by sharing implementation, which would be slightly more significant, but I'm not a 100% sure how much benefit there is on that side. |
I think this was mostly fine. There was one change to ac_nf that deliberately changes the proof terms it generates to avoid overly eager kernel reduction. We should make sure these fixes also work in our case (change ac_nf history for details). |
ac_nf!
, an alternative normalizer that takes terms shared across both sides of an equality into accountac_nf'
, an alternative normalizer that takes terms shared across both sides of an equality into account
Turns out the sharing behaviour the example was meant to highlight is not actually implemented
This emphasizes that it only works for binary applications
The hyp is exactly the theorem statement, nothing is being tested
@@ -1,39 +1,362 @@ | |||
/- | |||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved. | |||
Copyright (c) 2024 Lean FRO, LLC. All rights reserved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Time travelling copyright is interesting :P Also an interesting question whether this file's copyright should be FRO if neither of the authors are associated with the FRO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The year is indeed wrong. Not sure what to do with the copyright: a tiny part of the original file (the declaration of the pass) remains, not sure what the copyright implications of that are
|
||
example (x y : BitVec 256) : x * y = y * x := by | ||
bv_decide (config := { acNf := true }) | ||
|
||
example {x y z : BitVec 64} : ~~~(x &&& (y * z)) = (~~~x ||| ~~~(z * y)) := by |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did we have to change this test case? Does it not work quickly anymore? That would be quite the shame.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bollu, I believe you made this change?
let simpCtx ← Simp.mkContext | ||
(simpTheorems := {}) | ||
(congrTheorems := (← getSimpCongrTheorems)) | ||
(config := Simp.neutralConfig) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably want to thread the max rewrite steps from PreProcessM
through to this simp call in order to make sure that on SMTLIB we do not run out of rewrite steps for large expressions.
(Sid's notes on the algorithmic details are at: https://gist.github.com/bollu/e204a1f4d5a042695eee9cbaebce214a) |
Co-authored-by: Henrik Böving <[email protected]>
Co-authored-by: Henrik Böving <[email protected]>
This removes the need to carry it around in the `Op`. This is technically less general, as it only works with the default instance, but the rest of the code assumes the instance is the default one regardless (e.g., when determining the neutral element), so in practice there is no difference
Earlier passes in bv_normalize should have already rewritten all `Eq`s to Beq
This removes the need to infer the universe
This def lives in the `BVDecide.Frontend.Normalize` namespace, so it deserves a name that ties it to bvAcNf
This PR adds
ac_nf'
, a tactic that normalizes terms up to commutativity and associativity, much like ac_nf, but does it in a way that exposes common terms among both sides of an equality. For example,x₁ * (y₁ * z) = x₂ * (y₂ * z)
is normalized toz * (x₁ * y₁) = z * (x₂ * y₂)
, pulling the shared variablez
to the front on both sides. The PR also replaces the use ofac_nf
in the normalization pass ofbv_decide
.This tactic reuses the existing
ac_nf
implementation to (a) normalize compound atomic expression (e.g.,x + y
andy + x
inx * (y + x) * (x + y)
) and (b) produce an equivalence proof once a sharing-aware normal form has been determined. The newac_nf'
tactic is thus not a replacement forac_nf
.Furthermore, we only run the normalization on terms of the form
(a * b) = (c * d)
fora, b, c, d
bitvectors. This mirrors Bitwuzla'sPassNormalize::process
'sPassNormalize::normalize_eq_add_mul
. We leave the implementation ofPassNormalize::normalize_comm_assoc
, which is called when the toplevel terms are different for a subsequent patch.For posterity, we record the precise location in Bitwuzla where the codepath occurs: