Zulip Chat Archive
Stream: lean4
Topic: unfold essentially loops
Sébastien Michelland (Jun 30 2022 at 20:28):
The following piece of code causes unfold
to run for time exponential in the length of either string (while constantly allocating memory). Sorry for the somewhat contrived MWE @Leonardo de Moura, I wasn't able to cut it down any further. Confirmed on yesterday's nightly leanprover/lean4:nightly-2022-06-29
.
inductive Wrapper where
| wrap: Wrapper
def Wrapper.extend: Wrapper → (Unit × Unit)
| .wrap => ((), ())
mutual
inductive Op where
| mk: String → Block → Op
inductive Assign where
| mk : String → Op → Assign
inductive Block where
| mk: Assign → Block
| empty: Block
end
mutual
def runOp: Op → Wrapper
| .mk _ r => let r' := runBlock r; .wrap
def runAssign: Assign → Wrapper
| .mk _ op => runOp op
def runBlock: Block → Wrapper
| .mk a => runAssign a
| .empty => .wrap
end
private def b: Assign := .mk "r" (.mk "APrettyLongString" .empty)
theorem bug: (runAssign b).extend.snd = (runAssign b).extend.snd := by
--unfold b -- extremely slow
sorry
Leonardo de Moura (Jul 01 2022 at 00:56):
@Sébastien Michelland Thanks for reporting this issue. I pushed a fix for it.
https://github.com/leanprover/lean4/commit/14260f454b9b73d85aafef5e7be79c58ce4381b5
The problem was not unfold
, but type checking the proof generated using unfold
in the kernel.
When checking whether s.i
and r.i
are definitionally equal, the kernel was always trying to reduce them. However, in your example, this is very expensive, and checking whether s
and r
are definitionally equal first is a better strategy.
I have another commit that also fixes the problem in the isDefEq
for the MetaM
monad.
Sébastien Michelland (Jul 01 2022 at 10:39):
Thanks for the super quick fixes, this is helping a ton. Reducing entire projects never felt so worthwhile :)
Last updated: Dec 20 2023 at 11:08 UTC