1 | initial version |
The following may be a solution for small values of the degree of the cyclotomic field. In order to have a handy situation, where tests and prints are easy to follow, i will use P, N = 19, 18
instead of the data P, N = 53, 52
, extracted and generalized from the post. It may be that the following fails for bigger values of P, N
.
Let us start with:
P, N = 19, 18
F.<a> = CyclotomicField( P )
L.<b> = F.extension( cyclotomic_polynomial(N) )
V, psi, phi = L.relative_vector_space()
That's all. The values a
and b
correspond to
begin{align}
a&=\zeta_P=\zeta_{19}\ ,\\
b&=\zeta_N=\zeta_{18}\ ,\text{ so that }\\
c=\frac ba&=\zeta_{PN}
\end{align}
corresponds to a primitive root of order $PN=19\cdot 18$. ("This" works for relatively prime numbers $P,N$, the powers of $a$ and $b$ were copy+pasted from $\frac 1{18}- \frac 1{19}=\frac 1{18\cdot 19}$. For other $P,N$...)
The above code constructs the following objects:
sage: V
Vector space of dimension 6 over Cyclotomic Field of order 19 and degree 18
sage: psi
Isomorphism map:
From: Vector space of dimension 6 over Cyclotomic Field of order 19 and degree 18
To: Number Field in b with defining polynomial x^6 - x^3 + 1 over its base field
sage: phi
Isomorphism map:
From: Number Field in b with defining polynomial x^6 - x^3 + 1 over its base field
To: Vector space of dimension 6 over Cyclotomic Field of order 19 and degree 18
sage:
Above, $V$ is the (canonical) vector space $F^{\texttt{euler_phi}(N)}$.
We have the maps $\phi:!L\to V$ and $\psi:V\to !L$ (where the $!$ stays for the forgetful functor from field extensions of $F$ to vector spaces over $F$).
Code samples illustrating the way computations can be done:
sage: phi(1)
(1, 0, 0, 0, 0, 0)
sage: phi(b)
(0, 1, 0, 0, 0, 0)
sage: phi(b^2)
(0, 0, 1, 0, 0, 0)
sage: phi(b^3)
(0, 0, 0, 1, 0, 0)
sage: phi(b^4)
(0, 0, 0, 0, 1, 0)
sage: phi(b^5)
(0, 0, 0, 0, 0, 1)
sage: b^6
b^3 - 1
sage: phi(b^6)
(-1, 0, 0, 1, 0, 0)
This would be the solution, a structural, sage-specific solution, but it appears to be a very slow one.
And it is good possible, that this way to define L
in a tower is not the suitable way in application, where the direct definition via CyclotomicField( P*N )
is the natural one.
For these reasons, here is an other way to define elementwise an isomorphism. Letters have a slightly different meaning.
This gives:
P, N = 53, 52
F.<a> = CyclotomicField( P )
K.<c> = CyclotomicField( P*N )
L.<b> = CyclotomicField( N )
D = euler_phi( N )
W = F^D
def phi( k ):
"""For k in K deliver its image in W.
Here we simplify the program by considering F, K, a, c, N, P above as globals...
"""
w = W(0) # and we add, then finally return w
coeffs = k.lift().coefficients(sparse=False)
# if coeffs is [0,0,...,0, 1 on position L, 0,0,0,...,0]
# then this k corresponds to c^L
# rewrite c^L = (b/a)^L = b^L / a^L and reduce b^L (and a^L)
# here a^L = a^(L modulo P) and it can still be reduced, but we do not need this,
# since the coefficients in the final vector are in F.<a> and sage it computes for us.
# we need only to rewrite b^L in terms of 1, b, b^2, ... with powers < euler_phi(N).
for L in range(len(coeffs)):
if not coeffs[L]:
continue
bL_coeffs = (b^L).lift().coefficients(sparse=0) # i need padto= but...
bL_coeffs += [ QQ(0) for _ in range(D - len(bL_coeffs)) ]
w += coeffs[L] * a^(-L) * W( bL_coeffs )
return w
# test the above, e.g. the F-linearity
k = 777 + c + c^2 + c^20 + c^100
aK = c^N
struc = F.Hom( K, Fields() )( aK ) # a -> aK, structural morphism
for L in [1..9]:
print "check for phi(a^%s k) == a^%s phi(k) :: %s" % (L, L, bool( phi(struc(a^L)*k) == a^L*phi(k) ) )
The test gives:
check for phi(a^1 k) == a^1 phi(k) :: True
check for phi(a^2 k) == a^2 phi(k) :: True
check for phi(a^3 k) == a^3 phi(k) :: True
check for phi(a^4 k) == a^4 phi(k) :: True
check for phi(a^5 k) == a^5 phi(k) :: True
check for phi(a^6 k) == a^6 phi(k) :: True
check for phi(a^7 k) == a^7 phi(k) :: True
check for phi(a^8 k) == a^8 phi(k) :: True
check for phi(a^9 k) == a^9 phi(k) :: True
We have tested the $F$-multiplicativity for the ad-hoc map $\phi$ map $K\to W$ in some particular cases. For the additivity:
k1, k2 = K.random_element(), K.random_element()
phi(k1+k2) == phi(k1) + phi(k2)
This time i was lucky, got
True