feat: icombine#388
Conversation
Implement the iframe tactic and make it available in specialization patterns and cases patterns. Additional implement input / output handling to IPM synthesis roughly in the style of Hint Mode in Rocq. See the comment on `ParamKind` for a detailed description: The parameters of a class declared with `ipm_class` are categorized into the following categories: 1. in: This is the default for a parameter when not annotated in another way. 2. out: These are parameters marked with `outParam`. These parameters must be mvars when starting typeclass search. 3. semiOut: These are parameters marked with `semiOutParam`. The preceding parameter must be of type `InOut`. The value of the `InOut` parameter decides whether the `semiOut` parameter is treated as an input or an output. 4. uncheckedIn: These are parameters marked with `uncheckedInParam`. These behave like `in` parameters, but allow mvars to match terms (see below). 5. inout: Parameters of type `InOut`, must appear before semiOut parameters (see above). The following constraints apply to the parameters: (In the following, semiOut parameters are treated as inputs if the preceding `InOut` is `in` and as outputs if the `InOut` is `out`.) 1. semiOut parameters must have a preceding `InOut` parameter. 2. For each synthesis problem, all output parameters must be mvars. 3. When an input parameter is a mvar, it is not considered to match an instance which does not have an mvar at the top-level. This is to prevent accidentally instantiating mvars. Note that this only applies for mvars the top-level (matching the behavior of Hint Mode : ! in Rocq), since this is the simplest version to implement and catches most (all?) of the cases.
- Complete pass over the proofmode files to add the rocq_alias annotations - Add rocq_concept annotations for the tactics - Remove the proofmode section in PORTING.md, it is replaced by the status website
Currently using an instance combineSepAs_default for the simplest way to combine two propositions with separation conjunction
…ntuitionstically>, <absorb>, <pers> modalities
…and relevant instances for monotonicity
…e (iCombineCoreList)
… hypothesis for synthesis in CombineSepsAs_cons
iCombineCore works recursively on the list of hypotheses to be combined
…avoid typing problem
Some arguments can be inferred by the prover
…context by icombine
…CombineGivesCore is used Does not affect the behaviour correctness of the tactic but prettier
MackieLoeffel
left a comment
There was a problem hiding this comment.
Thanks for the PR! I had a brief look over it and added some comments.
| | true => intuitionistically_sep | ||
|
|
||
| theorem intuitionisticallyIf_sep_conj {p1 p2 : Bool} [BI PROP] {P Q : PROP} : | ||
| (□?p1 P ∗ □?p2 Q) ⊢ □?(p1 ∧ p2) (P ∗ Q) := by |
There was a problem hiding this comment.
I am surprised that you can use ∧, I was expecting && as the boolean version.
Also does this lemma correspond to a lemma in Rocq? If so, please add a rocq_alias annotation.
There was a problem hiding this comment.
It looks like p1 and p2 are forced into being p1 = true and p2 = true when ∧ is used as a connective. I have updated the lemma to use && instead; both formulations work with my implementation.
I'm not aware of a comparable lemma in the Rocq codebase, but I've added it into this file since the lemma hold generically. Otherwise I guess we can also place the lemma directly in Combine.lean instead.
| private def iCombineAsCore {u} {prop : Q(Type u)} {bi e} | ||
| (hyps : Hyps bi e) (goal : Q($prop)) (hs : List Ident) | ||
| (pat : iCasesPat) (recCall : Bool := false) : | ||
| ProofModeM Q($e ⊢ $goal) := do |
There was a problem hiding this comment.
Instead of writing this function as a recursive function, I recommend that you define a CombineState and then an function that combines the CombineState with one Ident. I think this should allow you to get rid of some of the duplication in this function. You can for example look at the revert tactic for how to do this.
There was a problem hiding this comment.
I have now restructured the code to handle the hypotheses iteratively with the mutable state instead of recursively, so there is no need for new idents at every iteration anymore.
In the original iCombineAsCore, there was pattern matching on the list of hypotheses hs, and for the case when hs was in the form h1 :: h2 :: htail, there was pattern matching on htail. This is no longer necessary with the current iterative approach, which means there is also no need for repeated pattern matching on matchBool p1 and matchBool p2.
There was a problem hiding this comment.
The elab definitions for icombine ... as ... and icombine ... gives ... now initialises the mutable state and handles the loop over the list of hypotheses, similar to how it is done in the iclear tactic.
| mvar.assign proof | ||
|
|
||
| ProofModeM.runTactic λ mvar { hyps, goal, .. } => do | ||
| let proof ← iCombineAsCore hyps goal hs.toList patAs |
There was a problem hiding this comment.
It is not ideal to do this in two separate calls to iCombineGivesCore and iCombineAsCore. Instead, it would be better to have a single iCombineGivesAsCore function that does both at the same time.
There was a problem hiding this comment.
How about defining the icombine ... as ... gives ... syntax as a macro?
macro "icombine" idents:(colGt ident)* "as" colGt patAs:icasesPat "gives" colGt patGives:icasesPat : tactic =>
`(tactic| (icombine $idents* gives $patGives; icombine $idents* as $patAs))So this appears to be the simplest way to define icombine ... as ... gives ... without being repetitive as the elab definitions for icombine ... as ... and icombine ... give ... now involve more than calling a helper function.
4a8bd2c to
adbd412
Compare
|
I believe this draft PR was accidentally closed because it was intended to merge into the branch of a PR that was merged. I cannot reopen this PR because the target branch has been deleted. |
|
Apologies for closing this! |
Description
Implements the
icombinetactic, available in three formats:icombine <hypotheses> as <pattern>icombine <hypotheses> gives <pattern>icombine <hypotheses> as <pattern> gives <pattern>Addresses #359.
The functions
iCombineAsCoreandiCombineGivesCoreutilise the type classesCombineSepAsandCombineSepGives, respectively. Since these two functions already handle the list of hypotheses recursively, there is no need to rely on type classes for recursion.The following type classes and type class instances are all located under the
ProofModedirectory.CombineSepAsClasses.leanCombineSepAsclasses.vCombineSepGivesClasses.leanCombineSepGivesclasses.vFour instances of the type class
CombineSepAsare namedcombine_sep_as_*insteadcombine_sep_gives_*in Rocq. Their Lean counterparts are namedcombineSepGives_*for consistency.combineSepAs_defaultInstances.leanmaybe_combine_sep_as_defaultclasses.vcombineSepAs_affinelyInstances.leanmaybe_combine_sep_as_affinelyclass_instances.vcombineSepAs_intuitionisticallyInstances.leanmaybe_combine_sep_as_intuitionisticallyclass_instances.vcombineSepAs_absorbinglyInstances.leanmaybe_combine_sep_as_absorbinglyclass_instances.vcombineSepAs_persistentlyInstances.leanmaybe_combine_sep_as_persistentlyclass_instances.vcombineSepAs_laterInstancesLater.leanmaybe_combine_sep_as_laterclass_instances_later.vcombineSepAs_laterNInstancesLater.leanmaybe_combine_sep_as_laterNclass_instances_later.vcombineSepAs_except0InstancesLater.leanmaybe_combine_sep_as_except_0class_instances_later.vcombineSepGives_affinelyInstances.leancombine_sep_as_affinelyclass_instances.vcombineSepGives_intuitionisticallyInstances.leancombine_sep_as_intuitionisticallyclass_instances.vcombineSepGives_absorbinglyInstances.leancombine_sep_as_absorbinglyclass_instances.vcombineSepGives_persistentlyInstances.leancombine_sep_as_persistentlyclass_instances.vcombineSepGives_laterInstancesLater.leanmaybe_combine_sep_gives_laterclass_instances_later.vcombineSepGives_laterNInstancesLater.leanmaybe_combine_sep_gives_laterNclass_instances_later.vcombineSepGives_except0InstancesLater.leanmaybe_combine_sep_gives_except_0class_instances_later.vThe tactic should exhibit the following behaviour, consistent with that in Rocq (correct me if I am wrong):
HP : Pin the intuitionistic context, thenicombine HP HP HP as HNewresults inHNew : P ∗ P ∗ Pbeing introduced.HP : PandHQ : Qin the intuitionistic context as well asHR : Rin the spatial context, thenicombine HR HQ HP HR as HNewproducesHnew : R ∗ Q ∗ P ∗ Rin the spatial context.P,QandRshould giveP ∗ Q ∗ Rinstead of(P ∗ Q) ∗ R.Regarding the last point, it appears that this is handled automatically by the type class instance for recursion in Rocq. Since recursion is handled by
iCombineAsCorein Lean instead, we currently have the type class instancecombineSepAs_assocfor this purpose.Checklist
PORTING.mdas appropriateauthorssection of any appropriate files