Ryan Rueger

ryan@rueg.re / picture / key / home
aboutsummaryrefslogtreecommitdiffhomepage
path: root/theta_lib/basis_change/base_change_dim2.py
diff options
context:
space:
mode:
Diffstat (limited to 'theta_lib/basis_change/base_change_dim2.py')
-rw-r--r--theta_lib/basis_change/base_change_dim2.py150
1 files changed, 0 insertions, 150 deletions
diff --git a/theta_lib/basis_change/base_change_dim2.py b/theta_lib/basis_change/base_change_dim2.py
deleted file mode 100644
index 4994529..0000000
--- a/theta_lib/basis_change/base_change_dim2.py
+++ /dev/null
@@ -1,150 +0,0 @@
-from sage.all import *
-
-import itertools
-
-def complete_symplectic_matrix_dim2(C, D, n=4):
- Zn = Integers(n)
-
- # Compute first row
- F = D.stack(-C).transpose()
- xi = F.solve_right(vector(Zn, [1, 0]))
-
- # Rearrange TODO: why?
- v = vector(Zn, [xi[2], xi[3], -xi[0], -xi[1]])
-
- # Compute second row
- F2 = F.stack(v)
- yi = F2.solve_right(vector(Zn, [0, 1, 0]))
- M = Matrix(Zn,
- [
- [xi[0], yi[0], C[0, 0], C[0, 1]],
- [xi[1], yi[1], C[1, 0], C[1, 1]],
- [xi[2], yi[2], D[0, 0], D[0, 1]],
- [xi[3], yi[3], D[1, 0], D[1, 1]],
- ],
- )
-
- return M
-
-def block_decomposition(M):
- """
- Given a 4x4 matrix, return the four 2x2 matrices as blocks
- """
- A = M.matrix_from_rows_and_columns([0, 1], [0, 1])
- B = M.matrix_from_rows_and_columns([2, 3], [0, 1])
- C = M.matrix_from_rows_and_columns([0, 1], [2, 3])
- D = M.matrix_from_rows_and_columns([2, 3], [2, 3])
- return A, B, C, D
-
-def is_symplectic_matrix_dim2(M):
- A, B, C, D = block_decomposition(M)
- if B.transpose() * A != A.transpose() * B:
- return False
- if C.transpose() * D != D.transpose() * C:
- return False
- if A.transpose() * D - B.transpose() * C != identity_matrix(2):
- return False
- return True
-
-def base_change_theta_dim2(M, zeta):
- r"""
- Computes the matrix N (in row convention) of the new level 2
- theta coordinates after a symplectic base change of A[4] given
- by M\in Sp_4(Z/4Z). We have:
- (theta'_i)=N*(theta_i)
- where the theta'_i are the new theta coordinates and theta_i,
- the theta coordinates induced by the product theta structure.
- N depends on the fourth root of unity zeta=e_4(Si,Ti) (where
- (S0,S1,T0,T1) is a symplectic basis if A[4]).
-
- Inputs:
- - M: symplectic base change matrix.
- - zeta: a primitive 4-th root of unity induced by the Weil-pairings
- of the symplectic basis of A[4].
-
- Output: Matrix N of base change of theta-coordinates.
- """
- # Split 4x4 matrix into 2x2 blocks
- A, B, C, D = block_decomposition(M)
-
- # Initialise N to 4x4 zero matrix
- N = [[0 for _ in range(4)] for _ in range(4)]
-
- def choose_non_vanishing_index(C, D, zeta):
- """
- Choice of reference non-vanishing index (ir0,ir1)
- """
- for ir0, ir1 in itertools.product([0, 1], repeat=2):
- L = [0, 0, 0, 0]
- for j0, j1 in itertools.product([0, 1], repeat=2):
- k0 = C[0, 0] * j0 + C[0, 1] * j1
- k1 = C[1, 0] * j0 + C[1, 1] * j1
-
- l0 = D[0, 0] * j0 + D[0, 1] * j1
- l1 = D[1, 0] * j0 + D[1, 1] * j1
-
- e = -(k0 + 2 * ir0) * l0 - (k1 + 2 * ir1) * l1
- L[ZZ(k0 + ir0) % 2 + 2 * (ZZ(k1 + ir1) % 2)] += zeta ** (ZZ(e))
-
- # Search if any L value in L is not zero
- if any([x != 0 for x in L]):
- return ir0, ir1
-
- ir0, ir1 = choose_non_vanishing_index(C, D, zeta)
-
- for i0, i1, j0, j1 in itertools.product([0, 1], repeat=4):
- k0 = A[0, 0] * i0 + A[0, 1] * i1 + C[0, 0] * j0 + C[0, 1] * j1
- k1 = A[1, 0] * i0 + A[1, 1] * i1 + C[1, 0] * j0 + C[1, 1] * j1
-
- l0 = B[0, 0] * i0 + B[0, 1] * i1 + D[0, 0] * j0 + D[0, 1] * j1
- l1 = B[1, 0] * i0 + B[1, 1] * i1 + D[1, 0] * j0 + D[1, 1] * j1
-
- e = i0 * j0 + i1 * j1 - (k0 + 2 * ir0) * l0 - (k1 + 2 * ir1) * l1
- N[i0 + 2 * i1][ZZ(k0 + ir0) % 2 + 2 * (ZZ(k1 + ir1) % 2)] += zeta ** (ZZ(e))
-
- return Matrix(N)
-
-def montgomery_to_theta_matrix_dim2(zero12,N=identity_matrix(4),return_null_point=False):
- r"""
- Computes the matrix that transforms Montgomery coordinates on E1*E2 into theta coordinates
- with respect to a certain theta structure given by a base change matrix N.
-
- Input:
- - zero12: theta-null point for the product theta structure on E1*E2[2]:
- zero12=[zero1[0]*zero2[0],zero1[1]*zero2[0],zero1[0]*zero2[1],zero1[1]*zero2[1]],
- where the zeroi are the theta-null points of Ei for i=1,2.
- - N: base change matrix from the product theta-structure.
- - return_null_point: True if the theta-null point obtained after applying N to zero12 is returned.
-
- Output:
- - Matrix for the change of coordinates:
- (X1*X2,Z1*X2,X1*Z2,Z1*Z2)-->(theta_00,theta_10,theta_01,theta_11).
- - If return_null_point, the theta-null point obtained after applying N to zero12 is returned.
- """
-
- Fp2=zero12[0].parent()
-
- M=zero_matrix(Fp2,4,4)
-
- for i in range(4):
- for j in range(4):
- M[i,j]=N[i,j]*zero12[j]
-
- M2=[]
- for i in range(4):
- M2.append([M[i,0]+M[i,1]+M[i,2]+M[i,3],-M[i,0]-M[i,1]+M[i,2]+M[i,3],-M[i,0]+M[i,1]-M[i,2]+M[i,3],M[i,0]-M[i,1]-M[i,2]+M[i,3]])
-
- if return_null_point:
- null_point=[M[i,0]+M[i,1]+M[i,2]+M[i,3] for i in range(4)]
- return Matrix(M2), null_point
- else:
- return Matrix(M2)
-
-def apply_base_change_theta_dim2(N,P):
- Q=[]
- for i in range(4):
- Q.append(0)
- for j in range(4):
- Q[i]+=N[i,j]*P[j]
- return Q
-