feat(Units): reducible rational arithmetic via Exponent - #1579
feat(Units): reducible rational arithmetic via Exponent#1579RaunakChhatwal wants to merge 3 commits into
Conversation
|
Thank you for this pull-request (PR). If this is your first PR, welcome to the community! Below is what will happen next. Please read carefully if you are not familiar with the process. You may open other PRs while this one is being reviewed, and can stack PRs on top of each other, so don't let these steps slow you down.
Tip: The easiest way to get have a fast review is to submit a PR that is small and self-contained, and has clear documentation explaining why things are the way they are in your chages. If you have any problems or questions, please reach out to the community on the Zulip. |
|
Maybe worth actually implementing this as the type for dimension exponent now, so it fits in with the rest of the project |
|
Putting awaiting-author For above comment, but also the linters. |
|
Sure, I updated Concrete cancellation now reduces as intended, so -awaiting-author |
|
Thanks for digging into this, @RaunakChhatwal — and for the cc. I wrote the parametric Short version, in three parts:
1.
|
|
The size and scope of that comment is uncalled for, and it reads like an AI-generated review dump. The first section opens with an outright hallucination:
The What then follows is a combination of concrete blockers, follow-up suggestions, minor cleanup, benchmarking requests, documentation requests, a lengthy argument about a future design mentioned in the description, a broader architectural critique, an alternative design proposal, and proposed sequencing for future work. This is an extremely large amount of material to put on one PR and then mark On the "main technical concern"This applies to many Mathlib type classes, and is not a concern specific to having a Type-valued field. If one defines two incompatible
Any dependent type indexed on an instance parameter (e.g. -awaiting-author |
|
@jstoobysmith Ideally, quantities/units should be the foundation for higher-level core APIs throughout the library. A |
|
You are right, and the correction is worse than you stated: I was wrong twice, not once.
example : Nat.gcd 1234567 7654321 = 1 := rfl -- succeeds
unseal Rat.add Rat.mul Rat.inv Rat.sub
example : ((1/3:Rat) + 1/6 + 1/7 + 2/9 + 5/11) * (3/5) - 1/13 = 21467/30030 := rfl -- succeedsIrreducibility is the whole of it, and unsealing is sufficient to lift it — which is exactly what On the lengthFair, and I have taken the point. That comment mixed diff-scoped review with an argument about a Where it should go is a question for @jstoobysmith: #1441 is where those requirements were On canonicityYou are right that I over-generalised. Import-order-sensitive elaboration under competing What I would still raise, narrowly: @[instance_reducible] instance altBasis : DimensionBasis LTMCTDimensionBase := DimensionBasis.pi _
def speed : Dimension LTMCTDimensionBase := L𝓭 / T𝓭
-- Type mismatch: @Dimension LTMCTDimensionBase LTMCTDimensionBase.instDimensionBasis
-- vs @Dimension LTMCTDimensionBase altBasisBoth instances are correct and neither author has erred. The cost is composition: two downstream Carrying the basis as a bundled value rather than an instance removes the search that makes this One thing that does not work yet — and a patch for itRational exponents do not get the -- integer exponents: the motivating example from your description now works
example (v : WithDim (L𝓭 / T𝓭) ℝ) (t : WithDim T𝓭 ℝ) : WithDim L𝓭 ℝ := v * t -- succeeds
-- rational exponents: unchanged from before the PR
example (a b : WithDim (L𝓭 ^ (1/2 : ℚ)) ℝ) : WithDim L𝓭 ℝ := a * b -- failsThe second fails with the same error your description opens with — The cause is not the example : (1 : Exponent)/2 + (1 : Exponent)/2 = 1 := rfl -- succeeds
example : Exponent.ofRat (1/2) + Exponent.ofRat (1/2) = 1 := rfl -- failsAll three of your section-D examples are of the first shape — the arithmetic happens in Which makes the fix small. Adding a /-- Raising a dimension to an `Exponent` power.
`^ (q : ℚ)` must call `Exponent.ofRat q`, which wraps a rational whose own arithmetic is
irreducible, so concrete rational powers do not reduce. Taking the exponent in the reducible
representation keeps the definitional win for fractional dimensions. -/
instance : Pow (Dimension B) Exponent where
pow d c := ofFunction fun b => d.exponent b * c
@[simp]
lemma epow_exponent (d : Dimension B) (c : Exponent) (b : B) :
(d ^ c).exponent b = d.exponent b * c :=
ofFunction_exponent _ _With that, on your branch: example : (L𝓭 ^ (1/2 : Exponent)) * (L𝓭 ^ (1/2 : Exponent)) = L𝓭 := rfl -- succeeds
example : (L𝓭 ^ (2/3 : Exponent)) * (L𝓭 ^ (1/3 : Exponent)) = L𝓭 := rfl -- succeeds
example (a b : WithDim (L𝓭 ^ (1/2 : Exponent)) ℝ) : WithDim L𝓭 ℝ := a * b -- succeedsThe call site stays the same shape as before — A related one, now filed as #1580. While testing the above I found that an unascribed example : L𝓭 ^ (1/2) = 1 := rfl -- succeeds: a "square root of a length" is dimensionlessThis one is not yours — it reproduces on the pre-PR base @[default_instance 10000] instance : Pow (Dimension B) Exponent where ...Priority matters — at the default and at If the On adoptionYour point to @jstoobysmith is a fair one and the numbers support it: exactly one of the 538 The one implication I would draw is about timing. Precisely because nothing depends on this layer What I would still ask for on this PRA That is the only thing I would hold out for. Everything else above is withdrawn, offered as a |
Reducible rational arithmetic for dimension exponents
Ideally, the product of speed and time should type-check as length. This does not happen at present because the product of their dimensions is not definitionally equal to the length dimension:
The root cause is that dimension arithmetic uses rational arithmetic, whose operations are irreducible in Lean:
Locally unsealing rational arithmetic does not export reducibility to downstream modules, while globally changing the reducibility of imported declarations requires allowUnsafeReducibility. This PR instead introduces a wrapper around ℚ with reducible arithmetic, enabling:
This enables definitional equality for tuple- or structure-based dimensions, but unfortunately not for Physlib's current parametric dimensions. Lean's definitional equality is less effective at comparing unapplied functions than concrete data structures, while the parametric approach relies on function representation to maintain basis independence. I would therefore like to follow this PR with a simpler, non-parametric formalization of dimensions using Exponent.