Ryan Rueger

ryan@rueg.re / picture / key / home
aboutsummaryrefslogtreecommitdiffhomepage
path: root/theta_lib/basis_change/base_change_dim4.py
diff options
context:
space:
mode:
authorRyan Rueger <git@rueg.re>2025-03-01 20:25:41 +0100
committerRyan Rueger <git@rueg.re>2025-03-01 22:11:11 +0100
commitd40de259097c5e8d8fd35539560ca7c3d47523e7 (patch)
tree18e0f94350a2329060c2a19b56b0e3e2fdae56f1 /theta_lib/basis_change/base_change_dim4.py
downloadpegasis-d40de259097c5e8d8fd35539560ca7c3d47523e7.tar.gz
pegasis-d40de259097c5e8d8fd35539560ca7c3d47523e7.tar.bz2
pegasis-d40de259097c5e8d8fd35539560ca7c3d47523e7.zip
Initial Commit
Co-Authored-By: Damien Robert <Damien.Olivier.Robert+git@gmail.com> Co-Authored-By: Frederik Vercauteren <frederik.vercauteren@gmail.com> Co-Authored-By: Jonathan Komada Eriksen <jonathan.eriksen97@gmail.com> Co-Authored-By: Pierrick Dartois <pierrickdartois@icloud.com> Co-Authored-By: Riccardo Invernizzi <nidadoni@gmail.com> Co-Authored-By: Ryan Rueger <git@rueg.re> [0.01s] Co-Authored-By: Benjamin Wesolowski <benjamin@pasch.umpa.ens-lyon.fr> Co-Authored-By: Arthur Herlédan Le Merdy <ahlm@riseup.net> Co-Authored-By: Boris Fouotsa <tako.fouotsa@epfl.ch>
Diffstat (limited to 'theta_lib/basis_change/base_change_dim4.py')
-rw-r--r--theta_lib/basis_change/base_change_dim4.py152
1 files changed, 152 insertions, 0 deletions
diff --git a/theta_lib/basis_change/base_change_dim4.py b/theta_lib/basis_change/base_change_dim4.py
new file mode 100644
index 0000000..aaf685f
--- /dev/null
+++ b/theta_lib/basis_change/base_change_dim4.py
@@ -0,0 +1,152 @@
+from sage.all import *
+import itertools
+
+from ..theta_structures.theta_helpers_dim4 import multindex_to_index
+
+def bloc_decomposition(M):
+ I1=[0,1,2,3]
+ I2=[4,5,6,7]
+
+ A=M[I1,I1]
+ B=M[I2,I1]
+ C=M[I1,I2]
+ D=M[I2,I2]
+
+ return A,B,C,D
+
+def mat_prod_vect(A,I):
+ J=[]
+ for i in range(4):
+ J.append(0)
+ for k in range(4):
+ J[i]+=A[i,k]*I[k]
+ return tuple(J)
+
+def add_tuple(I,J):
+ K=[]
+ for k in range(4):
+ K.append(I[k]+J[k])
+ return tuple(K)
+
+def scal_prod_tuple(I,J):
+ s=0
+ for k in range(4):
+ s+=I[k]*J[k]
+ return s
+
+def red_mod_2(I):
+ J=[]
+ for x in I:
+ J.append(ZZ(x)%2)
+ return tuple(J)
+
+def choose_non_vanishing_index(C,D,zeta):
+ for I0 in itertools.product([0,1],repeat=4):
+ L=[0 for k in range(16)]
+ for J in itertools.product([0,1],repeat=4):
+ CJ=mat_prod_vect(C,J)
+ DJ=mat_prod_vect(D,J)
+ e=-scal_prod_tuple(CJ,DJ)-2*scal_prod_tuple(I0,DJ)
+
+ I0pDJ=add_tuple(I0,CJ)
+
+ L[multindex_to_index(red_mod_2(I0pDJ))]+=zeta**(ZZ(e))
+ for k in range(16):
+ if L[k]!=0:
+ return I0,L
+
+
+def base_change_theta_dim4(M,zeta):
+
+ Z4=Integers(4)
+ A,B,C,D=bloc_decomposition(M.change_ring(Z4))
+
+ I0,L0=choose_non_vanishing_index(C,D,zeta)
+
+
+ N=[L0]+[[0 for j in range(16)] for i in range(15)]
+ for I in itertools.product([0,1],repeat=4):
+ if I!=(0,0,0,0):
+ AI=mat_prod_vect(A,I)
+ BI=mat_prod_vect(B,I)
+ for J in itertools.product([0,1],repeat=4):
+ CJ=mat_prod_vect(C,J)
+ DJ=mat_prod_vect(D,J)
+
+ AIpCJ=add_tuple(AI,CJ)
+ BIpDJ=add_tuple(BI,DJ)
+
+ e=scal_prod_tuple(I,J)-scal_prod_tuple(AIpCJ,BIpDJ)-2*scal_prod_tuple(I0,BIpDJ)
+ N[multindex_to_index(I)][multindex_to_index(red_mod_2(add_tuple(AIpCJ,I0)))]+=zeta**(ZZ(e))
+
+ Fp2=zeta.parent()
+ return matrix(Fp2,N)
+
+def apply_base_change_theta_dim4(N,P):
+ Q=[]
+ for i in range(16):
+ Q.append(0)
+ for j in range(16):
+ Q[i]+=N[i,j]*P[j]
+ return Q
+
+def complete_symplectic_matrix_dim4(C,D,n=4):
+ Zn=Integers(n)
+
+ Col_I4=[matrix(Zn,[[1],[0],[0],[0]]),matrix(Zn,[[0],[1],[0],[0],[0]]),
+ matrix(Zn,[[0],[0],[1],[0],[0],[0]]),matrix(Zn,[[0],[0],[0],[1],[0],[0],[0]])]
+
+ L_DC=block_matrix([[D.transpose(),-C.transpose()]])
+ Col_AB_i=L_DC.solve_right(Col_I4[0])
+ A_t=Col_AB_i[[0,1,2,3],0].transpose()
+ B_t=Col_AB_i[[4,5,6,7],0].transpose()
+
+ for i in range(1,4):
+ F=block_matrix(2,1,[L_DC,block_matrix(1,2,[B_t,-A_t])])
+ Col_AB_i=F.solve_right(Col_I4[i])
+ A_t=block_matrix(2,1,[A_t,Col_AB_i[[0,1,2,3],0].transpose()])
+ B_t=block_matrix(2,1,[B_t,Col_AB_i[[4,5,6,7],0].transpose()])
+
+ A=A_t.transpose()
+ B=B_t.transpose()
+
+ M=block_matrix([[A,C],[B,D]])
+
+ return M
+
+def random_symmetric_matrix(n,r):
+ Zn=Integers(n)
+ M=zero_matrix(Zn,r,r)
+ for i in range(r):
+ M[i,i]=randint(0,n-1)
+ for i in range(r):
+ for j in range(i+1,r):
+ M[i,j]=randint(0,n-1)
+ M[j,i]=M[i,j]
+ return M
+
+
+def random_symplectic_matrix(n):
+ Zn=Integers(n)
+
+ C=random_symmetric_matrix(n,4)
+ Cp=random_symmetric_matrix(n,4)
+
+ A=random_matrix(Zn,4,4)
+ while not A.is_invertible():
+ A=random_matrix(Zn,4,4)
+
+ tA_inv=A.inverse().transpose()
+ ACp=A*Cp
+ return block_matrix([[ACp,A],[C*ACp-tA_inv,C*A]])
+
+def is_symplectic_matrix_dim4(M):
+ A,B,C,D=bloc_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(4):
+ return False
+ return True
+