Zulip Chat Archive
Stream: mathlib4
Topic: hint tactic priorities
Gareth Ma (Nov 22 2023 at 08:48):
Hi! I saw that the hint
tactic got merged recently, that's very exciting. I was checking this example out:
example {P Q R: Prop} (x : P ∧ Q ∧ R ∧ R) : Q ∧ P ∧ R := by hint /- Try these: • simp_all only [and_self] -/
example {P Q R: Prop} (x : P ∧ Q ∧ R ∧ R) : Q ∧ P ∧ R := by tauto
Should there be some kind of priority system so that hint
tries the light-weight tactics such as tauto
first before the heavy ones e.g. simp
and linarith
? In the code it seems the hints are tried in arbitrary order:
def hint (stx : Syntax) : TacticM Unit := do
let tacs := Nondet.ofList (← getHints)
let results := tacs.filterMapM fun t : TSyntax `tactic => do
if let some msgs ← observing? (withMessageLog (withoutInfoTrees (evalTactic t))) then
return some (← getGoals, ← suggestion t msgs)
else
return none
Gareth Ma (Nov 22 2023 at 08:49):
This will also go nicely with parallelising the tactic
Ruben Van de Velde (Nov 22 2023 at 09:23):
The idea is to stop looking as soon as one of the parallel attempts succeeds, so I don't think this would be easy
Gareth Ma (Nov 22 2023 at 10:22):
What do you mean? You should be able to parallelise the tactics in order too
Gareth Ma (Nov 22 2023 at 10:23):
Also regarding the tauto
example I suggested at the start, it seems the problem is simply that tauto
is not registered:
Screenshot-2023-11-22-at-10.23.08.png
Trebor Huang (Nov 22 2023 at 10:36):
Isn't "parallelise in order" a contradiction in terms?
Gareth Ma (Nov 22 2023 at 10:37):
Uhh I am not a computer science expert, but I mean to assign those jobs ("test this tactic") in order to multiple processes (parallelise)
Gareth Ma (Nov 22 2023 at 10:38):
Like how multiprocessing.pool.Pool.imap does it, where it returns the mapped results in order. Maybe I'm being stupid here
Ruben Van de Velde (Nov 22 2023 at 10:40):
The point is that you try tactics A, B, C, ... at the same time, and the result you get is the first one that finishes
Mauricio Collares (Nov 22 2023 at 11:03):
hint
is supposed to stop after the first result is returned, the PR just hasn't been merged yet
Mauricio Collares (Nov 22 2023 at 11:05):
But a configuration option that tries all choices and picks the simplest one, which I guess is what you're asking for, sounds reasonable
Scott Morrison (Nov 22 2023 at 11:05):
Yes, if someone wants to add a switch so that it returns all results, rather than stopping after finding one that closes the goal, that would be fine.
Scott Morrison (Nov 22 2023 at 11:06):
But for the most part, if one closes the goal I'm not sure I really care about the details. :-)
Scott Morrison (Nov 22 2023 at 11:06):
(Note that with Lean's Task
model, there is no way to assign priorities.)
Gareth Ma (Nov 22 2023 at 11:06):
I was thinking more like "try tauto
then <insert other lightweight tactics> then simp
and linarith
last" rather than "try them in arbitrary order" :tear:
Scott Morrison (Nov 22 2023 at 11:08):
The point of parallelisation is that they are all tried at once.
Scott Morrison (Nov 22 2023 at 11:08):
The price of that is that if you don't have enough cores, you have lost the ability to choose the order.
Gareth Ma (Nov 22 2023 at 11:09):
Ahhhhhhh right, my bad
Jireh Loreaux (Nov 22 2023 at 18:49):
Scott Morrison speaking of not having enough cores, can we have an option to limit the number of cores hint
will use?
Kyle Miller (Nov 22 2023 at 19:26):
(@Gareth Ma You might have been thinking of concurrency vs parallelism. Without parallelism, it could have been that the tactics get run concurrently using a time-sharing scheme, and scheduling fast-completing tactics, ones that can complete within the time quantum, could make sense.)
Thomas Murrills (Nov 22 2023 at 21:29):
Hmm, aren’t there usually way more tactics to run than cores? Could we (down the road) set up a priority-ordered queue of tactics and one worker per core, each of which pops a tactic off the queue? (Is that kind of thing even possible in Lean?)
Scott Morrison (Nov 22 2023 at 23:52):
Currently there are 7 appearances of register_hint
in Mathlib, so on the same order as number of cores.
Scott Morrison (Nov 22 2023 at 23:52):
It would definitely be possible to write a queue that only generates a bounded number of Task
s.
Scott Morrison (Nov 22 2023 at 23:54):
I think all the work would be in modifying/generalizing MLList.ofTaskList
in #8435.
Scott Morrison (Nov 22 2023 at 23:57):
This would be great fun to write, and in fact I long ago implemented an MLList.parallelMap
for exactly this: #3978
Scott Morrison (Nov 22 2023 at 23:57):
(I never marked it for review, so it just rotted.)
Scott Morrison (Nov 22 2023 at 23:58):
(Actually, the MonadTask
design from #3978 is lovely, if I do say so myself, and ideally could be patched into #8435. I had completely forgotten about it.)
Scott Morrison (Nov 22 2023 at 23:59):
I abandoned the MLList.parallelMap
implementation because the performance overhead for lots of quick tasks was punitive. However that's much less of an issue for hint
, where we are more concerned about some slow running tasks, and the total number of tasks is so low that the overhead is irrelevant.
Scott Morrison (Nov 23 2023 at 00:00):
Nevertheless, I think limiting the number of cores that hint
will use is not actually that important. :-) Implementing it would be high fun, but limited practical impact.
Joachim Breitner (Nov 23 2023 at 14:04):
Maybe this is taking this thread too much on a tangent, but how good is the Lean RTS with extensive use of concurrency? On Haskell, I’d not hesitate to spawn many small tasks (“green threads”) and leave the rest to the RTS. But you say that in lean I shouldn't quite do that?
Scott Morrison (Nov 23 2023 at 21:11):
I didn't intend to say that. My parallel map approach for MLList was slow, but my (untested) suspicion was that the overhead came more from managing the look-ahead pool than spawning and waiting on tasks.
Last updated: Dec 20 2023 at 11:08 UTC