-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathspinor_norm.m
146 lines (141 loc) · 4.55 KB
/
spinor_norm.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
intrinsic Reflect(v,N) -> AlgMatElt
{ Compute reflection of V with norm N }
n:=Ncols(v);
ret:=ZeroMatrix(Rationals(), n, n);
for i in [1..n] do
w:=ZeroMatrix(Rationals(), 1, n);
w[1,i]:=1;
num:=2*w*N*Transpose(v)*(v*N*(Transpose(v)))^(-1);
ret[i]:=(w-num*v)[1];
end for;
assert ret*N*Transpose(ret) eq N;
return ret;
end intrinsic;
//Implementation of spinor norm calculations
intrinsic SpinorNorm(M::Mtrx, V::Mtrx) -> Rational
{ Compute the spinor norm of the isometry M with the inner product V }
n:=Ncols(M);
V:=MatrixRing(Rationals(),n)!V;
M:=MatrixRing(Rationals(),n)!M;
assert M*V*Transpose(M) eq V;
G, T, _ := OrthogonalizeGram(V);
//Rows of T are an orthonormal basis for original inner product: apply
//algorithm
retval:=Matrix(Rationals(), 1, 1, [1]);
transform:=M;
for i in [1..n] do
vec := T[i];
tmp := vec*transform-vec;
asb:=ZeroMatrix(Rationals(), 1, n);
asb[1]:=tmp;
if not (asb eq 0) then
transform:=transform*Reflect(asb, V);
retval := retval*asb*V*Transpose(asb);
end if;
end for;
return retval[1,1];
end intrinsic;
intrinsic SqRatClass(x::FldRatElt)->FldRatElt
{ Obvious element in square class of a rational }
return Squarefree(Numerator(x))*Squarefree(Denominator(x));
end intrinsic;
intrinsic ThetaIsoms(N::Lat)-> []
{ Compute theta of isometries of N }
if assigned N`ThetaIsoms then
return N`ThetaIsoms;
end if;
B:=Matrix(Rationals(), BasisMatrix(N));
inner:=Matrix(Rationals(), InnerProductMatrix(N));
retval:=[];
for T in Generators(AutomorphismGroup(N)) do
if Determinant(T) eq 1 then
Append(~retval, SqRatClass(SpinorNorm(B^(-1)*Matrix(Rationals(), T)*B, 1/2*inner)));
else
Append(~retval, SqRatClass(SpinorNorm(-1*B^(-1)*Matrix(Rationals(), T)*B, 1/2*inner)));
end if;
end for;
N`ThetaIsoms := retval;
return retval;
end intrinsic;
intrinsic ThetaEquivalent(M::Lat, N::Lat)->Bool
{ Determine of M and N are theta-equivalent }
assert InnerProductMatrix(M) eq InnerProductMatrix(N);
test, T :=IsIsometric(M,N);
if test eq false then
return false;
end if;
//TODO: cache theta image of automorphism group via some structs
B1:=Matrix(Rationals(),BasisMatrix(M));
B2:=Matrix(Rationals(), BasisMatrix(N));
T:=Matrix(Rationals(), T);
//T takes coordinates on N and turns them to coordinates on M
ambient_iso:=B2^(-1)*T*B1;
if Determinant(ambient_iso) eq -1 then
ambient_iso := -1*ambient_iso;
end if;
assert ambient_iso*InnerProductMatrix(M)*Transpose(ambient_iso) eq InnerProductMatrix(M);
theta:=SqRatClass(SpinorNorm(ambient_iso, 1/2*InnerProductMatrix(M)));
//Use isometries on N to reduce: cf Tornaria thesis
//This is what we want to cache
//Are we sure we used the right one...?
im_aut:=ThetaIsoms(N);
//Now decide if theta is in the image of im_aut via linear algebra;
if #im_aut eq 0 then
return theta eq 1;
end if;
if not(PrimeFactors(theta) subset PrimeFactors(&* im_aut)) then
return false;
end if;
primes:=PrimeFactors(&* im_aut);
n:=#primes;
mat:=ZeroMatrix(GaloisField(2), #im_aut, n);
vec:=Vector(GaloisField(2), #primes, [0 : i in primes]);
i:=1;
for p in primes do
j:=1;
for im in im_aut do
if (im mod p) eq 0 then
mat[j, i]:= 1;
end if;
j := j+1;
end for;
if (theta mod p) eq 0 then
vec[i]:=1;
i:=i+1;
end if;
end for;
if IsConsistent(mat, vec) then
return true;
else
return false;
end if;
end intrinsic;
intrinsic VectWNorm(V, p)-> AlgMatElt
{ Return vector of norm p}
J:=DiagonalJoin(V, Matrix(Rationals(), 1, 1, [-p]));
n:=Ncols(J);
vec:=BasisMatrix(IsotropicSubspace(J));
for row in Rows(vec) do
if not(row[n] eq 0) then
retval:=Matrix(Rationals(), 1, n-1, [row[i]/row[n]: i in [1..n-1]]);
assert (retval*V*Transpose(retval))[1,1] eq p;
return retval, true;
end if;
end for;
return false, false;
end intrinsic;
//Todo: make reliable
intrinsic SpinorOperation(M::Lat, p)-> Lat
{ Act on the basis of M by reflection by a vector of norm p }
Qform:=1/2*InnerProductMatrix(M);
veca, succa:=VectWNorm(Qform, 2);
vecb, succb:=VectWNorm(Qform, 2*p);
if succa and succb then
transform:=Reflect(veca, Qform)*Reflect(vecb, Qform);
else
assert false;
end if;
basis:=Matrix(Rationals(),BasisMatrix(M));
lat:=LatticeWithBasis(basis*transform, 2*Qform);
return lat;
end intrinsic;