Zulip Chat Archive
Stream: iris-lean
Topic: Rationals needed for the Frac CMRA?
Shreyas Srinivas (Jun 22 2025 at 21:29):
Based on my reading of the Frac CMRA, we need rational numbers to define it. Currently Rationals are defined in batteries. Should we include batteries as a dependency?
Shreyas Srinivas (Jun 22 2025 at 21:41):
CC : @Mario Carneiro and @Markus de Medeiros
Shreyas Srinivas (Jun 22 2025 at 21:42):
When we used iris in my semantics course we used it with stdpp and batteries serves a similar role in lean (but has some content differences), so hopefully it isn't a controversial addition
Markus de Medeiros (Jun 22 2025 at 21:45):
To port this file you don't actually need the rationals! This is a case where we can generalize the existing Iris implementation to require a typeclass with the properties we want, rather than the Rational type itself (namely, a type of positive numbers). I'll push my implementation of Frac in an hour or so.
Markus de Medeiros (Jun 22 2025 at 21:46):
Adding batteries is a bit of an orthogonal issue to this (though I'm definitely not be opposed to adding it when the need arises!)
Shreyas Srinivas (Jun 22 2025 at 21:46):
Ah okay. I actually want to get a hang of CMRAs (I only learnt the simplified resource algebra story in my course)
Mario Carneiro (Jun 22 2025 at 21:47):
presumably a minimalistic type which serves the role here would actually be dyadic rationals
Shreyas Srinivas (Jun 22 2025 at 21:47):
So I think I can try the Frac CMRA or some variant, just as a practice. Feel free to close the PR if you prefer it
Markus de Medeiros (Jun 22 2025 at 21:47):
It would be better to use a typeclass. I am sure that eventually I will want to instantiate this with the positive reals.
Shreyas Srinivas (Jun 22 2025 at 23:40):
what exactly is a Leibniz structure?
Shreyas Srinivas (Jun 22 2025 at 23:40):
conceptually?
Mario Carneiro (Jun 22 2025 at 23:40):
Leibniz equality is Rocq-speak for Eq
Mario Carneiro (Jun 22 2025 at 23:40):
I'm quite dubious about using the terminology in iris-lean since no one uses it here
Mario Carneiro (Jun 22 2025 at 23:41):
A Leibniz OFE is one where the Equiv relation is Eq
Shreyas Srinivas (Jun 22 2025 at 23:45):
some possibly mixed up questions : Equivalence is in Init. Why isn't Equivalence Eq defined in core?
Shreyas Srinivas (Jun 22 2025 at 23:45):
and why do we use this extra indirection in Iris at the moment?
Mario Carneiro (Jun 22 2025 at 23:45):
what indirection?
Shreyas Srinivas (Jun 22 2025 at 23:46):
structure LeibnizO (T : Type _) where
car : T
-- Move?
theorem Eq_Equivalence {T : Type _} : Equivalence (@Eq T) :=
⟨congrFun rfl, (Eq.symm ·), (· ▸ ·)⟩
instance : COFE (LeibnizO T) := COFE.ofDiscrete _ Eq_Equivalence
Mario Carneiro (Jun 22 2025 at 23:46):
LeibnizO is a type constructor which builds a COFE on an arbitrary type, which is also a leibniz OFE
Mario Carneiro (Jun 22 2025 at 23:47):
You don't want that structure on every type, it's like the discrete topology
Markus de Medeiros (Jun 22 2025 at 23:51):
Are there any rules about when we should use indirection? I brought up the fact that we put the discrete function CMRA on every function type but I don't think that point was ever resolved.
Mario Carneiro (Jun 22 2025 at 23:52):
The key question is whether there is a likelihood of conflict between different structures
Mario Carneiro (Jun 22 2025 at 23:53):
For function types, it's fine as long as you can argue that there will never be a different structure on function types (only wrapped function types)
Mario Carneiro (Jun 22 2025 at 23:54):
for LeibnizO this is clearly impossible to argue because it would be a blanket instance covering every type
Markus de Medeiros (Jun 22 2025 at 23:55):
Mario Carneiro said:
only wrapped function types
Ah--good point. I'm not sure I've ever seen a function type in Iris that wasn't wrapped into a discrete function with -d>.
Markus de Medeiros (Jun 22 2025 at 23:55):
So it might as well be the default
Mario Carneiro (Jun 22 2025 at 23:55):
I believe there is no competing instance for function types anyway; -n> isn't a function type, it is a subtype of a function type
Shreyas Srinivas (Jun 23 2025 at 00:00):
Also @Markus : there seems to be no clean way to map arbitrary typeclass instances from Fractional to Frac
Shreyas Srinivas (Jun 23 2025 at 00:00):
Referring to this part:
abbrev Frac (T : Type _) [Fractional T] := LeibnizO T
-- TODO: How do I get rid of these instances?
-- I definitely do not want to use an abbrev for Frac (there are many different OFE's for numerical types)
-- so do we need to keep around all of these coercions?
instance [Fractional T] : Coe (Frac T) T := ⟨(·.1)⟩
instance [Fractional T] : Coe T (Frac T) := ⟨(⟨·⟩)⟩
@[simp] instance [Fractional T] : COFE (Frac T) := by unfold Frac; infer_instance
@[simp] instance [Fractional T] : One (Frac T) := ⟨⟨One.one⟩⟩
@[simp] instance [Fractional T] : LE (Frac T) := ⟨fun x y => x.1 ≤ y.1⟩
@[simp] instance [Fractional T] : LT (Frac T) := ⟨fun x y => x.1 < y.1⟩
@[simp] instance [Fractional T] : Add (Frac T) := ⟨fun x y => x.1 + y.1⟩
Shreyas Srinivas (Jun 23 2025 at 00:36):
I made a draft PR to your PR at leanprover-community/iris-lean#57
Shreyas Srinivas (Jun 23 2025 at 00:36):
I want to simplify this further tomorrow morning
Shreyas Srinivas (Jun 23 2025 at 00:37):
For example, I think the positivity condition is pointless
Shreyas Srinivas (Jun 23 2025 at 00:38):
Since we are focussed on positive numbers only, we could add define the four conditions of Fractional in simpler terms. However changes here will break proofs, so I will fix this after some sleep
Markus de Medeiros (Jun 23 2025 at 00:46):
Nice! Yeah feel free to play around with it, I didn't simplify the Fractional typeclass at all :)
Markus de Medeiros (Jun 23 2025 at 00:47):
I do think positivity will be hard to remove (the type in Rocq is actually the positive rationals in case you missed it!)
Shreyas Srinivas (Jun 23 2025 at 00:54):
To clarify I mean we can take positivity simpler
Shreyas Srinivas (Jun 23 2025 at 16:30):
Trying to simplify positivity has had the side effect of creating a lot of useful API lemmas for the Fractional class
Markus de Medeiros (Jun 23 2025 at 16:50):
Your definition looks nice! Is it minimal?
Shreyas Srinivas (Jun 23 2025 at 16:52):
I don't have a proof of that. I am trying to codify rationals as totally ordered commutative monoids (ignoring multiplication).
Shreyas Srinivas (Jun 23 2025 at 16:52):
I am basically remembering Apostol's definition of ordered fields in his real analysis book and simply removing the multiplication axioms. I don't have a copy so I have to go with my memory
Markus de Medeiros (Jun 23 2025 at 16:54):
Okay! We don't need a proof or anything, just want to be reasonably confident that this typeclass is as minimal as possible.
Shreyas Srinivas (Jun 23 2025 at 16:54):
I have marked a couple of the remaining fields for removal after I prove them as theorems
Shreyas Srinivas (Jun 23 2025 at 16:55):
Oh and I miss quite a few tactics I take for granted in mathlib like contrapose, apply .. at, nth_rw, and simp_rw
Markus de Medeiros (Jun 23 2025 at 16:57):
I pushed iris-lean#59, we'll want Fractional to be the smallest typeclass such that everything in DFractional can also be proved.
Markus de Medeiros (Jun 23 2025 at 16:58):
Uh also, I think you should not use Zero. This cannot be instantiated for types that are intrinsically positive like the positive reals or positive rationals.
Shreyas Srinivas (Jun 23 2025 at 16:59):
Okay, but then the class that comes out of it will not be a monoid
Markus de Medeiros (Jun 23 2025 at 16:59):
That's fine
Shreyas Srinivas (Jun 23 2025 at 16:59):
I also miss all those precious code actions that split cases and create proof holes
Shreyas Srinivas (Jun 23 2025 at 17:06):
Everywhere you see me using the conv mode, I would have used nth_rw instead.
Shreyas Srinivas (Jun 23 2025 at 17:20):
Btw the Zero class only adds the notation for zero. For various intervals of Q I think the correct way to do this is by adding properties with the upper and lower bounds
Shreyas Srinivas (Jun 23 2025 at 17:21):
So I think the zero and id laws should remain
Shreyas Srinivas (Jun 23 2025 at 17:23):
And then this Fractional class should be extended with another that bounds the valid range of values. Kinda like subtypes
Shreyas Srinivas (Jun 23 2025 at 17:27):
Otherwise the order relations’ compatibility with addition will become complicated. Further, we would have to reinvent many of the API lemmas I have already proved
Mario Carneiro (Jun 23 2025 at 17:28):
Shreyas Srinivas said:
I also miss all those precious code actions that split cases and create proof holes
Those are in Batteries
Markus de Medeiros (Jun 23 2025 at 17:41):
Shreyas Srinivas said:
Btw the Zero class only adds the notation for zero. For various intervals of Q I think the correct way to do this is by adding properties with the upper and lower bounds
There is no zero in the positive rationals.
Shreyas Srinivas (Jun 23 2025 at 17:44):
Yeah but for positive rationals you can restrict the allowed values using a property
Markus de Medeiros (Jun 23 2025 at 17:44):
I understand that mechanizing a monoid is easy but that is not the structure we want. If the type includes zero elements we will need to change the CMRA to accommodate this, but since this is CMRA is used extensively throughout the derived parts of Iris I am hesitant to do that.
Shreyas Srinivas (Jun 23 2025 at 17:44):
I would call it “PositiveFractional” and impose a restriction that all values a strictly greater than 0
Markus de Medeiros (Jun 23 2025 at 17:45):
...PositiveFractional cannot extend zero then.
Shreyas Srinivas (Jun 23 2025 at 17:55):
0 won’t be a valid value if PositiveFractional
Shreyas Srinivas (Jun 23 2025 at 17:55):
Only fractional
Shreyas Srinivas (Jun 23 2025 at 17:55):
0 will be ruled out by the inability to prove the strict positivity field
Shreyas Srinivas (Jun 23 2025 at 17:56):
It’s basically like docs#Subtype
Markus de Medeiros (Jun 23 2025 at 17:57):
The stuff you've done is great, and it will be convenient to say that the positive restrictions of the classes you laid out will be PositiveFractional! But PositiveFractional itself should be a typeclass.
Think of how you would instantiate PositiveFractional for the type of intrinsically positive fractions represented as pairs structure PFrac : {num : Nat+; den: Nat+; wf : gcd num den = 1}. Under your strategy, you would have to add a zero onto this type
inductive positiveFracPlusZero
| pos : PFrac
| zero
then lift all of the PFrac operations to positiveFracPlusZero, all to use {p : positiveFracPlusZero | 0 < p} as the type of your indices. This is a mess.
Shreyas Srinivas (Jun 23 2025 at 17:58):
Once I’m back I’ll flesh it out in code.
Shreyas Srinivas (Jun 23 2025 at 17:58):
Maybe it will be easier to communicate it that way
Shreyas Srinivas (Jun 23 2025 at 18:10):
In a way you are right. But we can add default tactic arguments like by omega to make most of the api seamless
Shreyas Srinivas (Jun 23 2025 at 18:11):
And then we just establish the API with general bound parameters. EDIT: this is how docs#Vector works on top of docs#Array
suhr (Jun 23 2025 at 18:11):
By the way, why do we need rationals for program verification?
suhr (Jun 23 2025 at 18:12):
(sorry if the question is silly, I do not have that much experience with Iris)
Shreyas Srinivas (Jun 23 2025 at 18:15):
Yeah. This cmra expresses fractional ownership later
Mario Carneiro (Jun 23 2025 at 18:21):
So fractions come up in "fractional ownership" which are a way of dealing with avoiding races between readers and writers. Let's say we want to ensure the property:
- A writer can only write if there are no concurrent readers or writers
- Multiple readers can read concurrently
To accomplish this, we can have a separating proposition which represents full ownership of the value, and if you have this then you are the unique owner and can safely write. If you want to share read access to it, you can "split" the ownership into two pieces, , and now distribute these pieces to separate threads of execution. If you have only half of a permission, then you do not know that there are no concurrent readers so you are entitled only to read the value, not write it. The reason for having arbitrary rationals is so that these tokens can be arbitrarily split and passed around, and you can keep reading it as long as the fraction remains positive. When all is done you can recombine the pieces into one full permission and go back to writing.
Mario Carneiro (Jun 23 2025 at 18:25):
Here is what I would expect from an axiomatization of the type of positive fractions here, with the model in mind:
- is a permission
- is a functional ternary relation on permissions (write when this exists)
- is a function such that
I think that's it?
Shreyas Srinivas (Jun 23 2025 at 18:27):
I think Markus wants something more general. He mentioned wanting to use Real number intervals later
Markus de Medeiros (Jun 23 2025 at 18:27):
Adding onto Mario's explanation, the problem with a zero fraction is that it _does not_ denote read permissions to a location, so it adds an edge case that needs to be handled by the validity predicate of the CMRA.
Shreyas Srinivas (Jun 23 2025 at 18:28):
But yeah I am still convinced that a dual api with default arguments and/or partial functions is the way to handle bounded fractions.
Shreyas Srinivas (Jun 23 2025 at 18:28):
Same as Array and Vector
Shreyas Srinivas (Jun 23 2025 at 18:28):
Otherwise we lose substantially simplicity of API
Mario Carneiro (Jun 23 2025 at 18:29):
note that all of the following satisfy my axioms:
- , = dyadic rationals
You can only concretely construct fractions in as literals though.
Markus de Medeiros (Jun 23 2025 at 18:30):
That's right. I'm not convinced that your axiomatization actually has everything needed to instantiate CMRA (you don't have a relationship between addition and 1, for example) and the division by 2 axiom is useless.
Mario Carneiro (Jun 23 2025 at 18:30):
To construct 3/4 you need an axiom saying that when exists, also exists and (this is the associativity axiom but more precise about what exists)
Mario Carneiro (Jun 23 2025 at 18:32):
The division by 2 axiom is certainly not useless, it's the only way you can actually make fractions
Markus de Medeiros (Jun 23 2025 at 18:32):
Useless for the CMRA instance, which is what were talking about.
Mario Carneiro (Jun 23 2025 at 18:32):
otherwise would also be a model of the axioms
suhr (Jun 23 2025 at 18:33):
You also need a ≠ a/2.
Mario Carneiro (Jun 23 2025 at 18:33):
why?
Markus de Medeiros (Jun 23 2025 at 18:33):
Mario Carneiro said:
otherwise would also be a model of the axioms
is fine!
Mario Carneiro (Jun 23 2025 at 18:34):
is fine?
Markus de Medeiros (Jun 23 2025 at 18:34):
Yes.
Markus de Medeiros (Jun 23 2025 at 18:35):
Oh-- actually {1} is not fine, sorry. You need addition.
Mario Carneiro (Jun 23 2025 at 18:35):
no you have addition, it's just an empty relation in my setting
Mario Carneiro (Jun 23 2025 at 18:36):
so you can talk about splitting but you can never actually do it
Markus de Medeiros (Jun 23 2025 at 18:36):
I suppose you could change Add to be a relation instead of a function, yes. Then {1} is fine.
Markus de Medeiros (Jun 23 2025 at 18:36):
Frac {1} is the same as Excl I believe.
Mario Carneiro (Jun 23 2025 at 18:37):
I use a relation because I expect that the CMRA wants to do this PCM style
Mario Carneiro (Jun 23 2025 at 18:37):
so we have this way of combining values which is just not always defined
Markus de Medeiros (Jun 23 2025 at 18:38):
The well-definition is already controlled by the validity predicate of the CMRA
Mario Carneiro (Jun 23 2025 at 18:38):
if we restrict to those sets which have 1 as an upper bound then we get the relation which is nice
Markus de Medeiros (Jun 23 2025 at 18:39):
I could believe that. The question then becomes if using a relation instead of a function is easier for clients.
Markus de Medeiros (Jun 23 2025 at 18:40):
Is there (rational/real/natural) addition defined as a relation somewhere? I only know of it defined as a function.
Mario Carneiro (Jun 23 2025 at 18:40):
You can define as (which works also when 1 is not an upper bound) and then means that you can write
suhr (Jun 23 2025 at 18:40):
Anyway, speaking of axioms, what stops defining + in a trivial way: 1 + 1 = 1, where 1 is only value of the type?
This should satisfy the axioms?
Mario Carneiro (Jun 23 2025 at 18:41):
and you want an axiom
Mario Carneiro (Jun 23 2025 at 18:41):
which will prevent your example @suhr
Markus de Medeiros (Jun 23 2025 at 18:41):
Concretely, this is not sound from a logical perspective. You can't exchange for because then you get two write permissions to the same place.
Mario Carneiro (Jun 23 2025 at 18:42):
right, but the question is whether this should be prevented in the axioms somehow so that you can actually prove a soundness theorem for generalized fractional permissions using this typeclass
Mario Carneiro (Jun 23 2025 at 18:45):
there is a bit of difference between the sets that have 1 as an upper bound (which prefer the partial addition version) and those that are unbounded (which can have addition as a function but need more side conditions saying things are less than 1)
Mario Carneiro (Jun 23 2025 at 18:45):
What is the type actually used in iris for this?
Markus de Medeiros (Jun 23 2025 at 18:46):
Just to bring the discussion back down to earth, Iris does the following:
- Use a function for fraction addition
- Internalize that the fraction values are positive
- Externalize that the fraction values are at most 1 (using the CMRA validity predicate)
Iris uses Qp, the type of positive rationals for this.
Mario Carneiro (Jun 23 2025 at 18:46):
is division used?
Markus de Medeiros (Jun 23 2025 at 18:47):
Not for the CMRA instance
Markus de Medeiros (Jun 23 2025 at 18:49):
The generalization I'm suggesting matches Iris in terms of externalizing/internalizing different features of Qp, but generalizes the Qp type itself. Other generalizations are possible, but may change the derived proofs in tricky ways.
Mario Carneiro (Jun 23 2025 at 18:49):
in that case how about this:
- exists
- exists
- ,
- define as , define as
Mario Carneiro (Jun 23 2025 at 18:52):
there is no explicit relationship between 1 and + but you would use in the validity predicate
Markus de Medeiros (Jun 23 2025 at 18:53):
Mario just for context you can look at the Fractional class in my PR to see a sufficient set of axioms. @Shreyas Srinivas it's worth a shot to try reducing my typeclass to Mario's axioms.
Markus de Medeiros (Jun 23 2025 at 18:53):
Mario Carneiro said:
there is no explicit relationship between 1 and + but you would use in the validity predicate
Right, I get it. I did use the field one_strict_max in my DFractional typeclass (which Fractional should also subsume) but I feel that may be able to be removed.
Mario Carneiro (Jun 23 2025 at 18:54):
You should be able to prove transitivity of and using associativity
Mario Carneiro (Jun 23 2025 at 18:54):
oh we do need to add
Mario Carneiro (Jun 23 2025 at 18:55):
le_refl and positive are the same thing if you have
Mario Carneiro (Jun 23 2025 at 18:56):
and so add_le_mono should be provable
Mario Carneiro (Jun 23 2025 at 19:07):
(Just to be clear, I'm approving of the general structure of @Markus de Medeiros 's PR, this should be a custom typeclass.)
Mario Carneiro (Jun 23 2025 at 19:07):
the details of the axioms aren't too important
Markus de Medeiros (Jun 23 2025 at 19:09):
Your axiom " exists" means that we should keep + as a function (as it is now) instead of a relation, right? This detail does matter for the downstream code I am working on.
Mario Carneiro (Jun 23 2025 at 19:10):
yes
Mario Carneiro (Jun 23 2025 at 19:11):
this does mean that we won't be able to support as a model; there is no way you can do addition as a function without saturating, which violates cancellativity
Mario Carneiro (Jun 23 2025 at 19:13):
it also means 1 + 1 = 1 which violates irreflexivity
Markus de Medeiros (Jun 23 2025 at 19:17):
Hm. What is in this context?
Mario Carneiro (Jun 23 2025 at 19:17):
dyadic rationals
Mario Carneiro (Jun 23 2025 at 19:18):
and also have the same behavior though
Markus de Medeiros (Jun 23 2025 at 19:19):
Ah right--the issue is the $$...\cap (0,1]$$ part.
Shreyas Srinivas (Jun 23 2025 at 21:51):
There seems to be a lot of messages here. What’s the conclusion?
Markus de Medeiros (Jun 23 2025 at 21:55):
- You should try and refine the type class on my initial PR (without a Zero instance), Mario's axioms are probably the refinement you want
- Your work (the classes with a Zero instance) can stay, the positive subtype of them can be used as a generic instance for the Fractional typeclass
Markus de Medeiros (Jun 23 2025 at 22:03):
- The Fractional typeclass you end up with should subsume both Fractional from the frac branch and DFractional from the DFrac branch.
Shreyas Srinivas (Jun 23 2025 at 22:26):
My work is a bit generic. It just happens to subsume Fractional. Since Fractional is meant to use a different axiom set, should I move my work to a separate file? Alternatively, I can understand point 2 to mean that you wish to have all the API lemmas and properties from the typeclass, but have them proved from these axioms.
Markus de Medeiros (Jun 23 2025 at 22:30):
Where you put your work or if you keep it is largely irrelevant, just give it a shot (if you still want to!) and let me know when you're done so I can review it and give more detailed feedback.
Shreyas Srinivas (Jun 23 2025 at 22:38):
Okay. I’ll do this tomorrow. It’s past midnight in my time zone.
Shreyas Srinivas (Jun 23 2025 at 22:42):
Fwiw, the APi lemmas I showed for this typeclass will also be needed to make Mario’s definitions usable downstream.
Shreyas Srinivas (Jun 23 2025 at 22:43):
We are basically foregoing all the order theory and algebra that was developed for mathlib. So we need to recover the basic properties that a mathlib user can take for granted.
Mario Carneiro (Jun 23 2025 at 23:38):
I think that's the wrong way to look at it. As suhr remarked, it's surprising that we need rational numbers to begin with, and the truth is that we don't really, we need an extremely basic structure of which rational numbers are the simplest to explain model. Generalizing to the minimum properties necessary actually makes it clearer what's actually going on, and reveals that this really has little to do with rational numbers or any of their algebraic properties.
I am reminded of the evolution of "the interval" in HoTT and cubical type theory. Once upon a time people did homotopy theory using the type , which captures a bunch of structure of topological spaces. But when going synthetic, people started to realize that they can get away with just a rational interval and they get something computable, and in modern cubical type theory it's an extremely basic type, like "thing that has a 0 and 1 and maybe ?" And keeping things to that minimal subset is exactly what makes it possible to have a decidable theory of equality, which is part of what makes cubical type theory possible.
Shreyas Srinivas (Jun 24 2025 at 00:14):
hmm.. In neural nets, researchers went from all sorts of non-linear functions like the sigmoid function to softmax for the threshold
Shreyas Srinivas (Jun 24 2025 at 00:15):
I see your point. But I just realised that my generalisation also captures the resource for counters I had in my course. Except their core is the constant function . EDIT : It also captures
Shreyas Srinivas (Jun 24 2025 at 00:17):
For now I will use your axioms in the Frac CMRA, but keep the PR for the stuff I wrote open
Mario Carneiro (Jun 24 2025 at 00:18):
Shreyas Srinivas said:
I see your point. But I just realised that my generalisation also captures the resource for counters I had in my course. Except their core is the constant function
I think that's a different use case, which uses a monoid
Shreyas Srinivas (Jun 24 2025 at 00:19):
It's a commutative monoid with a total order. EDIT : Both and
Shreyas Srinivas (Jun 24 2025 at 00:21):
Screenshot from 2025-06-24 02-21-15.png
Markus de Medeiros (Jun 24 2025 at 00:24):
Yes, commutative monoids can be a resource (you should do the numbers resources after this!) But these are different than Frac. It is essential that Frac have a maximum valid element which neither (Nat, +) nor (Nat, max) really do.
Shreyas Srinivas (Jun 24 2025 at 00:29):
Okay. In that case I will proceed as follows:
- I will move my current
Frac.leantoNumbers.lean. Maybe even rename the PR.
Shreyas Srinivas (Jun 24 2025 at 00:30):
- Separately start a new PR against your PR to add the axioms Mario suggested for Frac.lean
All this tomorrow
Shreyas Srinivas (Jun 25 2025 at 11:53):
Mild confusion. In Init.Prelude online, I see a typeclass One here
Shreyas Srinivas (Jun 25 2025 at 11:53):
But somehow I can't access this in iris-lean
Shreyas Srinivas (Jun 25 2025 at 11:54):
Did something change between toolchain updates?
Shreyas Srinivas (Jun 25 2025 at 11:55):
This is the same part of the same file but opened in my editor with Ctrl + Click and the One typeclass is missing
Screenshot from 2025-06-25 13-55-15.png
Oliver Soeser (Jun 25 2025 at 12:04):
That typeclass was only added two months ago, maybe the version of Lean you're using doesn't have it yet?
Shreyas Srinivas (Jun 25 2025 at 12:06):
Okay that's possible. I haven't merged master and I don't think Markus has either
Shreyas Srinivas (Jun 25 2025 at 12:07):
I remember this class being around for a while.
Oliver Soeser (Jun 25 2025 at 12:11):
That typeclass has certainly been around for a while, but I think it was scattered across different files
Shreyas Srinivas (Jun 25 2025 at 12:12):
Nah it isn't there even in v4.20.0
Oliver Soeser (Jun 25 2025 at 12:12):
This seems to be the commit that brought it into the Prelude: # Commit 196d899
Shreyas Srinivas (Jun 25 2025 at 12:14):
Then it is surprising that it wasn't in this month's release
Oliver Soeser (Jun 25 2025 at 12:21):
Are you sure you're running v4.20? One is in the Prelude for me: image.png
Shreyas Srinivas (Jun 25 2025 at 12:24):
Oh thanks. I was in the wrong branch
Oliver Soeser (Jun 25 2025 at 12:24):
No worries!
Shreyas Srinivas (Jun 25 2025 at 12:36):
We need totality of the order relation
Oliver Soeser (Jun 25 2025 at 12:41):
What requires that?
Shreyas Srinivas (Jun 25 2025 at 12:48):
You can't prove it from the axioms above
Shreyas Srinivas (Jun 25 2025 at 12:48):
But maybe I am thinking about this the wrong way.
Shreyas Srinivas (Jun 25 2025 at 12:48):
Maybe we don't need to prove it
Oliver Soeser (Jun 25 2025 at 13:04):
Mario Carneiro said:
in that case how about this:
- exists
- exists
- ,
- define as , define as
These axioms?
Shreyas Srinivas (Jun 25 2025 at 13:38):
leanprover-community/iris-lean#62
Kevin Buzzard (Jun 25 2025 at 13:44):
FWIW (with 1 defined arbitrarily and + defined componentwise) seems to satisfy the both the axioms quoted by Oliver and the ones in the PR, and isn't total.
Shreyas Srinivas (Jun 25 2025 at 14:01):
I am beginning to think the only thing that we really need to check is if for some
Shreyas Srinivas (Jun 25 2025 at 14:02):
If not, then and we have total ownership of some resource
Shreyas Srinivas (Jun 25 2025 at 14:06):
More concretely, total ordering is not necessary
Markus de Medeiros (Jun 25 2025 at 14:06):
That's an interesting thought
Oliver Soeser (Jun 25 2025 at 14:07):
That's my intuition too, totality seems like an unnecessary restriction
Markus de Medeiros (Jun 25 2025 at 14:09):
It would be cool if we could instantiate it with abstract fractional permissions like here (though I wouldn't read too much into their exact permissions structure itself)
Shreyas Srinivas (Jun 25 2025 at 14:09):
Lol. I was thinking of something just like that
Shreyas Srinivas (Jun 25 2025 at 14:10):
Basically you don't need any operation other than halving and recombining
Shreyas Srinivas (Jun 25 2025 at 14:10):
there is an implicit partial order in halving
Shreyas Srinivas (Jun 25 2025 at 14:11):
So we only combine things that are equal in this order
Shreyas Srinivas (Jun 25 2025 at 14:14):
what we really need is an abstract binary tree structure where leaf nodes at the same level can be combined into a leaf node at the parent level or split
Markus de Medeiros (Jun 25 2025 at 14:14):
DFrac is more like the abstract fractional permissions in that paper, and deals with the invalid combinations, I think? Would be interesting to see if generalizing to partial orders (with total comparisons to 1) could simplify these OFE's.
Markus de Medeiros (Jun 25 2025 at 14:16):
Shreyas Srinivas said:
what we really need is an abstract binary tree structure where leaf nodes at the same level can be combined into a leaf node at the parent level or split
The rationals are not a binary tree so this is not right.
Shreyas Srinivas (Jun 25 2025 at 14:17):
no they are not, but as Mario says, we just need dyadic rationals
Oliver Soeser (Jun 25 2025 at 14:17):
I don't see why we can only combine equals?
Shreyas Srinivas (Jun 25 2025 at 14:17):
It means we don't have to keep track of what we are adding
Shreyas Srinivas (Jun 25 2025 at 14:18):
two equal leaf child nodes yield a new leaf node at the parent level
suhr (Jun 25 2025 at 14:19):
The rationals are not a binary tree so this is not right.
Oliver Soeser (Jun 25 2025 at 14:19):
Would that still work in practice though? To my knowledge it's fairly common for unequal fractional permissions to be combined
Shreyas Srinivas (Jun 25 2025 at 14:20):
So let's take a step back and consider what the fractional ownership actually represents
Shreyas Srinivas (Jun 25 2025 at 14:21):
In terms of heaplang, we get to create two threads out of one, if we fork at a thread.
Shreyas Srinivas (Jun 25 2025 at 14:24):
we recombine ownership when we join two threads
suhr (Jun 25 2025 at 14:25):
One could also spawn N threads simultaneously and then somehow use the fact that threads are essentially the same?
Shreyas Srinivas (Jun 25 2025 at 14:25):
You can model that general scenario using dyadic rationals
Shreyas Srinivas (Jun 25 2025 at 14:26):
but the model that I think Mario has in mind is based on what we do in heaplang
suhr (Jun 25 2025 at 14:26):
You can, but the proof might become more complex.
Shreyas Srinivas (Jun 25 2025 at 14:26):
We can instantiate the class with rationals
Shreyas Srinivas (Jun 25 2025 at 14:26):
and define the combining operation in terms of addition
Shreyas Srinivas (Jun 25 2025 at 14:27):
We will have the issue you speak of in any case @suhr : The definition Mario proposed is rather general
Shreyas Srinivas (Jun 25 2025 at 14:28):
The creation of n threads is an atomic sequence of (n-1) forks
Markus de Medeiros (Jun 25 2025 at 14:28):
Yes. Halving of any kind is not necessary for the proof that Frac is a CMRA and therefore should not be part of the Fractional class.
Shreyas Srinivas (Jun 25 2025 at 14:30):
Anyway, I think I have most of it nailed. I only made two changes. I added an axiom that a < b -> a \neq b
Shreyas Srinivas (Jun 25 2025 at 14:30):
and defined a \leq b as a < b \or a = b
Shreyas Srinivas (Jun 25 2025 at 14:30):
This is much more convenient for proofs
Markus de Medeiros (Jun 27 2025 at 19:01):
Shreyas Srinivas said:
I am beginning to think the only thing that we really need to check is if for some
Just curious, did this not end up working out for some reason?
Shreyas Srinivas (Jun 27 2025 at 19:12):
Oh no it works. I didn’t imagine this PR was the right place to experiment since Mario and you already had a plan.
Shreyas Srinivas (Jun 27 2025 at 19:12):
In general I think frac should just be a rooted tree
Shreyas Srinivas (Jun 27 2025 at 19:13):
The arity need not be fixed
Shreyas Srinivas (Jun 27 2025 at 19:13):
Basically it would model thread ownership
Markus de Medeiros (Jun 27 2025 at 19:13):
Shreyas Srinivas said:
Oh no it works. I didn’t imagine this PR was the right place to experiment since Mario and you already had a plan.
Good to know!
Shreyas Srinivas (Jun 27 2025 at 19:18):
A thread can only return fractional ownership to its creator if it has the entirety of its piece. When a thread spawns with split ownership, then, correspondingly many child nodes are tacked on. When the child nodes return their piece they are deleted. Ownership is 1 only if the tree has a root node with no children.
Frac is a very special case of this where, we always maintain a version of the tree flattened upto the root node plus its children nodes :
meaning either of the following :
- only the root node produces more pieces of partial ownership (or)
- The only non root nodes are leaf nodes, which are children of the root. Instead of adding child nodes to a non root node, we simply replace that node with more leaf nodes.
In either case total ownership is represented by a tree with only the root node.
Shreyas Srinivas (Jun 27 2025 at 19:36):
The nice thing is one can effectively compute when ownership is complete without the imprecision of machine arithmetic or overhead of rational arithmetic.
Shreyas Srinivas (Jun 27 2025 at 19:37):
One can also precisely reason about when a thread can relinquish ownership of its fraction.
Mario Carneiro (Jun 27 2025 at 20:52):
Markus de Medeiros said:
Yes. Halving of any kind is not necessary for the proof that Frac is a CMRA and therefore should not be part of the
Fractionalclass.
While true, I think you will probably want a class that extends this which actually contains a halving or similar operation, since without halving you can't actually do anything interesting with the class that would motivate including this CMRA in your iProp. And you might want to reconsider calling this class Fractional as there is nothing fractional about it, PNat satisfies the definition
Mario Carneiro (Jun 27 2025 at 20:55):
Shreyas Srinivas said:
In general I think frac should just be a rooted tree
That doesn't sound associative
Mario Carneiro (Jun 27 2025 at 21:05):
Shreyas Srinivas said:
A thread can only return fractional ownership to its creator if it has the entirety of its piece. When a thread spawns with split ownership, then, correspondingly many child nodes are tacked on. When the child nodes return their piece they are deleted. Ownership is 1 only if the tree has a root node with no children.
Your model, where you only recombine elements at the same height, is more restrictive than the actual fractional permissions model over Q, which in particular lets you do the following:
- Initialize with
- Split into where
- Fork off thread A with permission
- Split into where
- Fork off thread C with permission
- Thread C passes its ownership of to thread A (say, through a mutex) and exits
- Thread A recombines permissions to where
- Thread A dies and returns its permissions to main thread
- Main thread recombines permissions to where
If you keep track of what is happening with the fractions, you will see that at least one of the splits/merges , , , has to involve adding two fractions that are not at the same height. Permitting splits and merges only in perfect halves only permits stack-like usage of read permissions and would ban the cross cut here where thread C passes its permission over to thread A.
Shreyas Srinivas (Jun 27 2025 at 21:49):
Okay but you can recover this by allowing child nodes to be transferred
Shreyas Srinivas (Jun 27 2025 at 21:50):
At that point that fractional piece (c) is shifted to a different subtree so the subtree rooted at (b) is not concerned about it
Mario Carneiro (Jun 27 2025 at 21:52):
my point is that you need associativity to hold, and it doesn't if you only allow combining equal pieces
Mario Carneiro (Jun 27 2025 at 21:52):
if we suppose that all the splits are equal, then , , and then and is an unequal merge
Mario Carneiro (Jun 27 2025 at 21:54):
that is, you need dyadic rationals, not just
Shreyas Srinivas (Jun 27 2025 at 21:56):
Okay so concretely we need an operation that works on combining arbitrary subtrees associatively.
Mario Carneiro (Jun 27 2025 at 21:56):
what exactly are the trees you are referring to?
Markus de Medeiros (Jun 27 2025 at 21:59):
Mario Carneiro said:
While true, I think you will probably want a class that extends this which actually contains a halving or similar operation,
Yeah I wouldn't be opposed to this by any stretch! This won't affect anything beneath a program logic though, so it's library code.
Mario Carneiro (Jun 27 2025 at 22:00):
well you can't type a fork operation without it
Markus de Medeiros (Jun 27 2025 at 22:00):
Good thing the language I care about doesn't have fork :p
Mario Carneiro (Jun 27 2025 at 22:00):
why would you care about fractional permissions if you can't make fractions?
Mario Carneiro (Jun 27 2025 at 22:01):
we already have Auth, right?
Markus de Medeiros (Jun 27 2025 at 22:02):
Yes. But it's downstream of some constructions like gmap_view which I do care about.
Markus de Medeiros (Jun 27 2025 at 22:04):
In gmap_view the authoritative part has a fractional permission, and is used in a variety of program logics. We could write a version of gmap_view which elides this but it's nice that I can get the one I want without duplicating the structure.
Markus de Medeiros (Jun 27 2025 at 22:06):
It might be possible to parameterize gmap_view even further (parameterize the auth part by an arbitrary CMRA or something?) but I'm not sure about that yet.
Markus de Medeiros (Jun 27 2025 at 22:10):
Anyways, I ended up refactoring Shreyvas' code to implement his idea about comparing to 1
section Fractional
class Fractional (α : Type _) extends Add α where
/-- Validity predicate on fractions. Generalizes the notion of `(· ≤ 1)` from rational fractions. -/
proper : α → Prop
add_comm : ∀ {a b : α}, a + b = b + a
add_assoc : ∀ {a b c : α}, a + (b + c) = (a + b) + c
add_left_cancel : ∀ {a b c : α}, a + b = a + c → b = c
/-- There does not exist a zero fraction. -/
add_ne : ∀{a b : α}, a ≠ b + a
proper_add_mono_left : ∀ {a b : α}, proper (a + b) → proper a
/-- A type of fractions with a unique whole element. -/
class UFractional (α : Type _) extends Fractional α, One α where
whole_iff_one {a : α} : whole a ↔ a = 1
section NumericFractional
/-- Generic fractional instance for types with comparison and 1 operators. -/
class NumericFractional (α : Type _) extends One α, Add α, LE α, LT α where
add_comm : ∀ {a b : α}, a + b = b + a
add_assoc : ∀ {a b c : α}, a + (b + c) = (a + b) + c
add_left_cancel : ∀ {a b c : α}, a + b = a + c → b = c
le_def : ∀ {a b : α}, a ≤ b ↔ a = b ∨ a < b
lt_def : ∀ {a b : α}, a < b ↔ ∃ c : α, a + c = b
lt_not_eq : ∀ {a b : α}, a < b → a ≠ b
instance [NumFractional α] : UFractional α where ...
I think UFractional is probably the most general class that doesn't cause real problems downstream, but I'll keep playing around with it over the next few days to find out.
Mario Carneiro (Jun 27 2025 at 22:11):
what is whole?
Shreyas Srinivas (Jun 27 2025 at 22:13):
I think it’s an implementation of the idea that the only order comparison you actually care about it with 1
Mario Carneiro (Jun 27 2025 at 22:13):
what is add_left_cancel used for?
Mario Carneiro (Jun 27 2025 at 22:13):
I thought that was proper @Shreyas Srinivas
Mario Carneiro (Jun 27 2025 at 22:13):
I don't think @Markus de Medeiros 's code compiles as written since whole isn't defined
Shreyas Srinivas (Jun 27 2025 at 22:14):
whole is proper when the order is total I suppose.
Mario Carneiro (Jun 27 2025 at 22:14):
no, whole appears to generalize a >= 1 while proper generalizes a <= 1
Mario Carneiro (Jun 27 2025 at 22:15):
or maybe 1 | a, I'm not sure because there are no axioms for it
Markus de Medeiros (Jun 27 2025 at 22:16):
Ah right--sorry I snipped that segment out of a couple parts of the PR. Here's the missing piece:
open Fractional in
/-- A fraction does not represent the entire resource.
Generalizes the notion of `(· < 1)` from rational fractions. -/
abbrev fractional [Fractional α] (a : α) : Prop :=
proper a ∧ ∃ b, proper (a + b)
open Fractional in
/-- A fraction that is tne entire resource.
Generalizes the notion of `1` from rational fractions. -/
abbrev whole [Fractional α] (a : α) : Prop :=
proper a ∧ ¬∃ b, proper (a + b)
Mario Carneiro (Jun 27 2025 at 22:17):
I would expect the first conjunct in fractional to not be needed
Mario Carneiro (Jun 27 2025 at 22:17):
FYI proper, fractional and whole should be capitalized
Markus de Medeiros (Jun 27 2025 at 22:17):
Proper generalizes <=, fractional generalizes <, whole generalizes 1. I wanted to see how general I could make the CMRA construction, but for some downstream code it is (or at least seems) important to have a unique whole element.
Shreyas Srinivas (Jun 27 2025 at 22:18):
Mario Carneiro said:
what is
add_left_cancelused for?
I recall using it to prove a few lemmas about order in my pr to Markus’s PR
Markus de Medeiros (Jun 27 2025 at 22:18):
Mario Carneiro said:
I would expect the first conjunct in
fractionalto not be needed
I think you're right about that
Mario Carneiro (Jun 27 2025 at 22:19):
and if you do that then whole can be simplified using fractional
Mario Carneiro (Jun 27 2025 at 22:19):
these shouldn't be abbrevs
Shreyas Srinivas (Jun 28 2025 at 00:01):
The intuitive idea behind the tree is to represent how ownership of a resource is split. Each subtree represents the split up of some fragment of a resource. All currently owned resources are represented by leaf nodes. When a fragment of a resource is split (or some fragment taken out of the resource, the corresponding leaf node branches out into child nodes.
Shreyas Srinivas (Jun 28 2025 at 00:01):
These splits don’t have to be “equal”
Shreyas Srinivas (Jun 28 2025 at 00:02):
You might choose to transfer ownership of an entire subtree of resources to a different branch.
Shreyas Srinivas (Jun 28 2025 at 00:02):
I am trying to come up with the most free version of resource splitting that keeps track of the history of resource partitioning and sharing.
Shreyas Srinivas (Jun 28 2025 at 00:12):
One can also think of the internal & leaf nodes of the tree as threads, where only leaf threads hold resource fragments. When, say, a single thread is forked from another, the node of the parent thread splits into two child nodes of which one carries the resource of the newly forked thread, and the other carries what’s left in the parent thread. Conversely the join operation joins child nodes. If there are no other child threads left then a child node is merged into its parent node. If you wish to represent the transfer of resources to a different thread, this is done by attaching the corresponding subtrees as children of the node corresponding to the recipient thread.
Shreyas Srinivas (Jun 28 2025 at 00:14):
That being said, the more I write, the more complicated this seems to be getting. Rational numbers seem much simpler
Mario Carneiro (Jun 28 2025 at 00:16):
sure, you can imagine the resources as a finite antichain in the complete binary tree, but then the "numbers" need to represent sets of leaves, not just one
Mario Carneiro (Jun 28 2025 at 00:16):
and that's equivalent to dyadic rationals
Mario Carneiro (Jun 28 2025 at 00:34):
Actually if you really want the free structure defined by these axioms I think you would get:
inductive Rat where
| one : Rat
| left : Rat → Rat
| right : Rat → Rat
| add : Rat → Rat → Rat
inductive Equiv : Rat → Rat → Prop
| refl : Equiv a a
| symm : Equiv a b → Equiv b a
| trans : Equiv a b → Equiv b c → Equiv a c
| left : Equiv a a' → Equiv (.left a) (.left a')
| right : Equiv a a' → Equiv (.right a) (.right a')
| add : Equiv a a' → Equiv b b' → Equiv (.add a b) (.add a' b')
| comm : Equiv (.add a b) (.add b a)
| assoc : Equiv (.add a (.add b c)) (.add (.add a b) c)
| split : Equiv (.add (.left a) (.right a)) a
inductive Disjoint : Rat → Rat → Prop
| symm : Disjoint a b → Disjoint b a
| split : Disjoint (.left a) (.right a)
| left : Disjoint a b → Disjoint a (.left b)
| right : Disjoint a b → Disjoint a (.right b)
| add : Disjoint a b → Disjoint a c → Disjoint a (.add b c)
| equiv : Equiv b b' → Disjoint a b → Disjoint a b'
inductive Valid : Rat → Prop
| one : Valid .one
| left : Valid a → Valid (.left a)
| right : Valid a → Valid (.right a)
| add : Valid a → Valid b → Disjoint a b → Valid (.add a b)
| equiv : Equiv a b → Valid a → Valid b
def FreeRational := @Quot {x : Rat // Valid x} (Equiv ·.1 ·.1)
Mario Carneiro (Jun 28 2025 at 00:35):
This is including an axiom saying splits exist, i.e.
Mario Carneiro (Jun 28 2025 at 00:36):
but not specifically that half exists, which is why left and right are not the same
Markus de Medeiros (Jun 28 2025 at 00:57):
Mario Carneiro said:
what is
add_left_cancelused for?
Only the CMRA.Cancellable instance right now, for which it seems necessary. No idea what else downstream.
Shreyas Srinivas (Jun 28 2025 at 01:18):
Mario Carneiro said:
sure, you can imagine the resources as a finite antichain in the complete binary tree, but then the "numbers" need to represent sets of leaves, not just one
Yes. But the sets would correspond to a subtree. So merging a set of resources would be collapsing a subtree to its root node.
Mario Carneiro (Jun 28 2025 at 01:19):
but there isn't necessarily one root node
Shreyas Srinivas (Jun 28 2025 at 01:19):
If some fragment of the subtree is actually moved, the corresponding subsubtree is transplanted to the other root node
Shreyas Srinivas (Jun 28 2025 at 01:19):
Mario Carneiro said:
but there isn't necessarily one root node
Root of a subtree.
Shreyas Srinivas (Jun 28 2025 at 01:20):
The overall tree has one root node that represents 1, and when the tree collapses to its root there is sole ownership again.
Mario Carneiro (Jun 28 2025 at 01:20):
if you have
1
/ \
d c
/ \
a b
then {b, c} can't be represented by the root node 1 because it's missing a
Mario Carneiro (Jun 28 2025 at 01:20):
there is no single node which represents {b, c}
Mario Carneiro (Jun 28 2025 at 01:21):
in the above inductive this would be add (right (left one)) (right one)
Mario Carneiro (Jun 28 2025 at 01:23):
and actually I don't think sets of nodes from the tree is enough, since if you decided to split {b, c} then there is no set of nodes that would be equivalent to (i.e. left (add (right (left one)) (right one)) isn't a set of nodes)
Shreyas Srinivas (Jun 28 2025 at 01:25):
If you split b and c, you would have a new internal node
Mario Carneiro (Jun 28 2025 at 01:26):
no, I'm splitting b + c
Mario Carneiro (Jun 28 2025 at 01:26):
not b or c
Shreyas Srinivas (Jun 28 2025 at 01:26):
Oh right
Shreyas Srinivas (Jun 28 2025 at 01:27):
But once we do b + c, do we care to keep their identities separate?
Shreyas Srinivas (Jun 28 2025 at 01:28):
Can’t they just be one thread carrying b and c as on big fragment of resource?
Mario Carneiro (Jun 28 2025 at 01:28):
we don't, but that's the problem, there is no single node representing that combination so now we can't draw children of that non-node to represent the result of splitting it
Mario Carneiro (Jun 28 2025 at 01:29):
we would need a representation where sums of elements are themselves elements
Shreyas Srinivas (Jun 28 2025 at 01:29):
In my idea you would combine the two nodes of b and c into one node
Mario Carneiro (Jun 28 2025 at 01:29):
which the inductive type does
Mario Carneiro (Jun 28 2025 at 01:29):
what does that mean?
Shreyas Srinivas (Jun 28 2025 at 01:29):
If it is the sole remaining child, then just delete and let the parent node represent the combination of b and c
Mario Carneiro (Jun 28 2025 at 01:30):
You can definitely do it if you have mutable state, the challenge here is that this "rational" type has to represent every possible split pattern and history
Mario Carneiro (Jun 28 2025 at 01:30):
if you have mutable state you just need a list of objects that add to 1
Mario Carneiro (Jun 28 2025 at 01:31):
and every split just removes that element and adds two more
Shreyas Srinivas (Jun 28 2025 at 01:31):
Let’s say you have a node structure a-> [b,c,d]. When merging b and c you create a combined node e. Then you get a -> [e,d]
Shreyas Srinivas (Jun 28 2025 at 01:32):
If you combine e and d into a new blob f, first that node becomes a -> [f]`
Shreyas Srinivas (Jun 28 2025 at 01:32):
Then because a has only one child
Shreyas Srinivas (Jun 28 2025 at 01:32):
a gets replaced by f
Mario Carneiro (Jun 28 2025 at 01:32):
but Rational is just a type, it isn't living in some particular context which keeps track of what other rationals have been created
Mario Carneiro (Jun 28 2025 at 01:34):
and in particular even if you did store that context inside each rational you would get in trouble when it goes out of date because you try to hold on to one piece while splitting another one
Shreyas Srinivas (Jun 28 2025 at 01:40):
My hope is that we don’t actually have to track exact numbers. After all we only care that we can merge the same things we split and check that we have all the pieces. Suppose we split a cake into pieces and put them in different plates on a table. We then put the pieces back on the cake tray. Even if we don’t rearrange them into the exact shape, and have a haphazard arrangement, ,we can determine that all the pieces we cut out have been returned. This is because all the plates are empty
Shreyas Srinivas (Jun 28 2025 at 01:41):
The tree analogy just introduces some bigger intermediate plates and the tree structure tracks which small plates derive their cake from which intermediate plate.
Markus de Medeiros (Jun 28 2025 at 01:41):
Iris is affine so you can lose plates
Shreyas Srinivas (Jun 28 2025 at 01:56):
Right, but even if someone steals a plate, we can track of whether someone owns a totality or part of the remaining cake by checking for emptiness of remaining plates
Shreyas Srinivas (Jun 28 2025 at 01:57):
Even in the rational number case, if some resource fragment just disappears, then thanks to our full ownership check (=?= 1) , the remainig fragments can’t sum up to 1.
Shreyas Srinivas (Jun 28 2025 at 01:58):
To be upfront, I can see the simplicity of just using rational numbers here. The more I think about this tree system, the more complicated it seems.
Mario Carneiro (Jun 28 2025 at 01:59):
Shreyas Srinivas said:
My hope is that we don’t actually have to track exact numbers. After all we only care that we can merge the same things we split and check that we have all the pieces. Suppose we split a cake into pieces and put them in different plates on a table. We then put the pieces back on the cake tray. Even if we don’t rearrange them into the exact shape, and have a haphazard arrangement, ,we can determine that all the pieces we cut out have been returned. This is because all the plates are empty
The free rational type is strictly harder than just tracking actual numbers. But really you don't need to do this in logical reasoning, you existentially quantify all of these numbers so you aren't actually working with them concretely anyway
Mario Carneiro (Jun 28 2025 at 02:00):
The point of this type is to have an abstract accounting mechanism that in principle does not forget anything
Mario Carneiro (Jun 28 2025 at 02:00):
that's what you need to prove the lemmas
Mario Carneiro (Jun 28 2025 at 02:00):
but in the program logic you don't actually need to deal with the numbers
Markus de Medeiros (Jun 28 2025 at 02:09):
Mario Carneiro said:
you existentially quantify all of these numbers
Well that's not strictly true, you could want a finitely splittable fractional resource for example (Nat+ with addition and One.one := n). But your overall point that program logics abstract over the concrete fractions is true.
Mario Carneiro (Jun 28 2025 at 02:10):
if you are doing finite splitting then yes you will have to do math
Mario Carneiro (Jun 28 2025 at 02:11):
maybe the fistful of dollars paper is doing that?
Mario Carneiro (Jun 28 2025 at 02:14):
(misremembered, that was not an iris paper, but https://iris-project.org/pdfs/2019-esop-time.pdf is the iris version)
Markus de Medeiros (Jun 28 2025 at 02:15):
IIRC that's different, more like the numbers CMRA's
Mario Carneiro (Jun 28 2025 at 02:16):
I guess if you want a finitely divisible read permission that would be something like a bounded concurrency primitive
Markus de Medeiros (Jun 28 2025 at 02:26):
Or maybe to specify an invariant for a size N circular buffer, something like [ exists n, Frac(n) * pure (sizeof buf + n = N) ]so if you have Frac i it is sound to add i elements to the buffer without overflow.
Markus de Medeiros (Jun 28 2025 at 02:27):
Anyways, this is interesting but no reason to add anything about splitting to Frac haha
Mario Carneiro (Jun 28 2025 at 02:27):
I don't see why you wouldn't just use numbers CMRA for that
Markus de Medeiros (Jun 28 2025 at 02:28):
Sure, yeah
Mario Carneiro (Jun 28 2025 at 02:28):
I think this discussion has been a bit too theoretical, we don't actually have the code that uses Frac
Mario Carneiro (Jun 28 2025 at 02:30):
the only motivation thus far is that it is one part of the stack to define something we want, but obviously that was added for a reason and I am sure we don't have anything that would notice if we just skipped that part
Markus de Medeiros (Jul 29 2025 at 19:50):
FYI: I did end up needing to add in class of fractions with splitting for this update lemma:
theorem dfrac_undiscard_update [IsSplitFraction F] :
(.discard : DFrac F) ~~>: fun k => ∃ q, k = .own q
Last updated: Dec 20 2025 at 21:32 UTC