-
Notifications
You must be signed in to change notification settings - Fork 251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(AlgebraicGeometry/EllipticCurve/Projective): implement group law for projective coordinates #8485
base: master
Are you sure you want to change the base?
Conversation
David you are far more likely to get this material into mathlib easily if you break it up into far smaller chunks, and write an extensive module docstring explaining what you are doing. I just envisage this PR sitting open for months otherwise. |
`(tactic| simp only [eval_C, eval_X, eval_add, eval_sub, eval_mul, eval_pow]) | ||
|
||
structure PointRep (R : Type u) where | ||
(x y z : R) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The implementation I had in mind is to define the projective space as a subtype (or just a subset) of a quotient type (by the analogue of PointRel R
) of Fin 3 → R
, and define the points as a subtype of that (or just a smaller subset of the quotient type). Doesn't Fin 3
make it easier to connect to MvPolynomial? I think my proposal might be more broadly applicable and convenient, but you have more experience working on this to decide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, it seems your implementation is pretty close to what I have in mind, just that you're using (x y z : R)
rather than Fin 3 → R
. But I think PointRel
and general APIs (e.g. reduction) should be defined in terms of tuples indexed by an arbitrary type (Fin 3
here) to be more widely applicable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I wrote and rewrote this about seven times and I did have Fin 3 → R
originally, but here are two possible issues:
- I would have to write a
Setoid
instance forFin 3 → R
that is visible globally (e.g. for use in other files downstream), which might pose some problems for other people who don't want this instance (e.g. when I want the analogous thing for weighted projective space). Maybe this is a non-issue but I'm not sure. - At the beginning I had the issue that
P
is not defeq to![P.0, P.1, P.2]
(whereas myP
is defeq to<P.x, P.y, P.z>
), and this is slightly annoying when trying to define some predicates and structures in term mode (not a problem for proofs). I have since rewritten the entire file several times so maybe this is no longer problematic.
If you think these aren't big issues, I can try making it work for Fin 3 → R
again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would have to write a
Setoid
instance forFin 3 → R
that is visible globally (e.g. for use in other files downstream), which might pose some problems for other people who don't want this instance (e.g. when I want the analogous thing for weighted projective space). Maybe this is a non-issue but I'm not sure.
The usual approach is make the instSetoidPointRep
a def
and write attribute [local instance]
when you need to activate it.
At the beginning I had the issue that
P
is not defeq to![P.0, P.1, P.2]
(whereas myP
is defeq to<P.x, P.y, P.z>
), and this is slightly annoying when trying to define some predicates and structures in term mode (not a problem for proofs). I have since rewritten the entire file several times so maybe this is no longer problematic.
I don't quite get what the problem in term mode is and would appreciate an example. And what are the "structures" that you mention? In any case, wouldn't you define predicates in terms of P 0
, P 1
and P 2
the same way you define them in terms of P.x
, P.y
and P.z
? You then need to supply a proof it's well-defined to define predicates on the quotient type, but you can do it in tactic mode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough. I don't have an example in mind because this was a while ago. Let me try this again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just realized: PointRel can be defined on any R-module (not just ι → R
) and is actually already available as the MulAction.orbitRel of Units.instMulActionUnitsToMonoidToDivInvMonoidInstGroupUnits, so we can just define PointClass
as the MulAction.orbitRel.Quotient.
For modules of the form ι → R
we can show the ideal generated by the coordinates is invariant under the action, and define the projective space as the subtype where this ideal is the unit ideal. I can't find this in your code, maybe because you don't need this. (Because it's implied by the nonsingularity condition? Maybe we should redefine nonsingularity in terms of the ideal generated by the partial derivatives for compatibility with the projective space and smoothness.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I replaced PointRep
with Fin 3 → R
, but now there will be lots of matrix_simp
's and smul_fin3
's sprinkled in places.
Yes it's implied by the nonsingularity condition. Why do you need the predicates to be defined in terms of ideal generated by the coordinates or partial derivatives? Is this because your base ring is not a field?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I replaced
PointRep
withFin 3 → R
, but now there will be lots ofmatrix_simp
's andsmul_fin3
's sprinkled in places.
Thanks! The diff of a839ab looks pretty reasonable to me (+394 -397). When I'm looking at it I realize that P 0
P 1
P 2
etc. is more obscure than the old P.x
P.y
P.z
, and I came up with some potential tricks to use notations similar to the old ones:
We may introduce a abbrev axis := Fin 3
and use axis → R
instead of Fin 3 → R
. Then we define def axis.x : axis := 0
, def axis.y : axis := 1
etc. so that for P : axis → R
we may write P .x
etc. Or maybe we can just introduce private def Fin.x : Fin 3 := 0
etc. without introducing axis
. We could also introduce axis
as an inductive type of three constructors x
, y
, and z
, and the advantage would be being able to use cases
rather than fin_cases
. (Maybe Lean 4's cases
can do fin_cases
as well? Anyway I don't think this is that much an advantage.)
Yes it's implied by the nonsingularity condition. Why do you need the predicates to be defined in terms of ideal generated by the coordinates or partial derivatives? Is this because your base ring is not a field?
The condition feels more natural as it's preserved by ring homomorphisms and invariant under the action by the group of units, and I think if you define the projective points this way then E(R) maps to E(Frac R) and E(R/m) which identifies E(R) as the nonsingular points of E(Frac R) that reduces to nonsingular points of E(R/m) (for R a DVR, say). And the unit ideal condition on projective points easily reduces to that on the affine points, because of the identity
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would the current definitions be too troublesome for the maps you need? I would think R -> Frac R and R -> R / m are just baseChange
s over algebras, and we have the corresponding baseChange
on the nonsingular points.
I'm trying to give analogous definitions for weighted projective points, and I'm not sure how easy it is to rephrase everything in terms of ideals in this case, and I still need to do the same for the group law, which is why I'm hesitating.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like a local notation
suffices if we just need it to be pretty in the file.
51fb893
to
a839abc
Compare
…t into two files (#8540) Refactor the files in `AlgebraicGeometry/EllipticCurve/*` as follows: - `Weierstrass.lean` contains general definitions common to all Weierstrass and elliptic curves, namely quantities associated to their coefficients, variable and base changes, and models with prescribed j-invariants. - `Affine.lean` contains definitions specific to Weierstrass curves written in affine coordinates, including `equation` and `nonsingular` from the old `Weierstrass.lean`, but also the `Point` inductive and group operations from the old `Point.lean`. - `Group.lean` contains a standalone proof of the group law for `Point`, including instances for `CoordinateRing` in the old `Weierstrass.lean`, and ideal computations in its `ClassGroup` in the old `Point.lean`. This refactor is done in preparation for the new `Projective.lean` in #8485 (and the upcoming `Jacobian.lean`), which shares all the general definitions in `Weierstrass.lean`, but none of those in `Affine.lean` and `Group.lean` except their proofs (analogous lemmas are proven by "reducing to the affine case"). Most of the definitions and lemmas for `equation`, `nonsingular`, `CoordinateRing`, and `ClassGroup` are specific to the affine representation of Weierstrass curves, so they are now in the `WeierstrassCurve.Affine` namespace, which is just an abbreviation for `WeierstrassCurve`. Further documentation is added to `Group.lean` to explain the argument for the group law, but otherwise few things are changed from the original files.
…t into two files (#8540) Refactor the files in `AlgebraicGeometry/EllipticCurve/*` as follows: - `Weierstrass.lean` contains general definitions common to all Weierstrass and elliptic curves, namely quantities associated to their coefficients, variable and base changes, and models with prescribed j-invariants. - `Affine.lean` contains definitions specific to Weierstrass curves written in affine coordinates, including `equation` and `nonsingular` from the old `Weierstrass.lean`, but also the `Point` inductive and group operations from the old `Point.lean`. - `Group.lean` contains a standalone proof of the group law for `Point`, including instances for `CoordinateRing` in the old `Weierstrass.lean`, and ideal computations in its `ClassGroup` in the old `Point.lean`. This refactor is done in preparation for the new `Projective.lean` in #8485 (and the upcoming `Jacobian.lean`), which shares all the general definitions in `Weierstrass.lean`, but none of those in `Affine.lean` and `Group.lean` except their proofs (analogous lemmas are proven by "reducing to the affine case"). Most of the definitions and lemmas for `equation`, `nonsingular`, `CoordinateRing`, and `ClassGroup` are specific to the affine representation of Weierstrass curves, so they are now in the `WeierstrassCurve.Affine` namespace, which is just an abbreviation for `WeierstrassCurve`. Further documentation is added to `Group.lean` to explain the argument for the group law, but otherwise few things are changed from the original files.
…t into two files (#8540) Refactor the files in `AlgebraicGeometry/EllipticCurve/*` as follows: - `Weierstrass.lean` contains general definitions common to all Weierstrass and elliptic curves, namely quantities associated to their coefficients, variable and base changes, and models with prescribed j-invariants. - `Affine.lean` contains definitions specific to Weierstrass curves written in affine coordinates, including `equation` and `nonsingular` from the old `Weierstrass.lean`, but also the `Point` inductive and group operations from the old `Point.lean`. - `Group.lean` contains a standalone proof of the group law for `Point`, including instances for `CoordinateRing` in the old `Weierstrass.lean`, and ideal computations in its `ClassGroup` in the old `Point.lean`. This refactor is done in preparation for the new `Projective.lean` in #8485 (and the upcoming `Jacobian.lean`), which shares all the general definitions in `Weierstrass.lean`, but none of those in `Affine.lean` and `Group.lean` except their proofs (analogous lemmas are proven by "reducing to the affine case"). Most of the definitions and lemmas for `equation`, `nonsingular`, `CoordinateRing`, and `ClassGroup` are specific to the affine representation of Weierstrass curves, so they are now in the `WeierstrassCurve.Affine` namespace, which is just an abbreviation for `WeierstrassCurve`. Further documentation is added to `Group.lean` to explain the argument for the group law, but otherwise few things are changed from the original files.
…t into two files (#8540) Refactor the files in `AlgebraicGeometry/EllipticCurve/*` as follows: - `Weierstrass.lean` contains general definitions common to all Weierstrass and elliptic curves, namely quantities associated to their coefficients, variable and base changes, and models with prescribed j-invariants. - `Affine.lean` contains definitions specific to Weierstrass curves written in affine coordinates, including `equation` and `nonsingular` from the old `Weierstrass.lean`, but also the `Point` inductive and group operations from the old `Point.lean`. - `Group.lean` contains a standalone proof of the group law for `Point`, including instances for `CoordinateRing` in the old `Weierstrass.lean`, and ideal computations in its `ClassGroup` in the old `Point.lean`. This refactor is done in preparation for the new `Projective.lean` in #8485 (and the upcoming `Jacobian.lean`), which shares all the general definitions in `Weierstrass.lean`, but none of those in `Affine.lean` and `Group.lean` except their proofs (analogous lemmas are proven by "reducing to the affine case"). Most of the definitions and lemmas for `equation`, `nonsingular`, `CoordinateRing`, and `ClassGroup` are specific to the affine representation of Weierstrass curves, so they are now in the `WeierstrassCurve.Affine` namespace, which is just an abbreviation for `WeierstrassCurve`. Further documentation is added to `Group.lean` to explain the argument for the group law, but otherwise few things are changed from the original files.
… and nonsingularity for projective coordinates (#9416) Define a projective point representative over a ring `R` as the type `Fin 3 -> R`, and its equivalence class `PointClass` as a quotient by the usual scaling relation. Define the analogous `equation` and `nonsingular` predicates on `Fin 3 -> F` over a field `F`, and lift `nonsingular` to `PointClass`. This also has minimal API (e.g. it's missing many of the `equation` lemmas) as most computations should ideally be done using the affine API. This is the first in a series of four PRs leading to #8485
… and nonsingularity for projective coordinates (#9416) Define a projective point representative over a ring `R` as the type `Fin 3 -> R`, and its equivalence class `PointClass` as a quotient by the usual scaling relation. Define the analogous `equation` and `nonsingular` predicates on `Fin 3 -> F` over a field `F`, and lift `nonsingular` to `PointClass`. This also has minimal API (e.g. it's missing many of the `equation` lemmas) as most computations should ideally be done using the affine API. This is the first in a series of four PRs leading to #8485
… and nonsingularity for projective coordinates (#9416) Define a projective point representative over a ring `R` as the type `Fin 3 -> R`, and its equivalence class `PointClass` as a quotient by the usual scaling relation. Define the analogous `equation` and `nonsingular` predicates on `Fin 3 -> F` over a field `F`, and lift `nonsingular` to `PointClass`. This also has minimal API (e.g. it's missing many of the `equation` lemmas) as most computations should ideally be done using the affine API. This is the first in a series of four PRs leading to #8485
… and nonsingularity for projective coordinates (#9416) Define a projective point representative over a ring `R` as the type `Fin 3 -> R`, and its equivalence class `PointClass` as a quotient by the usual scaling relation. Define the analogous `equation` and `nonsingular` predicates on `Fin 3 -> F` over a field `F`, and lift `nonsingular` to `PointClass`. This also has minimal API (e.g. it's missing many of the `equation` lemmas) as most computations should ideally be done using the affine API. This is the first in a series of four PRs leading to #8485
… and nonsingularity for projective coordinates (#9416) Define a projective point representative over a ring `R` as the type `Fin 3 -> R`, and its equivalence class `PointClass` as a quotient by the usual scaling relation. Define the analogous `equation` and `nonsingular` predicates on `Fin 3 -> F` over a field `F`, and lift `nonsingular` to `PointClass`. This also has minimal API (e.g. it's missing many of the `equation` lemmas) as most computations should ideally be done using the affine API. This is the first in a series of four PRs leading to #8485
… and nonsingularity for projective coordinates (#9416) Define a projective point representative over a ring `R` as the type `Fin 3 -> R`, and its equivalence class `PointClass` as a quotient by the usual scaling relation. Define the analogous `equation` and `nonsingular` predicates on `Fin 3 -> F` over a field `F`, and lift `nonsingular` to `PointClass`. This also has minimal API (e.g. it's missing many of the `equation` lemmas) as most computations should ideally be done using the affine API. This is the first in a series of four PRs leading to #8485
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some initial comments
/-- The point class underlying a nonsingular rational point on `W`. -/ | ||
add_decl_doc Point.point | ||
|
||
/-- The nonsingular condition underlying a nonsingular rational point on `W`. -/ | ||
add_decl_doc Point.nonsingular |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
inline
attribute [pp_dot] Point.point | ||
attribute [pp_dot] Point.nonsingular |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
presumably
attribute [pp_dot] Point.point | |
attribute [pp_dot] Point.nonsingular | |
attribute [pp_dot] Point.point Point.nonsingular |
/-- The proposition that a point representative $(x, y, z)$ lies in `W`. | ||
In other words, $W(x, y, z) = 0$. -/ | ||
@[pp_dot] | ||
def equation (P : Fin 3 → R) : Prop := |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
capitalize (ditto for Nonsingular(Lift)
)
This is only an auxiliary definition needed to define `WeierstrassCurve.Projective.addY'_of_Xne`, | ||
and the full $X$-coordinate is defined in `WeierstrassCurve.Projective.addX_of_Xne`. -/ | ||
@[pp_dot] | ||
def addX'_of_Xne (P Q : Fin 3 → R) : R := |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
negAddXOfXNe
?
(I don't care much since I won't need the projective addition formulas for the reduction homomorphism. The projective addition formulas have the same number of cases as the affine formulas, so we can just transfer the affine addition formulas through the Equiv on Points, and the projective formulas do not look more computable than the affine ones (basically you need to check the same amount of conditions).)
See my later comment: https://github.com/leanprover-community/mathlib4/pull/8485/files#r1649475618
lemma add_left_neg (P : W.Point) : -P + P = 0 := | ||
toAffine_addEquiv.injective <| by | ||
rcases P with @⟨⟨_⟩, _⟩ | ||
simp only [map_add, toAffine_addEquiv_apply, toAffine_lift_neg, Affine.Point.add_left_neg, | ||
toAffine_lift_zero] | ||
|
||
lemma add_comm (P Q : W.Point) : P + Q = Q + P := | ||
toAffine_addEquiv.injective <| by simp_rw [map_add, Affine.Point.add_comm] | ||
|
||
lemma add_assoc (P Q R : W.Point) : P + Q + R = P + (Q + R) := | ||
toAffine_addEquiv.injective <| by simp only [map_add, Affine.Point.add_assoc] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
inline
Thanks for the comments. I won't be touching this PR until the Jacobian project is over, but I will keep these in mind. |
![W.addX_of_Yne P, W.addY_of_Yne P, W.addZ_of_Yne P] | ||
else ![W.addX_of_Xne P Q, W.addY_of_Xne P Q, addZ_of_Xne P Q] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these could be called ![W.dblX P, W.dblY P, W.dblZ P]
and ![W.addX P, W.addY P, addZ P]
just like the Jacobian case. In fact, I've found that you can remove a P z ^ 2
factor from the projective doubling formula to make it valid in all cases (O+O or P+P for P 2-torsion); the resulting formula is homogeneous of degree 4 rather than 6. From the projective addition formula, you can also remove a factor of P z * Q z
, and the resulting formula is homogeneous of degree 6 rather than 8, and applies in the case P=-Q≠Q, but not in the cases P=O or Q=O (gives (0,0,0)). I don't think this simplifies the proof that the reduction map is a homomorphism though.
I think this is the best you can do in projective coordinates, which is not as nice as the Jacobian formulas, where both doubling and addition are weighted homogeneous of degree (8,12,4) and applies more universally without needing to single out the cases P+O and O+P.
The way to remove the factors is as follows: for Xne
/add
, subtract addX'_of_Xne
, then it becomes divisible by addY'_of_Xne
and add Yne
/dbl
, add addX'_of_Yne
then it becomes divisible by addX_of_Yne
. Plug this new version of addX'_of_Yne
+ addY'_of_Yne
and subtract addY'_of_Yne
becomes divisible by
Completes the proof of the group law in projective coordinates.