-
-
Notifications
You must be signed in to change notification settings - Fork 482
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
Implement the logarithm and the exponential of a Drinfeld module #35260
Merged
Merged
Changes from 30 commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
c23ec60
inital commit
DavidAyotte 1f608cf
enhance_compute_coeffcient_log
DavidAyotte 3daba4a
add documentation
DavidAyotte 451cf1f
implement exponential
DavidAyotte bfe9a0c
document exponential method
DavidAyotte 01d620d
enhance documentation of logarithm
DavidAyotte 9b83a03
Merge branch 'develop' into logarithm_exponential
DavidAyotte 643cfde
fix some line length and add some details to the doc
DavidAyotte c7f9ffd
Merge branch 'develop' into logarithm_exponential
DavidAyotte 5356e39
fix mistake
DavidAyotte 237815f
Merge branch 'develop' into logarithm_exponential
DavidAyotte 9c8d4a7
small updates
DavidAyotte 644cafc
(re)add the valuation=1 flag
DavidAyotte 8323f6f
fix failing doctests
DavidAyotte fad3fd3
Merge branch 'develop' into logarithm_exponential
DavidAyotte b73d1ae
remove unnecessary integer type conversion
DavidAyotte ba57245
add cached_method decorator
DavidAyotte 364fd55
use ellipsis
DavidAyotte 8f292e9
fix failing doctets
DavidAyotte eb78111
Update src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py
DavidAyotte 68477a8
Merge remote-tracking branch 'origin/logarithm_exponential' into logaβ¦
DavidAyotte 1504a19
add checks for finite Drinfeld modules
DavidAyotte 706ded5
update error message
DavidAyotte 26498b8
refactor _compute_coefficient methods
DavidAyotte 005acd5
Update src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py
DavidAyotte 7f72a21
Update src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py
DavidAyotte 962e70d
Update src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py
DavidAyotte 3e873b9
Update src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py
DavidAyotte f8c867d
fix failing doctest
DavidAyotte e85227e
minor update to documentation of exponential and logarithm
DavidAyotte 2b242fb
refactor exponential and logarithm
DavidAyotte File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,10 +26,13 @@ | |
|
||
from sage.categories.drinfeld_modules import DrinfeldModules | ||
from sage.categories.homset import Hom | ||
from sage.misc.cachefunc import cached_method | ||
from sage.misc.latex import latex | ||
from sage.misc.latex import latex_variable_name | ||
from sage.misc.lazy_import import lazy_import | ||
from sage.misc.lazy_string import _LazyString | ||
from sage.rings.integer import Integer | ||
from sage.rings.integer_ring import ZZ | ||
from sage.rings.polynomial.ore_polynomial_element import OrePolynomial | ||
from sage.rings.polynomial.polynomial_ring import PolynomialRing_general | ||
from sage.rings.ring_extension import RingExtension_generic | ||
|
@@ -38,6 +41,8 @@ | |
from sage.structure.sequence import Sequence | ||
from sage.structure.unique_representation import UniqueRepresentation | ||
|
||
lazy_import('sage.rings.lazy_series_ring', 'LazyPowerSeriesRing') | ||
|
||
|
||
class DrinfeldModule(Parent, UniqueRepresentation): | ||
r""" | ||
|
@@ -958,6 +963,127 @@ def coefficients(self, sparse=True): | |
""" | ||
return self._gen.coefficients(sparse=sparse) | ||
|
||
@cached_method | ||
def _compute_coefficient_exp(self, k): | ||
r""" | ||
Return the `q^k`-th coefficient of the exponential of this Drinfeld module. | ||
|
||
INPUT: | ||
|
||
- ``k`` (integer) -- the index of the coefficient | ||
|
||
TESTS:: | ||
|
||
sage: A = GF(2)['T'] | ||
sage: K.<T> = Frac(A) | ||
sage: phi = DrinfeldModule(A, [T, 1]) | ||
sage: q = A.base_ring().cardinality() | ||
sage: phi._compute_coefficient_exp(0) | ||
1 | ||
sage: phi._compute_coefficient_exp(1) | ||
1/(T^2 + T) | ||
sage: phi._compute_coefficient_exp(2) | ||
1/(T^8 + T^6 + T^5 + T^3) | ||
sage: phi._compute_coefficient_exp(3) | ||
1/(T^24 + T^20 + T^18 + T^17 + T^14 + T^13 + T^11 + T^7) | ||
""" | ||
k = ZZ(k) | ||
if k.is_zero(): | ||
return self._base.one() | ||
q = self._Fq.cardinality() | ||
c = self._base.zero() | ||
for i in range(k): | ||
j = k - i | ||
c += self._compute_coefficient_exp(i)*self._compute_coefficient_log(j)**(q**i) | ||
return -c | ||
|
||
def exponential(self, name='z'): | ||
r""" | ||
Return the exponential of this Drinfeld module. | ||
|
||
Note that the exponential is only defined when the | ||
`\mathbb{F}_q[T]`-characteristic is zero. | ||
|
||
INPUT: | ||
|
||
- ``name`` (string, default: ``'z'``) -- the name of the | ||
generator of the lazy power series ring. | ||
|
||
OUTPUT: | ||
|
||
A lazy power series over the base field. | ||
|
||
EXAMPLES:: | ||
|
||
sage: A = GF(2)['T'] | ||
sage: K.<T> = Frac(A) | ||
sage: phi = DrinfeldModule(A, [T, 1]) | ||
sage: q = A.base_ring().cardinality() | ||
sage: exp = phi.exponential(); exp | ||
z + ((1/(T^2+T))*z^2) + ((1/(T^8+T^6+T^5+T^3))*z^4) + O(z^8) | ||
|
||
The exponential is returned as a lazy power series, meaning that | ||
any of its coefficients can be computed on demands:: | ||
|
||
sage: exp[2^4] | ||
1/(T^64 + T^56 + T^52 + ... + T^27 + T^23 + T^15) | ||
sage: exp[2^5] | ||
1/(T^160 + T^144 + T^136 + ... + T^55 + T^47 + T^31) | ||
|
||
Example in higher rank:: | ||
|
||
sage: A = GF(5)['T'] | ||
sage: K.<T> = Frac(A) | ||
sage: phi = DrinfeldModule(A, [T, T^2, T + T^2 + T^4, 1]) | ||
sage: exp = phi.exponential(); exp | ||
z + ((T/(T^4+4))*z^5) + O(z^8) | ||
|
||
The exponential is the compositional inverse of the logarithm | ||
(see :meth:`logarithm`):: | ||
|
||
sage: log = phi.logarithm(); log | ||
z + ((4*T/(T^4+4))*z^5) + O(z^8) | ||
sage: exp.compose(log) | ||
z + O(z^8) | ||
sage: log.compose(exp) | ||
z + O(z^8) | ||
|
||
:: | ||
|
||
sage: Fq.<w> = GF(3) | ||
sage: A = Fq['T'] | ||
sage: phi = DrinfeldModule(A, [w, 1]) | ||
sage: phi.exponential() | ||
Traceback (most recent call last): | ||
... | ||
ValueError: characteristic must be zero (=T + 2) | ||
|
||
TESTS:: | ||
|
||
sage: A = GF(2)['T'] | ||
sage: K.<T> = Frac(A) | ||
sage: phi = DrinfeldModule(A, [T, 1]) | ||
sage: exp = phi.exponential() | ||
sage: exp[2] == 1/(T**q - T) # expected value | ||
True | ||
sage: exp[2^2] == 1/((T**(q**2) - T)*(T**q - T)**q) # expected value | ||
True | ||
sage: exp[2^3] == 1/((T**(q**3) - T)*(T**(q**2) - T)**q*(T**q - T)**(q**2)) # expected value | ||
True | ||
|
||
REFERENCE: | ||
|
||
See section 4.6 of [Gos1998]_ for the definition of the | ||
exponential. | ||
""" | ||
if self.category()._characteristic: | ||
raise ValueError(f"characteristic must be zero (={self.characteristic()})") | ||
L = LazyPowerSeriesRing(self._base, name) | ||
zero = self._base.zero() | ||
q = self._Fq.cardinality() | ||
exp = lambda k: self._compute_coefficient_exp(ZZ(k).log(q)) if ZZ(k).is_power_of(q) or k == 0 else zero | ||
return L(exp, valuation=1) | ||
|
||
def gen(self): | ||
r""" | ||
Return the generator of the Drinfeld module. | ||
|
@@ -1103,6 +1229,113 @@ def j_invariant(self): | |
q = self._Fq.order() | ||
return (g**(q+1)) / delta | ||
|
||
@cached_method | ||
def _compute_coefficient_log(self, k): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same remarks as for exp. |
||
r""" | ||
Return the `q^k`-th coefficient of the logarithm of this Drinfeld module. | ||
|
||
TESTS:: | ||
|
||
sage: A = GF(2)['T'] | ||
sage: K.<T> = Frac(A) | ||
sage: phi = DrinfeldModule(A, [T, 1]) | ||
sage: q = A.base_ring().cardinality() | ||
sage: phi._compute_coefficient_log(0) | ||
1 | ||
sage: phi._compute_coefficient_log(1) | ||
1/(T^2 + T) | ||
sage: phi._compute_coefficient_log(2) | ||
1/(T^6 + T^5 + T^3 + T^2) | ||
sage: phi._compute_coefficient_log(3) | ||
1/(T^14 + T^13 + T^11 + T^10 + T^7 + T^6 + T^4 + T^3) | ||
""" | ||
k = ZZ(k) | ||
if k.is_zero(): | ||
return self._base.one() | ||
r = self._gen.degree() | ||
T = self._gen[0] | ||
q = self._Fq.cardinality() | ||
c = self._base.zero() | ||
for i in range(k): | ||
j = k - i | ||
if j < r + 1: | ||
c += self._compute_coefficient_log(i)*self._gen[j]**(q**i) | ||
return c/(T - T**(q**k)) | ||
|
||
def logarithm(self, name='z'): | ||
r""" | ||
Return the logarithm of the given Drinfeld module. | ||
|
||
By definition, the logarithm is the compositional inverse of the | ||
exponential (see :meth:`exponential`). Note that the logarithm | ||
is only defined when the `\mathbb{F}_q[T]`-characteristic is | ||
zero. | ||
|
||
INPUT: | ||
|
||
- ``name`` (string, default: ``'z'``) -- the name of the | ||
generator of the lazy power series ring. | ||
|
||
OUTPUT: | ||
|
||
A lazy power series over the base field. | ||
|
||
EXAMPLES:: | ||
|
||
sage: A = GF(2)['T'] | ||
DavidAyotte marked this conversation as resolved.
Show resolved
Hide resolved
|
||
sage: K.<T> = Frac(A) | ||
sage: phi = DrinfeldModule(A, [T, 1]) | ||
sage: log = phi.logarithm(); log | ||
z + ((1/(T^2+T))*z^2) + ((1/(T^6+T^5+T^3+T^2))*z^4) + O(z^8) | ||
|
||
The logarithm is returned as a lazy power series, meaning that | ||
any of its coefficients can be computed on demands:: | ||
|
||
sage: log[2^4] | ||
1/(T^30 + T^29 + T^27 + ... + T^7 + T^5 + T^4) | ||
sage: log[2^5] | ||
1/(T^62 + T^61 + T^59 + ... + T^8 + T^6 + T^5) | ||
|
||
Example in higher rank:: | ||
|
||
sage: A = GF(5)['T'] | ||
sage: K.<T> = Frac(A) | ||
sage: phi = DrinfeldModule(A, [T, T^2, T + T^2 + T^4, 1]) | ||
sage: phi.logarithm() | ||
z + ((4*T/(T^4+4))*z^5) + O(z^8) | ||
|
||
TESTS:: | ||
|
||
sage: A = GF(2)['T'] | ||
sage: K.<T> = Frac(A) | ||
sage: phi = DrinfeldModule(A, [T, 1]) | ||
sage: q = 2 | ||
sage: log[2] == -1/((T**q - T)) # expected value | ||
True | ||
sage: log[2**2] == 1/((T**q - T)*(T**(q**2) - T)) # expected value | ||
True | ||
sage: log[2**3] == -1/((T**q - T)*(T**(q**2) - T)*(T**(q**3) - T)) # expected value | ||
True | ||
|
||
:: | ||
|
||
sage: Fq.<w> = GF(3) | ||
sage: A = Fq['T'] | ||
sage: phi = DrinfeldModule(A, [w, 1]) | ||
sage: phi.logarithm() | ||
Traceback (most recent call last): | ||
... | ||
ValueError: characteristic must be zero (=T + 2) | ||
""" | ||
if self.category()._characteristic: | ||
raise ValueError(f"characteristic must be zero (={self.characteristic()})") | ||
L = LazyPowerSeriesRing(self._base, name) | ||
zero = self._base.zero() | ||
q = self._Fq.cardinality() | ||
log = lambda k: self._compute_coefficient_log(ZZ(k).log(q)) if ZZ(k).is_power_of(q) or k == 0 else zero | ||
DavidAyotte marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return L(log, valuation=1) | ||
|
||
|
||
def morphism(self): | ||
r""" | ||
Return the morphism object that defines the Drinfeld module. | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 are (nonterminal) recursive calls in this function.
Probably, we should consider adding the decorator
@cached_method
for performances.