feat: OFE step-indexing parametrisation, port algebra/stepindex_finite.v - #550
feat: OFE step-indexing parametrisation, port algebra/stepindex_finite.v#550alvinylt wants to merge 34 commits into
algebra/stepindex_finite.v#550Conversation
… for `Nat` in `StepIndexFinite.lean`
|
At the moment, only the definitions within
The proofs are not yet updated, so the code on the branch does not compile. @Kaptch Could you check if these changes are in the direction that we want before we proceed with updating the rest of the code? |
|
Thanks! Looks nice by me!
Yeah, I also had the same problem before, I'm not sure if there's a good way to avoid explicit SI in the current setup. Probably, it feature we could experiment with some attribute/flag, but for now explicit parameter should be fine. |
…stances not yet complete
Replace all proofs in section `Fixpoint`, all requires rewrite
…and `Contractive.succ`
Parametrisation of `CMRA` to be done in a future PR
|
Up to commit f59dcf0 (see diff), So here's the plan: until the latest commit (see diff), definitions in relation to |
|
Sounds good! I think finishing OFE parametrization in this PR (including fixpoints, but limited to OFE.lean file) is a good goal, because CMRA parametrization will also require changing BI (and probably some parts of proof mode), so it would be nice to do it separately. Just ping me, when you think it is ready, and i can review and merge it. |
…nt with `SI = Nat`
|
Sorry, I might have missed it in the discussion, but what do you think about following what Rocq does and use the following (proposed by Alvin above)? edited in response to Markus' comment below This indeed assumes that there is only |
|
Before I reply, is this a typo? I assumed Alvin was bringing this up just an an analogy to how this is done in Rocq, not a suggestion for doing it this way in Lean. What you suggested here is actually an extremely invasive change: it would mean going from an unbundled typeclass hierarchy to a bundled hierarchy, and if you use typeclass inference for that you can only have one OFE in scope at once. I assume you meant something different but I'm not sure what. |
|
You are of course right, the version from my previous message did not make sense. I've edited it to the version I actually had in mind (hopefully at least). |
|
Positing that it is actually easy to manage these scopes (I'm not sure I actually believe this) there are other challenges. For one, projecting out of the Here is an example of the kind of mess you can get yourself into with this approach: live.lean-lang.org. Maybe you can find a fix for this specific example but I'm more partial to staying in the happy path of Lean's typeclass synthesis algorithm if at all possible. |
|
I was able to fix all issues in your example with type annotations, see here. see here. I have not worked enough with Lean to know exactly what the pitfalls of dependent casts are. I guess we could try the (fixed) approach from my previous message in a branch and see what kind of problems appear? |
|
Off the top of my head I'll also note the following:
Zooming back out: the question is whether this is worth complicating our core theory like this just to avoid having extra notation. To me the answer to this still seems to be an obvious no!! But if you guys think this is worth it, I guess we might as well try... In fact, why don't we have a general notation for the general case, and then scoped notation for each instance that makes it look like the existing code? The general library code will need to use the slightly more verbose notation but clients with a fixed index type would not. |
|
About your points:
This point is very vague to me. Do you have concrete pointers that describe the limitations of dependent cases in Lean? (I am not even fully sure what you mean with dependent cases.) I think this point would also be best demonstrated by trying the bundled version of SIdx and seeing what problems arise. I think this will be interesting in any case.
I don't think this is true. I also want to be clear that at this point I don't know what the better approach is. I think this encoding of stepindices is a quite fundamental decision and we should make this decision carefully. This is why I think we should try out both approaches such that we can get some actual data on what the advantages and disadvantages of each approach are such that we can make an informed decision and don't need to speculate. @alvinylt Would it be possible to create a new branch based on this sketch of the approach? (Note the use of |
|
There is actually another version that comes to mind (based on the discussion above): We can use the non-bundled version, but make the stepindex type an |
Do you mean the following? class SIdx (I : outParam <| Type u) extends LT I, LE I, Zero I where
succ : I → I
lt_trans : ∀ {n m p : I}, n < m → m < p → n < p
... -- other fields here
class OFE {SI : Type _} [SIdx SI] (α : Type _) where
Dist : SI → α → α → Prop
dist_eqv : Equivalence (Dist n)
eq_dist : x = y ↔ ∀ n, Dist n x y
dist_lt : Dist n x y → m < n → Dist m x y
...
open OFE
scoped notation:40 x " ≡{" n "}≡ " y:41 => OFE.Dist n x y
namespace OFE
variable [instSI : SIdx SI]
theorem Dist.of_eq [OFE α] {x y : α} : x = y → x ≡{n}≡ y := (· ▸ .rfl)In this case, Lean gives an error about theorem Dist.of_eq [OFE α] {n : SI} {x y : α} : x = y → x ≡{n}≡ y := (· ▸ .rfl)Not that this solution is difficult, but the error message that the "type class instance problem is stuck with |
|
Does making |
Yes, I have managed to have
Here is another branch: see diff. The proofs in relation to |
You are right about this, my mistake. The universe bump in SIdx does not translate to OFE.
I would like to see this--you're probably better at dependent-type-fu than I am: -- What automation breaks?
open NatIndices in
example {m n : instNatSIdx.I} (h' : m ≤ n) (h : m ≠ n) : m < n := by
-- omega -- fails
-- exact? -- fails
-- grind -- fails
unfold instNatSIdx at m
unfold instNatSIdx at n
-- omega -- fails
-- exact? -- fails
-- grind -- fails
have H : instNatSIdx.I = Nat := by exact optParam_eq SIdx.I m
-- rw [H] in m -- Tactic `rewrite` failed: motive is not type correct ...
cases h'
· grind
· simp only [Nat.succ_eq_add_one, gt_iff_lt]
/-
T : Type ?u.2
U : Type ?u.4
m : SIdx.I
H : SIdx.I = Nat
m✝ : Nat
a✝ : Nat.le m m✝
h : m ≠ m✝.succ
⊢ m < m✝ + 1
-- There is a new m in the context, because of the dependent cases, but at least it's a Nat now?
-/
-- Maybe cases on m too?
cases m -- Well, at least everything is a Nat now
· -- apply? -- Doesn't work??
-- Oh, is SIdx.I still present in the invisible LT instance?
-- This should be defeq to the instance for Nat but of course
-- Maybe I need to transport the instance as well?
sorry
· sorry
-- Of course, supplying the answer directly works, even though exact? can't find it.
open NatIndices in
example {m n : SIdx.I} (h' : m ≤ n) (h : m ≠ n) : m < n := Nat.lt_of_le_of_ne h' h
This is more or less where the PR started. Anyways, I feel like I'm missing something, because intentionally breaking the assumptions of Lean's typeclass system just to solve a metaprogramming problem seems like a total self-own for no reason. I'm probably just overfit to this because a poor hierarchy is the reason I stopped using Iris-Rocq, and I was hoping the hierarchy in Iris-Lean could be as stable as possible. I'm will prepare a new PR with my proposal so I understand your guy's problem with it better. |
Well, there is a crucial difference: This PR in its current form has a 1000-line diff since it needs to add an explicit parameter to all uses of Thanks for preparing the different versions @alvinylt ! It seems like the
To be clear, I don't have any emotional attachment to any of these versions. I just want to discuss the different possibilities to make sure that we make an informed decision about this. |
|
Just to provide more data, I've ported my thing to use this PR instead of using a home-brewed version of (C)OFEs parameterized by ordinals, and it worked well. It doesn't use concrete instances of SI though, just an arbitrary SI parameter. So purely from api completeness perspective it works nice! Just to discuss possibilities: is there a way to produce an error/warning if there are two instances of SI in the context? I'm still not 100% sure what would be the problem, because the way I thought about it is: eventually we will have iProp/iPropTransfinite (or iProp (SI : Type _)), they bring different instances of SI into context and have different reasoning rules, but ultimately, the end-user never imports SI themself (unless they want to define yet another version of iProp). |
iProp/iPropTransfinite bring different instances in the context, but if they are never used in the same context, we still only ever have one instance in each context. |
Yes, sorry, I probably phrased in ambiguously. My point was that if we design it in a way that bringing SI instance can happen only by deliberate choice, then the current PR should be fine. Morally, right now SI should be fixed when importing CMRA (so probably SI instances and the interface should be split into different modules). Eventually, as more modules get parameterized, the pinning is going to happen when importing iProp/sProp.
I was thinking about one potential application, but haven't attempted it yet. For iPropTransfinite (over ordinal \gamma) one can define a family of modalities j_\alpha (for \alpha < \gamma) with j_\alpha(P)(n)(w) = n < \alpha \and P(n)(w). If cf(\alpha) < cf(\gamma) (e.g., \alpha = \omega, \gamma = \omega_1), then one can restore some missing logical rules in the transfinite setting, when working under the modality. But given that it's just a rough idea, and we still have a lot to do before it's even expressible, it's probably not an issue for now. |
|
From the discussion with @markusdemedeiros, @Kaptch, and @alvinylt (among other), the next steps of this PR would be to switch to the outParam version and see if we can get a linter that warns the user if there is ever more than one instance of the step index typeclass in scope. It seem like Mathlib has an overlapping instance linter, which sounds like the linter we want: leanprover-community/mathlib4#38126 , implementation here |
|
I might misunderstand but the instances in the outParam version are not overlapping though, right? But we could also probably adapt that code to look for our specific case. Not mentioned here I will be also exploring if my other PR if a term elab can be used to avoid all outParams and optParams and autoParams while also not introducing any new notation. |
I am not fully sure what counts as an overlapping instance in Lean. In any case, this linter might be a good starting point as you say.
Indeed, I've added a comment about this to the other PR. |
|
I have an alternative proposal which I'm still working on a demo for, but the short version is to remove the outparam from SI and just use a combination of notation overloading and |
|
Here's the proposal. (analysis written by claude) I spent some time building this out to see what the Branch: Numbers
The downstream half of the diff fits on one screen. Line-length discipline is comparable to master: The proposal
class OFE {SI : Type _} [SIdx SI] (α : Type _) whereThe polymorphic core spells attribute [default_instance] natSIdx
scoped notation:40 x " ≡{" n "}≡ " y:41 => OFE.Dist (SI := Nat) n x y
@[inherit_doc] infixr:25 " -n> " => OFE.Hom
theorem OFE.eq_dist [OFE α] {x y : α} : x = y ↔ ∀ n : Nat, x ≡{n}≡ y := OFE.eq_dist'The position is load-bearing: the file itself elaborates without these, using Why drop
|
|
@digama0 Did you want to make a PR out of this so there's somewhere to comment on it, or are you holding off for some reason? |
|
Thanks for trying this out. But it seems like the https://github.com/leanprover-community/iris-lean/tree/sidx-clean branch does not solve the problem that writing generic code requires a lot of adaptation, as the description says itself. Also I don't think hard coding Nat in the notations is a good idea. We want to use these notations for generic step indices, not just for Nat. I do not understand the point about leaf instances. They seem to work fine with |
|
@MackieLoeffel @Kaptch How much code outside of Iris-Lean would you expect to be generic in terms of the type of step indices? I didn't think about |
|
The other thing which would be nice (in theory) would be if a scoped default instance could refer to section variables. Together, these two features would solve all of our problems, because we could just open a |
Could you please elaborate? I'm not sure I understood correctly. E.g., the stuff that I work on is generic in SI. |
I was not sure if what you were working on required the core theory to be generic in terms of SI so you could fix it to something (omega or whatnot) or if your work was also generic. This answers my question, thanks |
I'm just providing it as a point of reference and a possible design. I trust you to make good use of it; I do not intend to force my opinion on this matter. |
Description
Ports
algebra/stepindex_finite.v, which involves an instance ofSIdxwith natural numbers (Nat), and generalises definitions inAlgebra/OFE.lean. Everything dependent onAlgebra/OFE.leanshall be updated accordingly.Addresses #29 and #230 in part.
Checklist
authorssection of any appropriate files