-
-
Notifications
You must be signed in to change notification settings - Fork 631
Implement kernel_points and inverse_image for elliptic curve hom #40251
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
base: develop
Are you sure you want to change the base?
Implement kernel_points and inverse_image for elliptic curve hom #40251
Conversation
Documentation preview for this PR (built with commit b6176fe; changes) is ready! 🎉 |
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.
A bunch of minor things.
if Q not in self.codomain(): | ||
raise TypeError('input must be a point in the codomain') |
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.
Should we explicitly cast Q
to the codomain? For example, 2/2 in ZZ
but it is not an integer.
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.
__contains__
implementation of EllipticCurve checks isinstance(Q, EllipticCurveModel) and Q.curve() == self
if I recalled correctly, so I think this does what it should.
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.
Actually you're right, the current behavior is like this
sage: f.inverse_image((0, 2))
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
...
AttributeError: 'tuple' object has no attribute 'is_zero'
on the other hand,
sage: f.codomain().coerce((0, 2))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
...
TypeError: no canonical coercion from <class 'tuple'> to Elliptic Curve defined by ...
it's not ideal to directly convert the point, since the zero point in any elliptic curve can be converted into the zero point in any other elliptic curve. I decide to cast it after checking Q in self.codomain()
.
New behavior:
sage: f.inverse_image((0, 2))
(2 : 3*z2 + 1 : 1)
Or maybe it's a good idea to make conversion not work for the wrong curve, or __contains__
not work for tuple? After all the documentation says
def __contains__(self, P):
"""
Return ``True`` if and only if P is a point on the elliptic curve.
P just has to be something that can be coerced to a point.
see "coerced", not "converted". Yet the implementation converts.
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.
There isn't necessarily anything wrong with it using conversion to check (yes, the doc should be changed). Well, I'm not sure what the best course of action is here as I don't use this code. John is a very good person to ask about this.
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 that using contains as a test is fine. If E1 and E2 are different curves then "E1(0) in E2" is False.
I noticed this PR just when I was myself computing some inverse images under isogenies, so thanks! For what I was doing I would need an option extend=True. Perhaps we can mae that a new issue, I would not want to delay this one. It's not an obvious extension since even for the x-coordinates, the roots will in general lie in different fields. |
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.
Nothing to add beyond what @tscrim has already said. Good!
I realize there's a bug that if you just call |
That is a good catch, which I should have noticed before yesterday's comment. You might find it helpful to look at the code (which I wrote) for Q.division_points(n) which returns a list of P satisfying nP=Q. That's a specical case of what this function is doing. That code does look at every root x and tries to lift to (x,y). Now if 2Q=0 then both y's are valid solutions, while otherwise at most one is, and you may need to check both to see which one works. |
I took a look. The only difference with the current implementation is the check of is 2 torsion, but I think that check is not particularly useful, at best it saves 1-2 evaluation of the morphism at the cost of computing |
Ideally I want to implement
.kernel_gens()
(and eventually.kernel()
) but that requires a lot of framework (subgroup ofE.abelian_group()
, etc.)Also it may be possible to use a more efficient algorithm for
EllipticCurveHom_composite
, but I haven't worked out the math yet. (if you're lucky then taking the inverse image over each successtiveφ
works, but otherwise…) Currently it takes successive image, but might have bad worst case behavior.📝 Checklist
⌛ Dependencies