99public import Lean.Meta.LazyDiscrTree
1010public import Lean.Meta.Tactic.SolveByElim
1111public import Lean.Util.Heartbeats
12+ public import Lean.Elab.Parallel
1213
1314public section
1415
@@ -119,20 +120,6 @@ def libSearchFindDecls : Expr → MetaM (Array (Name × DeclMod)) :=
119120 (droppedKeys := droppedKeys)
120121 (constantsPerTask := constantsPerImportTask)
121122
122- /--
123- Return an action that returns true when the remaining heartbeats is less
124- than the currently remaining heartbeats * leavePercent / 100.
125- -/
126- def mkHeartbeatCheck (leavePercent : Nat) : MetaM (MetaM Bool) := do
127- let maxHB ← getMaxHeartbeats
128- let hbThreshold := (← getRemainingHeartbeats) * leavePercent / 100
129- -- Return true if we should stop
130- pure $
131- if maxHB = 0 then
132- pure false
133- else do
134- return (← getRemainingHeartbeats) < hbThreshold
135-
136123private def librarySearchEmoji : Except ε (Option α) → String
137124| .error _ => bombEmoji
138125| .ok (some _) => crossEmoji
@@ -157,24 +144,6 @@ def interleaveWith {α β γ} (f : α → γ) (x : Array α) (g : β → γ) (y
157144 (y.extract n y.size).map g
158145 pure $ res ++ last
159146
160- /--
161- An exception ID that indicates further speculation on candidate lemmas should stop
162- and current results should be returned.
163- -/
164- private builtin_initialize abortSpeculationId : InternalExceptionId ←
165- registerInternalExceptionId `Lean.Meta.LibrarySearch.abortSpeculation
166-
167- /--
168- Called to abort speculative execution in library search.
169- -/
170- def abortSpeculation [MonadExcept Exception m] : m α :=
171- throw (Exception.internal abortSpeculationId {})
172-
173- /-- Returns true if this is an abort speculation exception. -/
174- def isAbortSpeculation : Exception → Bool
175- | .internal id _ => id == abortSpeculationId
176- | _ => false
177-
178147section LibrarySearch
179148
180149/--
@@ -241,59 +210,14 @@ private def librarySearchLemma (cfg : ApplyConfig) (act : List MVarId → MetaM
241210 else
242211 failure
243212
244- /--
245- Sequentially invokes a tactic `act` on each value in candidates on the current state.
246-
247- The tactic `act` should return a list of meta-variables that still need to be resolved.
248- If this list is empty, then no variables remain to be solved, and `tryOnEach` returns
249- `none` with the environment set so each goal is resolved.
250-
251- If the action throws an internal exception with the `abortSpeculationId` id then
252- further computation is stopped and intermediate results returned. If any other
253- exception is thrown, then it is silently discarded.
254- -/
255- def tryOnEach
256- (act : Candidate → MetaM (List MVarId))
257- (candidates : Array Candidate) :
258- MetaM (Option (Array (List MVarId × MetavarContext))) := do
259- let mut a := #[]
260- let s ← saveState
261- for c in candidates do
262- match ← (tryCatch (Except.ok <$> act c) (pure ∘ Except.error)) with
263- | .error e =>
264- restoreState s
265- if isAbortSpeculation e then
266- break
267- | .ok remaining =>
268- if remaining.isEmpty then
269- return none
270- let ctx ← getMCtx
271- restoreState s
272- a := a.push (remaining, ctx)
273- return (.some a)
274-
275- private def librarySearch' (goal : MVarId)
276- (tactic : List MVarId → MetaM (List MVarId))
277- (allowFailure : MVarId → MetaM Bool)
278- (leavePercentHeartbeats : Nat) :
279- MetaM (Option (Array (List MVarId × MetavarContext))) := do
280- withTraceNode `Tactic.librarySearch (return m!"{librarySearchEmoji ·} {← goal.getType}" ) do
281- profileitM Exception "librarySearch" (← getOptions) do
282- -- Create predicate that returns true when running low on heartbeats.
283- let candidates ← librarySearchSymm libSearchFindDecls goal
284- let cfg : ApplyConfig := { allowSynthFailures := true }
285- let shouldAbort ← mkHeartbeatCheck leavePercentHeartbeats
286- let act := fun cand => do
287- if ←shouldAbort then
288- abortSpeculation
289- librarySearchLemma cfg tactic allowFailure cand
290- tryOnEach act candidates
291-
292213/--
293214Tries to solve the goal either by:
294215* calling `tactic true`
295216* or applying a library lemma then calling `tactic false` on the resulting goals.
296217
218+ Runs all candidates in parallel, iterates through results in order.
219+ Cancels remaining tasks and returns immediately if a complete solution is found.
220+
297221Typically here `tactic` is `solveByElim`,
298222with the `Bool` flag indicating whether it may retry with `exfalso`.
299223
@@ -311,11 +235,36 @@ this is not currently tracked.)
311235def librarySearch (goal : MVarId)
312236 (tactic : Bool → List MVarId → MetaM (List MVarId) :=
313237 fun initial g => solveByElim [] (maxDepth := 6 ) (exfalso := initial) g)
314- (allowFailure : MVarId → MetaM Bool := fun _ => pure true )
315- (leavePercentHeartbeats : Nat := 10 ) :
238+ (allowFailure : MVarId → MetaM Bool := fun _ => pure true ) :
316239 MetaM (Option (Array (List MVarId × MetavarContext))) := do
317- (tactic true [goal] *> pure none) <|>
318- librarySearch' goal (tactic false ) allowFailure leavePercentHeartbeats
240+ let tryDirect : MetaM (Option (Array (List MVarId × MetavarContext))) := do
241+ let _ ← tactic true [goal]
242+ pure none
243+ tryDirect <|> do
244+ withTraceNode `Tactic.librarySearch (return m!"{librarySearchEmoji ·} {← goal.getType}" ) do
245+ profileitM Exception "librarySearch" (← getOptions) do
246+ let candidates ← librarySearchSymm libSearchFindDecls goal
247+ let cfg : ApplyConfig := { allowSynthFailures := true }
248+ let jobs := candidates.toList.map fun cand => do
249+ let remaining ← librarySearchLemma cfg (tactic false ) allowFailure cand
250+ pure (remaining, ← getMCtx)
251+ let (cancel, iter) ← MetaM.parIterWithCancelChunked jobs (maxTasks := 128 )
252+ let mut partialSuccesses : Array (List MVarId × MetavarContext) := #[]
253+ for result in iter.allowNontermination do
254+ match result with
255+ | .ok (remaining, mctx) =>
256+ if remaining.isEmpty then
257+ -- Complete solution found - cancel remaining tasks and return
258+ cancel
259+ setMCtx mctx
260+ return none
261+ else
262+ -- Partial success - collect it
263+ partialSuccesses := partialSuccesses.push (remaining, mctx)
264+ | .error _ =>
265+ -- Task failed, continue to next
266+ continue
267+ return some partialSuccesses
319268
320269end LibrarySearch
321270
0 commit comments