Ticket #11380: trac_11380_cont_frac_quadratic_2.patch
| File trac_11380_cont_frac_quadratic_2.patch, 31.1 KB (added by mmasdeu, 2 years ago) |
|---|
-
sage/rings/number_field/number_field_element_quadratic.pyx
# HG changeset patch # User Marc Masdeu <masdeu@math.columbia.edu> # Date 1306446759 14400 # Node ID 0c92a2edd152e4089378686528b1139a0c9f6fb2 # Parent b97e6e8ba4a1155e42d5b8c355e065c76ca1add8 trac 11380: Fixed minor issues to make it (much) faster. diff -r b97e6e8ba4a1 -r 0c92a2edd152 sage/rings/number_field/number_field_element_quadratic.pyx
a b 1416 1416 P=QuadraticContinuedFraction(F,Nbound,Tbound) 1417 1417 P.solve() 1418 1418 F.__continued_fraction_cache=P 1419 print 'Done with precomputations...'1419 print 'Done with precomputations...' 1420 1420 v=[] 1421 1421 knm1=self 1422 1422 kn=1 -
deleted file sage/rings/number_field/quadratic_continued_fraction.py
diff -r b97e6e8ba4a1 -r 0c92a2edd152 sage/rings/number_field/quadratic_continued_fraction.py
+ - 1 2 ##########################################3 #4 # Added by mmasdeu5 # Authors: Xevi Guitart and Marc Masdeu6 #7 ##########################################8 9 from sage.matrix.constructor import Matrix10 from sage.rings.all import RealField11 from sage.structure.sage_object import SageObject12 from sage.misc.all import union13 from sage.functions.all import (floor,ceil)14 from sage.rings.all import IntegerRing15 from sage.rings.all import RationalField16 from collections import deque17 18 class Regions(SageObject):19 def __init__(self,parent):20 self._regions=dict([])21 self._F=parent._F22 self._eps=parent._eps23 self._epsto=[self._F(1)]24 self.fundom_rep=parent.fundom_rep25 self.embed=parent.embed26 self._parent=parent27 self._N=1 # Means that we have regions up to _N-1=0, so none28 self._area=self._parent._Rw29 30 def get_regions(self,B):31 regions=self._regions32 if(B>self._N):33 F=self._F34 eps=self._eps35 newelts=dict([(IntegerRing()(n),[I.gens_reduced()[0] for I in v if I.is_principal()]) for n,v in self._F.ideals_of_bdd_norm(B-1).iteritems() if n>=self._N])36 self._N=B37 for nn in range(len(self._epsto),B):38 self._epsto.append(self._epsto[nn-1]*eps)39 for nn,v in newelts.iteritems():40 assert not regions.has_key(nn)41 regions[nn]=[]42 for q in v:43 invden=1/q44 invden_red=self.fundom_rep(invden)45 q0=invden_red-invden46 m_invden=-invden47 m_invden_red=self.fundom_rep(m_invden)48 m_q0=m_invden_red-m_invden49 a=invden_red[0]50 b=invden_red[1]51 am=m_invden_red[0]52 bm=m_invden_red[1]53 54 regions[nn].extend([[invden_red,[q0,q],Region(self.embed(invden_red),RealField()(1/nn)),[a,b],nn],[m_invden_red,[m_q0,-q],Region(self.embed(m_invden_red),RealField()(1/nn)),[am,bm],nn]])55 for jj in range(1,nn):56 x=self._epsto[jj]*invden57 x_red=self.fundom_rep(x)58 x_red_minus=self.fundom_rep(-x_red)59 60 regs=regions[nn]61 if(x_red==regs[0][0] or x_red_minus==regs[0][0]):62 continue63 64 q0_minus=x_red_minus+x65 q0=x_red-x66 q1=1/x67 a=x_red[0]68 b=x_red[1]69 am=x_red_minus[0]70 bm=x_red_minus[1]71 regions[nn].extend([[x_red,[q0,q1],Region(self.embed(x_red),RealField()(1/nn)),[a,b],nn],[x_red_minus,[q0_minus,-q1],Region(self.embed(x_red_minus),RealField()(1/nn)),[am,bm],nn]])72 73 else:74 # We have all the required regions75 pass76 return [reg for nn,lst in regions.iteritems() if nn<B for reg in lst]77 78 class Hole(SageObject):79 def __init__(self,parent,v,depth=0):80 self._parent=parent81 if isinstance(v,list):82 #Input in as [xmin,ymin,xmax,ymax]83 if not (v[0]<v[2] and v[1]<v[3]):84 print 'The input should be of the form [xmin,ymin,xmax,ymax], with xmin<xmax and ymin<ymax.'85 assert(0)86 (self.xmin,self.ymin,self.xmax,self.ymax)=v87 elif(isinstance(v,Hole)):88 self.xmin=v.xmin89 self.ymin=v.ymin90 self.xmax=v.xmax91 self.ymax=v.ymax92 self.size=max([self.xmax-self.xmin,self.ymax-self.ymin])93 self._corners=None94 self._depth=depth95 96 def depth(self):97 return self._depth98 99 def corners(self):100 if self._corners==None:101 self._corners=[(self.xmin,self.ymin),(self.xmin,self.ymax),(self.xmax,self.ymax),(self.xmax,self.ymin)]102 return self._corners103 104 def plot(self,color='blue'):105 return plot(polygon(self.corners()))106 107 def overlaps_fundamental_domain(self):108 return any([self._parent.in_fundamental_domain(x) for x in self.corners()])109 110 def _repr_(self):111 my_str='Hole with corners=('+str(self.xmin)+','+str(self.ymin)+'),('+str(self.xmax)+','+str(self.ymax)+')'112 return my_str113 114 class Region(SageObject):115 def __init__(self,center,radius):116 assert(isinstance(center,tuple))117 self._center=center118 radius=abs(radius)119 if(radius>1):120 print radius121 print center122 assert(0)123 self._radius=radius124 def radius(self):125 return self._radius126 def center(self):127 return self._center128 129 def plot_center(self,color='red'):130 return plot(point(self._center,color=color))131 132 def plot(self,color='red'):133 r=2*self._radius134 a=self._center[0]135 b=self._center[1]136 Pts=[(a,b+r),(a+r,b),(a,b-r),(a-r,b)]137 return plot(polygon(Pts),color=color)138 139 def contains_point(self,P):140 return abs((P[0]-self._center[0])*(P[1]-self._center[1]))<self._radius141 142 def contains_hole(self,h):143 return all([self.contains_point(P) for P in h.corners()])144 145 class QuadraticContinuedFraction(SageObject):146 def __init__(self,F,Nbound=50,Tbound=5):147 self._F=F148 self._disc=self._F.discriminant()149 self._w=self._F.gen()150 self._eps=self._F.units()[0]151 self._Phi=self._F.real_embeddings(prec=300)152 153 # We assume here that Phi orders the embeddings to that154 # Phi[1] is the largest155 self._Rw=self._Phi[1](self._w)156 self._Rwconj=self._Phi[0](self._w)157 158 self._used_regions=[]159 self._Nboundmin=2160 self._Nboundmax=Nbound161 self._Nboundinc=1162 self._Nbound=Nbound163 self._epsto=[self._F(1)]164 self._Dmax=self.embed(self._w)165 self._Tbound=Tbound166 self._ranget=sorted(range(-self._Tbound,self._Tbound+2),key=abs)167 self._M=Matrix(RealField(),2,2,[1,self._Rw,1,self._Rwconj]).inverse()168 self.initialize_fundom()169 self._master_regs=Regions(self)170 self._maxdepth=0171 '''Takes an element in the number field F and returns172 y in the fundamental domain such that such that (x-y) belongs to R'''173 def fundom_rep(self,x,y=None):174 if(y==None):175 x1=x[0]176 x2=x[1]177 else: # Assume these are coordinates a,b of a+bw178 x1=x179 x2=y180 d=x1.floor()+self._w*(x2.floor())181 return x-d182 183 # Returns a function that, given a t-value, will return a range of a-values. The arguments specify the region that we want to cover184 def rangea_gen(self,xmin,ymin,xmax,ymax):185 wprime0=self._Rw186 wprime1=self._Rwconj187 def rangea(t):188 tp0=t*wprime0189 tp1=t*wprime1190 return sorted(list(union(range(floor(xmin-1-tp0-wprime0),ceil(xmax-tp0)+1),range(floor(ymin-1-tp1-wprime1),ceil(ymax-tp1)+1))),key=abs)191 return rangea192 193 def in_fundamental_domain(self,P):194 A=self._M*Matrix(RealField(),2,1,[P[0],P[1]])195 return A[0,0]>=0 and A[0,0]<1 and A[1,0]>=0 and A[1,0]<1196 197 '''Given x in F (or in R) embeds it into R^2198 '''199 def embed(self,x):200 return (self._Phi[1](x),self._Phi[0](x))201 202 def embed_coords(self,a,b):203 return ((a+self._Rw*b,a+self._Rwconj*b))204 205 '''Build the fundamental domain206 '''207 def initialize_fundom(self):208 F=self._F209 Pts=[self.embed(a+b*self._w) for a in [0,1] for b in [0,1]]210 xmin=min([x[0] for x in Pts])211 xmax=max([x[0] for x in Pts])212 ymin=min([x[1] for x in Pts])213 ymax=max([x[1] for x in Pts])214 215 self._aplusbomega=dict([])216 rangea=self.rangea_gen(xmin-1,ymin-1,xmax+1,ymax+1)217 for b in self._ranget:218 bw=b*self._w219 for a in rangea(b):220 self._aplusbomega[(a,b)]=a+bw221 222 dx=RealField()(0.499)223 dy=dx224 Nx=ceil((xmax-xmin)/dx)225 Ny=ceil((ymax-ymin)/dy)226 self._holes=deque([])227 for ii in range(Nx):228 for jj in range(Ny):229 self._holes.append(Hole(self,[xmin+ii*dx,ymin+jj*dy,xmin+(ii+1)*dx,ymin+(jj+1)*dy]))230 231 232 def plot_holes(self):233 myplot=plot([])234 for h in self._holes:235 myplot+=h.plot()236 return myplot237 238 def remaining_holes(self):239 return len(self._holes)240 241 def test_regions(self,corners,at_least_one,embed_coords,regions,Region,aplusbomega,ranget,rangea):242 ii=0243 NumRegions=len(regions)244 #print "Looking at ",NumRegions," regions..."245 atws=[[aplusbomega[(a,b)],embed_coords(a,b),[a,b]] for b in ranget for a in rangea(b)]246 for ii in range(NumRegions):247 reg=regions[ii]248 for inc in atws:249 passed=[False for ii in range(4)]250 a=inc[1][0]251 b=inc[1][1]252 for ii,P in enumerate(corners):253 if reg[2].contains_point((P[0]-a,P[1]-b)):254 at_least_one[ii]=True255 passed[ii]=True256 else:257 break258 if(all(passed)):259 rparts=reg[3]260 incparts=inc[2]261 return [reg[0]+inc[0],[reg[1][0]+inc[0],reg[1][1]],Region(embed_coords(rparts[0]+incparts[0],rparts[1]+incparts[1]),reg[2].radius()),reg[3],reg[4]]262 return None263 264 # Given a hole, returns:265 # -2 if at least one of the points is not covered by the regions266 # -1 if no region covers all the points267 # 0 if the a region can cover all the points268 def evaluate_hole(self,h,verifying=False,maxdepth=-1):269 if not h.overlaps_fundamental_domain():270 return 0271 regs=[[],[],[],[]]272 data=[]273 used=self._used_regions274 corners=h.corners()275 atws=[]276 w=self._w277 if(verifying):278 at_least_one=[False,False,False,False]279 280 for reg in used:281 passed=True282 for ii,P in enumerate(corners):283 if not reg[2].contains_point(P):284 passed=False285 if(not verifying):286 break287 elif verifying:288 at_least_one[ii]=True289 if(passed):290 return 0291 292 if(verifying):293 if(all(at_least_one)):294 return -1295 else:296 if(h.depth()>maxdepth):297 return -2298 else:299 return -1300 301 rangea=self.rangea_gen(h.xmin,h.ymin,h.xmax,h.ymax)302 at_least_one=[False,False,False,False]303 304 l=100305 B=ceil(4/(l*(h.size**2)))306 B=max([self._Nboundmin,B])307 #print 'B=',B,'Size ~ 10^',RealField(prec=10)((log(h.size)/log(10)))308 regions=self._master_regs.get_regions(min([B,self._Nbound]))309 nreg=self.test_regions(corners,at_least_one,embed_coords=self.embed_coords,regions=regions,Region=Region,aplusbomega=self._aplusbomega, ranget=self._ranget,rangea=rangea)310 if(nreg!=None):311 used.append(nreg)312 return 0313 314 return -1315 316 def evaluate_pointxy(self,x,y):317 P=(x,y)318 for reg in self._used_regions:319 if(reg[2].contains_point(P)):320 return reg321 return -1322 323 def evaluate_number(self,x):324 y=self.fundom_rep(x)325 d=x-y326 P=self.embed(self.fundom_rep(x))327 for reg in self._used_regions:328 if(reg[2].contains_point(P)):329 return [reg[1][0]+d,reg[1][1]]330 return -1331 332 def verify(self):333 maxdepth=self._maxdepth334 self.initialize_fundom()335 percent=RealField(prec=20)(0)336 holes=self._holes337 self._minholes=len(holes)338 while(len(holes)>0):339 if(len(holes)-self._minholes>1000):340 assert(0)341 h=holes.popleft()342 result=self.evaluate_hole(h,verifying=True,maxdepth=maxdepth)343 if(result==-2):344 print "The solution is incorrect."345 print "The ",h," is not covered by any region."346 return False347 if(result==-1):348 xh=(h.xmax+h.xmin)/2349 yh=(h.ymax+h.ymin)/2350 depth=h.depth()+1351 self._maxdepth=max([self._maxdepth,depth])352 h1=Hole(self,[h.xmin,h.ymin,xh,yh],depth=depth)353 h2=Hole(self,[h.xmin,yh,xh,h.ymax],depth=depth)354 h3=Hole(self,[xh,h.ymin,h.xmax,yh],depth=depth)355 h4=Hole(self,[xh,yh,h.xmax,h.ymax],depth=depth)356 holes.extendleft([h1,h2,h3,h4])357 else:358 percent+=100*(4**(-h.depth()))359 #print 'Finished hole ',self._minholes,' up to ',percent,'%'360 361 if(len(holes)<self._minholes):362 self._minholes=len(holes)363 percent=RealField(prec=20)(0)364 #print "Remaining ",self._minholes,' holes.'365 return True366 367 def solve(self,verify=False):368 percent=RealField(prec=20)(0)369 holes=self._holes370 self._minholes=len(holes)371 while(len(holes)>0):372 if(len(holes)-self._minholes>1000):373 assert(0)374 h=holes.popleft()375 result=self.evaluate_hole(h)376 if(result==-2):377 self._Nboundmax=max([self._Nboundmax,self._Nbound])378 self._holes.append(h)379 if(result==-1):380 xh=(h.xmax+h.xmin)/2381 yh=(h.ymax+h.ymin)/2382 depth=h.depth()+1383 self._maxdepth=max([self._maxdepth,depth])384 h1=Hole(self,[h.xmin,h.ymin,xh,yh],depth=depth)385 h2=Hole(self,[h.xmin,yh,xh,h.ymax],depth=depth)386 h3=Hole(self,[xh,h.ymin,h.xmax,yh],depth=depth)387 h4=Hole(self,[xh,yh,h.xmax,h.ymax],depth=depth)388 389 holes.extendleft([h1,h2,h3,h4])390 else:391 percent+=100*(4**(-h.depth()))392 #print 'Finished hole ',self._minholes,' up to ',percent,'%'393 394 if(len(holes)<self._minholes):395 self._minholes=len(holes)396 percent=RealField(prec=20)(0)397 #print "Remaining ",self._minholes,' holes.'398 if(verify==True):399 assert(self.verify())400 return [self._disc,self._maxdepth,1+max([abs(self._F(reg[1][1]).norm()) for reg in self._used_regions]),len(self._used_regions),self._used_regions]401 -
new file sage/rings/number_field/quadratic_continued_fraction.pyx
diff -r b97e6e8ba4a1 -r 0c92a2edd152 sage/rings/number_field/quadratic_continued_fraction.pyx
- + 1 2 ########################################## 3 # 4 # Added by mmasdeu 5 # Authors: Xevi Guitart and Marc Masdeu 6 # 7 ########################################## 8 9 from sage.matrix.constructor import Matrix 10 from sage.rings.all import RealField 11 from sage.structure.sage_object import SageObject 12 from sage.misc.all import union 13 from sage.functions.all import (floor,ceil) 14 from sage.rings.all import IntegerRing 15 from sage.rings.all import RationalField 16 from collections import deque 17 from collections import namedtuple 18 19 20 21 class Regions(SageObject): 22 def __init__(self,parent): 23 self._regions=dict([]) 24 self._F=parent._F 25 self._eps=parent._eps 26 self._epsto=[self._F(1)] 27 self.fundom_rep=parent.fundom_rep 28 self.embed=parent.embed 29 self._parent=parent 30 self._N=1 # Means that we have regions up to _N-1=0, so none 31 self._area=self._parent._Rw 32 33 def get_regions(self,B): 34 regions=self._regions 35 if(B>self._N): 36 F=self._F 37 eps=self._eps 38 newelts=dict([(IntegerRing()(n),[I.gens_reduced()[0] for I in v if I.is_principal()]) for n,v in self._F.ideals_of_bdd_norm(B-1).iteritems() if n>=self._N]) 39 self._N=B 40 for nn in range(len(self._epsto),B): 41 self._epsto.append(self._epsto[nn-1]*eps) 42 for nn,v in newelts.iteritems(): 43 assert not regions.has_key(nn) 44 regions[nn]=[] 45 for q in v: 46 invden=1/q 47 invden_red=self.fundom_rep(invden) 48 q0=invden_red-invden 49 m_invden_red=self.fundom_rep(-invden) 50 m_q0=m_invden_red+invden 51 52 a,b=self._parent._change_basis(invden_red) 53 am,bm=self._parent._change_basis(m_invden_red) 54 55 regions[nn].extend([[invden_red,[q0,q],Region(self.embed(invden_red),RealField()(1/nn)),[a,b],nn],[m_invden_red,[m_q0,-q],Region(self.embed(m_invden_red),RealField()(1/nn)),[am,bm],nn]]) 56 57 for jj in range(1,nn): 58 x=self._epsto[jj]*invden 59 x_red=self.fundom_rep(x) 60 x_red_minus=self.fundom_rep(-x_red) 61 regs=regions[nn] 62 if(x_red==regs[0][0] or x_red_minus==regs[0][0]): 63 continue 64 65 q0_minus=x_red_minus+x 66 q0=x_red-x 67 q1=1/x 68 a,b=self._parent._change_basis(x_red) 69 am,bm=self._parent._change_basis(x_red_minus) 70 regions[nn].extend([[x_red,[q0,q1],Region(self.embed(x_red),RealField()(1/nn)),[a,b],nn],[x_red_minus,[q0_minus,-q1],Region(self.embed(x_red_minus),RealField()(1/nn)),[am,bm],nn]]) 71 72 else: 73 # We have all the required regions 74 pass 75 return [reg for nn,lst in regions.iteritems() if nn<B for reg in lst] 76 77 class Hole(SageObject): 78 def __init__(self,parent,v,depth=0): 79 self._parent=parent 80 if isinstance(v,list): 81 #Input in as [xmin,ymin,xmax,ymax] 82 if not (v[0]<v[2] and v[1]<v[3]): 83 print 'The input should be of the form [xmin,ymin,xmax,ymax], with xmin<xmax and ymin<ymax.' 84 assert(0) 85 (self.xmin,self.ymin,self.xmax,self.ymax)=v 86 elif(isinstance(v,Hole)): 87 self.xmin=v.xmin 88 self.ymin=v.ymin 89 self.xmax=v.xmax 90 self.ymax=v.ymax 91 self.size=max([self.xmax-self.xmin,self.ymax-self.ymin]) 92 self._corners=None 93 self._depth=depth 94 95 def depth(self): 96 return self._depth 97 98 def corners(self): 99 if self._corners==None: 100 Pt=self._parent.Pointxy 101 self._corners=[Pt(self.xmin,self.ymin),Pt(self.xmin,self.ymax),Pt(self.xmax,self.ymax),Pt(self.xmax,self.ymin)] 102 return self._corners 103 104 def plot(self,color='blue'): 105 return plot(polygon(self.corners())) 106 107 def overlaps_fundamental_domain(self): 108 return any([self._parent.in_fundamental_domain(x) for x in self.corners()]) 109 110 def _repr_(self): 111 my_str='Hole with corners=('+str(self.xmin)+','+str(self.ymin)+'),('+str(self.xmax)+','+str(self.ymax)+')' 112 return my_str 113 114 class Region(SageObject): 115 def __init__(self,center,radius): 116 #assert(isinstance(center,Pointxy)) 117 self._center=center 118 radius=abs(radius) 119 if(radius>1): 120 print radius 121 print center 122 assert(0) 123 self._radius=radius 124 def radius(self): 125 return self._radius 126 def center(self): 127 return self._center 128 129 def plot_center(self,color='red'): 130 return plot(point(self._center,color=color)) 131 132 def plot(self,color='red'): 133 r=2*self._radius 134 a=self._center[0] 135 b=self._center[1] 136 Pts=[(a,b+r),(a+r,b),(a,b-r),(a-r,b)] 137 return plot(polygon(Pts),color=color) 138 139 def contains_point(self,P): 140 return abs((P.x-self._center.x)*(P.y-self._center.y))<self._radius 141 142 def contains_hole(self,h): 143 return all([self.contains_point(P) for P in h.corners()]) 144 145 class QuadraticContinuedFraction(SageObject): 146 def __init__(self,F,Nbound=50,Tbound=5): 147 self._F=F 148 self._solved=False 149 self._disc=self._F.discriminant() 150 self._w=self._F.maximal_order().ring_generators()[0] 151 self._eps=self._F.units()[0] 152 self._Phi=self._F.real_embeddings(prec=300) 153 a=F.gen() 154 self.Pointxy=namedtuple('Pointxy','x y') 155 if(self._disc%2==0): 156 self._changebasismatrix=1 157 else: 158 self._changebasismatrix=Matrix(IntegerRing(),2,2,[1,-1,0,2]) 159 160 # We assume here that Phi orders the embeddings to that 161 # Phi[1] is the largest 162 self._Rw=self._Phi[1](self._w) 163 self._Rwconj=self._Phi[0](self._w) 164 165 self._used_regions=[] 166 self._Nboundmin=2 167 self._Nboundmax=Nbound 168 self._Nboundinc=1 169 self._Nbound=Nbound 170 self._epsto=[self._F(1)] 171 self._Dmax=self.embed(self._w) 172 self._Tbound=Tbound 173 self._ranget=sorted(range(-self._Tbound,self._Tbound+2),key=abs) 174 self._M=Matrix(RealField(),2,2,[1,self._Rw,1,self._Rwconj]).inverse() 175 self.initialize_fundom() 176 self._master_regs=Regions(self) 177 self._maxdepth=0 178 '''Takes an element in the number field F and returns 179 y in the fundamental domain such that such that (x-y) belongs to R''' 180 def fundom_rep(self,x): 181 # Now xp contains a,b such that x=a+b sqrt(D) 182 y00,y10=self._change_basis(x) 183 d=y00.floor()+self._w*y10.floor() 184 return x-d 185 186 def _change_basis(self,x): 187 v=x.parts() 188 tmp=self._changebasismatrix*Matrix(RationalField(),2,1,v) 189 return tmp[0,0],tmp[1,0] 190 191 # Returns a function that, given a t-value, will return a range of a-values. The arguments specify the region that we want to cover 192 def rangea_gen(self,xmin,ymin,xmax,ymax): 193 wprime0=self._Rw 194 wprime1=self._Rwconj 195 def rangea(t): 196 tp0=t*wprime0 197 tp1=t*wprime1 198 return sorted(list(union(range(floor(xmin-1-tp0-wprime0),ceil(xmax-tp0)+1),range(floor(ymin-1-tp1-wprime1),ceil(ymax-tp1)+1))),key=abs) 199 return rangea 200 201 def in_fundamental_domain(self,P): 202 #assert(isinstance(P,Pointxy)) 203 A=self._M*Matrix(RealField(),2,1,[P.x,P.y]) 204 return A[0,0]>=0 and A[0,0]<1 and A[1,0]>=0 and A[1,0]<1 205 206 '''Given x in F (or in R) embeds it into R^2 207 ''' 208 def embed(self,x): 209 return self.Pointxy(self._Phi[1](x),self._Phi[0](x)) 210 211 def embed_coords(self,a,b): 212 return self.Pointxy(a+b*self._Rw,a+b*self._Rwconj) 213 #return ((ZZ(a)+self._Rw*ZZ(b),ZZ(a)+self._Rwconj*ZZ(b))) 214 215 '''Build the fundamental domain 216 ''' 217 def initialize_fundom(self): 218 F=self._F 219 Pts=[self.embed_coords(a,b) for a in [0,1] for b in [0,1]] 220 xmin=min([P.x for P in Pts]) 221 xmax=max([P.x for P in Pts]) 222 ymin=min([P.y for P in Pts]) 223 ymax=max([P.y for P in Pts]) 224 225 self._aplusbomega=dict([]) 226 rangea=self.rangea_gen(xmin-1,ymin-1,xmax+1,ymax+1) 227 for b in self._ranget: 228 bw=b*self._w 229 for a in rangea(b): 230 self._aplusbomega[(a,b)]=a+bw 231 232 dx=RealField()(0.49) 233 dy=dx 234 Nx=ceil((xmax-xmin)/dx) 235 Ny=ceil((ymax-ymin)/dy) 236 self._holes=deque([]) 237 for ii in range(Nx): 238 for jj in range(Ny): 239 self._holes.append(Hole(self,[xmin+ii*dx,ymin+jj*dy,xmin+(ii+1)*dx,ymin+(jj+1)*dy])) 240 241 242 def plot_holes(self): 243 myplot=plot([]) 244 for h in self._holes: 245 myplot+=h.plot() 246 return myplot 247 248 def remaining_holes(self): 249 return len(self._holes) 250 251 def test_regions(self,corners,at_least_one,embed_coords,regions,Region,aplusbomega,ranget,rangea): 252 ii=0 253 NumRegions=len(regions) 254 #print "Looking at ",NumRegions," regions..." 255 atws=[[aplusbomega[(a,b)],embed_coords(a,b),[a,b]] for b in ranget for a in rangea(b)] 256 for ii in range(NumRegions): 257 reg=regions[ii] 258 for inc in atws: 259 passed=[False for ii in range(4)] 260 a=inc[1].x 261 b=inc[1].y 262 for ii,P in enumerate(corners): 263 if reg[2].contains_point(self.Pointxy(P.x-a,P.y-b)): 264 at_least_one[ii]=True 265 passed[ii]=True 266 else: 267 break 268 if(all(passed)): 269 rparts=reg[3] 270 incparts=inc[2] 271 return [reg[0]+inc[0],[reg[1][0]+inc[0],reg[1][1]],Region(embed_coords(rparts[0]+incparts[0],rparts[1]+incparts[1]),reg[2].radius()),reg[3],reg[4]] 272 return None 273 274 # Given a hole, returns: 275 # -2 if at least one of the points is not covered by the regions 276 # -1 if no region covers all the points 277 # 0 if the a region can cover all the points 278 def evaluate_hole(self,h,verifying=False,maxdepth=-1): 279 if not h.overlaps_fundamental_domain(): 280 return 0 281 regs=[[],[],[],[]] 282 data=[] 283 used=self._used_regions 284 corners=h.corners() 285 atws=[] 286 w=self._w 287 if(verifying): 288 at_least_one=[False,False,False,False] 289 290 for reg in used: 291 passed=True 292 for ii,P in enumerate(corners): 293 if not reg[2].contains_point(P): 294 passed=False 295 if(not verifying): 296 break 297 elif verifying: 298 at_least_one[ii]=True 299 if(passed): 300 return 0 301 302 if(verifying): 303 if(all(at_least_one)): 304 return -1 305 else: 306 if(h.depth()>maxdepth): 307 return -2 308 else: 309 return -1 310 311 rangea=self.rangea_gen(h.xmin,h.ymin,h.xmax,h.ymax) 312 at_least_one=[False,False,False,False] 313 314 l=100 315 B=ceil(4/(l*(h.size**2))) 316 B=max([self._Nboundmin,B]) 317 #print 'B=',B,'Size ~ 10^',RealField(prec=10)((log(h.size)/log(10))) 318 regions=self._master_regs.get_regions(min([B,self._Nbound])) 319 nreg=self.test_regions(corners,at_least_one,embed_coords=self.embed_coords,regions=regions,Region=Region,aplusbomega=self._aplusbomega, ranget=self._ranget,rangea=rangea) 320 if(nreg!=None): 321 used.append(nreg) 322 return 0 323 324 return -1 325 326 def evaluate_pointxy(self,x,y): 327 P=self.Pointxy(x,y) 328 for reg in self._used_regions: 329 if(reg[2].contains_point(P)): 330 return reg 331 return -1 332 333 def evaluate_number(self,x): 334 y=self.fundom_rep(x) 335 d=x-y 336 P=self.embed(y) 337 for reg in self._used_regions: 338 if(reg[2].contains_point(P)): 339 return [reg[1][0]+d,reg[1][1]] 340 return -1 341 342 def verify(self): 343 maxdepth=self._maxdepth 344 self.initialize_fundom() 345 percent=RealField(prec=20)(0) 346 holes=self._holes 347 self._minholes=len(holes) 348 while(len(holes)>0): 349 if(len(holes)-self._minholes>1000): 350 assert(0) 351 h=holes.popleft() 352 result=self.evaluate_hole(h,verifying=True,maxdepth=maxdepth) 353 if(result==-2): 354 print "The solution is incorrect." 355 print "The ",h," is not covered by any region." 356 return False 357 if(result==-1): 358 xh=(h.xmax+h.xmin)/2 359 yh=(h.ymax+h.ymin)/2 360 depth=h.depth()+1 361 self._maxdepth=max([self._maxdepth,depth]) 362 h1=Hole(self,[h.xmin,h.ymin,xh,yh],depth=depth) 363 h2=Hole(self,[h.xmin,yh,xh,h.ymax],depth=depth) 364 h3=Hole(self,[xh,h.ymin,h.xmax,yh],depth=depth) 365 h4=Hole(self,[xh,yh,h.xmax,h.ymax],depth=depth) 366 holes.extendleft([h1,h2,h3,h4]) 367 else: 368 percent+=100*(4**(-h.depth())) 369 #print 'Finished hole ',self._minholes,' up to ',percent,'%' 370 371 if(len(holes)<self._minholes): 372 self._minholes=len(holes) 373 percent=RealField(prec=20)(0) 374 #print "Remaining ",self._minholes,' holes.' 375 return True 376 377 def solve(self,verify=False): 378 percent=RealField(prec=20)(0) 379 holes=self._holes 380 self._minholes=len(holes) 381 while(len(holes)>0): 382 if(len(holes)-self._minholes>1000): 383 assert(0) 384 h=holes.popleft() 385 result=self.evaluate_hole(h) 386 if(result==-2): 387 self._Nboundmax=max([self._Nboundmax,self._Nbound]) 388 self._holes.append(h) 389 if(result==-1): 390 xh=(h.xmax+h.xmin)/2 391 yh=(h.ymax+h.ymin)/2 392 depth=h.depth()+1 393 self._maxdepth=max([self._maxdepth,depth]) 394 h1=Hole(self,[h.xmin,h.ymin,xh,yh],depth=depth) 395 h2=Hole(self,[h.xmin,yh,xh,h.ymax],depth=depth) 396 h3=Hole(self,[xh,h.ymin,h.xmax,yh],depth=depth) 397 h4=Hole(self,[xh,yh,h.xmax,h.ymax],depth=depth) 398 399 holes.extendleft([h1,h2,h3,h4]) 400 else: 401 percent+=100*(4**(-h.depth())) 402 #print 'Finished hole ',self._minholes,' up to ',percent,'%' 403 404 if(len(holes)<self._minholes): 405 self._minholes=len(holes) 406 percent=RealField(prec=20)(0) 407 #print "Remaining ",self._minholes,' holes.' 408 if(verify==True): 409 assert(self.verify()) 410 self._solved=True 411 return [self._disc,self._maxdepth,1+max([abs(self._F(reg[1][1]).norm()) for reg in self._used_regions]),len(self._used_regions),self._used_regions] 412
