27
27
from .divisors import Divisors , DivisorsElement
28
28
from .meromorphic import *
29
29
from .theta import *
30
- from .util import muted
30
+ from .util import muted , our_sqrt
31
31
32
32
infinity = Infinity
33
33
@@ -100,17 +100,20 @@ def uniq(lst):
100
100
101
101
102
102
@muted
103
- @cached_function
104
103
def find_eigenvector_matrix (g ):
104
+ K = g .parent ().base_ring ()
105
105
t = g .trace ()
106
106
n = g .determinant ()
107
- delta = (t * t - 4 * n ).sqrt ()
108
- vaps = sorted ([(t + delta ) / 2 , (t - delta ) / 2 ], key = lambda o : o .valuation ())
109
- veps = sum (((g - l ).right_kernel ().basis () for l in vaps ), [])
107
+ delta = (t * t - K (4 ) * n ).sqrt ()
108
+ vaps = sorted ([(t + delta ) / K (2 ), (t - delta ) / K (2 )], key = lambda o : o .valuation ())
109
+ assert len (vaps ) == 2
110
+ veps = []
111
+ for l in vaps :
112
+ B = g - l
113
+ veps .append ((B [0 ,1 ], - B [0 ,0 ])) # The right kernel of a rank-1 2x2 matrix
110
114
return g .matrix_space ()(veps ).transpose ()
111
115
112
116
113
- @cached_function
114
117
def find_parameter (g , ball , pi = None , check = True ):
115
118
if pi is None :
116
119
pi = g .parent ().base_ring ().uniformizer ()
@@ -210,6 +213,8 @@ def theta_naive(self, m, a=ZZ(0), b=ZZ(1), z=None, gamma=None, **kwargs):
210
213
K = self .K
211
214
if z is Infinity :
212
215
return K (1 )
216
+ if isinstance (z , Divisors ): # z is a divisor!
217
+ return prod (self .theta_naive (m , a , b , P , gamma , ** kwargs )** n for P , n in z )
213
218
if gamma is not None :
214
219
if b != ZZ (1 ):
215
220
raise ValueError ("If gamma is specified, then b should not" )
@@ -225,9 +230,9 @@ def theta_naive(self, m, a=ZZ(0), b=ZZ(1), z=None, gamma=None, **kwargs):
225
230
can_stop = True
226
231
for _ , g in self .enumerate_group_elements (i ):
227
232
ga = act (g , a )
228
- tmp1 = K (1 ) if ga is Infinity else z - ga
233
+ tmp1 = K (1 ) if ga is Infinity or z == ga else z - ga
229
234
gb = act (g , b )
230
- tmp2 = K (1 ) if gb is Infinity else z - gb
235
+ tmp2 = K (1 ) if gb is Infinity or z == gb else z - gb
231
236
new_num *= tmp1
232
237
new_den *= tmp2
233
238
try :
@@ -353,7 +358,7 @@ def construct_tree(self, level):
353
358
return self .NJtree
354
359
355
360
@cached_method
356
- @muted
361
+ # @muted # DEBUG
357
362
def fundamental_domain (self , level = 1 , check = True ):
358
363
while True :
359
364
level += 1
@@ -364,7 +369,7 @@ def fundamental_domain(self, level=1, check=True):
364
369
except ValueError as e :
365
370
verbose (str (e ))
366
371
367
- @muted
372
+ # @muted # DEBUG
368
373
def _fundamental_domain (self , i0 = None , check = True ):
369
374
tree = self .NJtree
370
375
if i0 is None :
@@ -546,13 +551,14 @@ def test_fundamental_domain(self):
546
551
gens = self ._generators
547
552
test_fundamental_domain (gens , balls )
548
553
549
- def balls (self ):
554
+ def balls (self , generators = None ):
550
555
try :
551
556
return self ._balls
552
557
except AttributeError :
553
558
pass
554
559
K = self .base_ring ()
555
- generators = self ._generators
560
+ if generators is None :
561
+ generators = self ._generators
556
562
G = PreSchottkyGroup (K , generators )
557
563
gp = G .group ()
558
564
good_gens , good_balls , _ = G .fundamental_domain ()
@@ -608,22 +614,18 @@ def a_point(self):
608
614
return x0
609
615
raise RuntimeError ("Reached maximum iterations (100)" )
610
616
611
- def find_point (self , gamma , eps = 1 , idx = None ):
617
+ def find_point (self , gamma , eps = 1 , idx = None , check = True ):
612
618
balls = self .balls ()
613
619
gens = self .gens_extended ()
614
620
if idx is not None :
615
621
B = balls [- idx ]
616
622
if idx > 0 :
617
623
if self ._generators [idx - 1 ] != gamma :
618
624
B1 = next (balls [- i ] for i , g in gens if g == gamma )
619
- # print(f'!! {B = } but {B1 = }')
620
- # print(balls)
621
625
B = B1
622
626
else :
623
627
if self ._generators [- idx - 1 ] ** - 1 != gamma :
624
628
B1 = next (balls [- i ] for i , g in gens if g == gamma )
625
- # print(f'!! {B = } but {B1 = }')
626
- # print(balls)
627
629
B = B1
628
630
else :
629
631
B = next (balls [- i ] for i , g in gens if g == gamma )
@@ -632,11 +634,10 @@ def find_point(self, gamma, eps=1, idx=None):
632
634
except TypeError :
633
635
raise RuntimeError (
634
636
"Fundamental domain has balls with fractional radius. \
635
- Try with a quadratic (ramified) extension."
637
+ Try with a quadratic (ramified) extension."
636
638
)
637
- test = lambda x : self .in_fundamental_domain (x , strict = False )
638
-
639
- try :
639
+ if check :
640
+ test = lambda x : self .in_fundamental_domain (x , strict = False )
640
641
if not test (ans ):
641
642
raise RuntimeError (
642
643
f"{ ans = } should be in fundamental domain, but it is not."
@@ -646,11 +647,6 @@ def find_point(self, gamma, eps=1, idx=None):
646
647
raise RuntimeError (
647
648
f"gamma * ans = { ga } should be in fundamental domain, but it is not."
648
649
)
649
- except RuntimeError :
650
- new_idx = - idx if idx is not None else None
651
- ginv = gamma ** - 1
652
- ans = self .find_point (ginv , eps , new_idx )
653
- return act (ginv , ans )
654
650
return ans
655
651
656
652
def to_fundamental_domain (self , x ):
@@ -731,7 +727,7 @@ def find_equivalent_divisor(self, D):
731
727
if e == 0 :
732
728
continue
733
729
zz = self .find_point (g , idx = i + 1 )
734
- ans - = Div ([(e , zz ), (- e , act (g , zz ))])
730
+ ans + = Div ([(- e , zz ), (e , act (g , zz ))])
735
731
return ans
736
732
737
733
def theta (self , prec , a , b = None , ** kwargs ):
@@ -767,9 +763,7 @@ def theta(self, prec, a, b=None, **kwargs):
767
763
s = kwargs .pop ("s" , None )
768
764
if s is not None :
769
765
D0 += s * D0
770
- recursive = kwargs .get ("recursive" , True )
771
- if recursive :
772
- D0 = self .find_equivalent_divisor (D0 )
766
+ D0 = self .find_equivalent_divisor (D0 )
773
767
ans = ThetaOC (self , a = D0 , b = None , prec = prec , base_ring = K , ** kwargs )
774
768
z = kwargs .pop ("z" , None )
775
769
improve = kwargs .pop ("improve" , True )
@@ -788,32 +782,37 @@ def u_function(self, gamma, prec, a=None, **kwargs):
788
782
if z is None :
789
783
kwargs .pop ("z" , None )
790
784
return lambda z : prod (
791
- self ._u_function (gens [ abs (i ) - 1 ] , prec , a = a )(z ) ** ZZ (sgn (i ))
785
+ self ._u_function (abs (i ) - 1 , prec , a = a )(z ) ** ZZ (sgn (i ))
792
786
for i in wd
793
787
)
794
788
return prod (
795
- self ._u_function (gens [ abs (i ) - 1 ] , prec , a = a )(z ) ** ZZ (sgn (i ))
789
+ self ._u_function (abs (i ) - 1 , prec , a = a )(z ) ** ZZ (sgn (i ))
796
790
for i in wd
797
791
)
792
+ naive = kwargs .get ('naive' , None )
798
793
if z is None :
799
- return lambda z : self ._u_function (gens [ wd [0 ] - 1 ] , prec , a = a )(z )
794
+ return lambda z : self ._u_function (wd [0 ] - 1 , prec , a = a , naive = naive )(z )
800
795
else :
801
- return self ._u_function (gens [ wd [0 ] - 1 ] , prec , a = a )(z )
796
+ return self ._u_function (wd [0 ] - 1 , prec , a = a , naive = naive )(z )
802
797
803
798
@cached_method
804
- def _u_function (self , gamma , prec , a ):
799
+ def _u_function (self , i , prec , a , naive = False ):
805
800
r"""
806
801
Compute u_gamma
807
802
"""
808
- (i ,) = self .word_problem (gamma )
809
- assert i > 0
803
+ gamma = self ._generators [i ]
810
804
if a is None :
811
- a = self .a_point () # self.find_point(gamma, idx=g)
812
- a = self .base_ring ()(1 ) * a
813
- K = a .parent ()
805
+ a = self .find_point (gamma , idx = i ) # self.a_point()
806
+ K = a .parent ()
807
+ else :
808
+ a = self .base_ring ()(1 ) * a
809
+ K = a .parent ()
814
810
D = self .find_equivalent_divisor (Divisors (K )([(1 , a ), (- 1 , act (gamma , a ))]))
815
- ans = ThetaOC (self , a = D , b = None , prec = prec , base_ring = K )
816
- ans = ans .improve (prec )
811
+ if naive :
812
+ return lambda z : self .theta_naive (prec , z = z , a = a , gamma = gamma )
813
+ else :
814
+ ans = ThetaOC (self , a = D , b = None , prec = prec , base_ring = K )
815
+ ans = ans .improve (prec )
817
816
return ans
818
817
819
818
@cached_method
0 commit comments