├── LICENSE ├── README.md ├── __init__.py ├── chol_and_inverse.c ├── chol_and_inverse.h ├── context_object.pxd ├── context_object.pyx ├── context_variables.c ├── context_variables.h ├── examples ├── 3dBosonic.py ├── 3dOn.py ├── 3dOn2.py ├── mixed_ising.py └── super_Ising.py ├── integral_decomp.c ├── integral_decomp.h ├── partial_fraction.c ├── partial_fraction.h ├── scalar ├── __init__.py ├── hor_formula.c ├── hor_formula.h ├── hor_recursion.c ├── hor_recursion.h ├── k_compute.c ├── k_compute.h ├── scalar_context.pxd └── scalar_context.pyx └── tutorial.pdf /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Tomoki Ohtsuki 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This tiny module for [SageMath](http://www.sagemath.org) contains helper functions to generate a bootstrap problem to be solved by [SDPB](https://github.com/davidsd/sdpb), written originally for Ph.D. thesis of the author. Almost the same functionality is offered by [PyCFTBoot](https://github.com/cbehan/pycftboot), but the implementation detail and notation are somewhat different. This makes extensive use of `sage.rings.real_mpfr.RealNumber` and "rings.RealDensePolynomials" classes contained in Sage, to handle arbitrary precision number/polynomials. 2 | 3 | ###Install 4 | 5 | 1. Install sage from source. This module has been originally written in the environment of sage-6.8 on OSX Yosemite, but confirmed to work up to sage-7.0. 6 | 7 | 2. Place cboot directory under 8 | `your/sage/src/sage`. 9 | The actual location of `your/sage/src` can be checked by running sage and enter 10 | `SAGE_ENV['SAGE_SRC']` 11 | In my environment, for example, this is '/Users/tomoki/sources/sage-6.8/src'. 12 | 13 | 3. Edit `your/sage/src/module_list.py` to add the following items in the variable `ext_modules`. 14 | ``` 15 | Extension('sage.cboot.context_object',sources=['sage/cboot/context_object.pyx','sage/cboot/partial_fraction.c','sage/cboot/integral_decomp.c','sage/cboot/chol_and_inverse.c','sage/cboot/context_variables.c'], extra_compile_args=['-std=c99'],libraries=['gmp','mpfr'],language = 'c'), 16 | 17 | Extension('sage.cboot.scalar_context',sources=['sage/cboot/scalar/scalar_context.pyx','sage/cboot/scalar/hor_formula.c','sage/cboot/scalar/hor_recursion.c','sage/cboot/scalar/k_compute.c'],include_dirs=['sage/cboot','sage/cboot/scalar'],depends=['sage/cboot/context_variables.h'], extra_compile_args=['-std=c99'],libraries=['gmp','mpfr'],language = 'c'), 18 | ``` 19 | 4. Then run from your terminal `sage -b`. 20 | 21 | 22 | ###Examples 23 | The example scripts are contained in `examples` folder. See `tutorial.pdf`. 24 | 25 | ###Acknowledgement 26 | I thank Yu Nakayama for collaboration, tests, and complaints. 27 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | #this is not an empty file 2 | from sage.all import * 3 | from .context_object import * 4 | from .scalar_context import * 5 | 6 | -------------------------------------------------------------------------------- /chol_and_inverse.c: -------------------------------------------------------------------------------- 1 | #include "chol_and_inverse.h" 2 | mpfr_t* mpfr_triangular_inverse(mpfr_t* A, int dim,mpfr_prec_t prec){ 3 | 4 | mpfr_t *res=malloc(sizeof(mpfr_t)*dim*dim); 5 | 6 | mpfr_t s; 7 | mpfr_t mul_temp; 8 | 9 | mpfr_init2(s,prec); 10 | mpfr_init2(mul_temp,prec); 11 | /* 12 | * 13 | * \sum_{j=0}^{dim-1} A[i,k] res[k,j] = delta _ {i,j} 14 | * e.g. i=0 -> only A[0+0] can contribute, res[0,j]*A[0,0] = delta_{0,j} 15 | * 16 | * i=1 -> A[1,0]*res[0,k] + A[1,1]*res[1,k]=delta_{1,k} 17 | * res[1,k]= 0 for k>1 18 | * res[1,1] = A[1,1]^{-1} 19 | * res[1,0] = (-A[1,0]*res[0,0] )A[1,1]^{-1} 20 | * 21 | * i=2 -> A[2,0]*res[0,k] + A[2,1]*res[1,k] + A[2,2]*res[2,k] = delta(2,k) 22 | * k=2 -> ok 23 | * k=1 -> A[2,i]*res[0,k] 24 | * 25 | * 26 | * A[i,0]*res[0,1] + A[i,k] * res[k,j] +...+ A[i,i]res[i,k] = delta(i,k) 27 | * 28 | * A[i,i]*res[i,j] = -( A[i,0]*res[0,j] +...+ A[i,k]*res[k,j] 29 | * + A[i,i-1] * res[i-1,j]) 30 | * = sum_{k= j}^{i-1} A[i,k]*res[k,j] 31 | * 32 | * */ 33 | for(int i=0;i x^m y^{2n} 42 | # (m+2 n)=(i+j) 43 | if ((i+j)%2): 44 | # x^m in (0,2,...) 45 | # n=(i+j-m)/2 46 | # 0,1,dots,Lambda,0,dots,Lambda-2, 47 | # \sum_i=0^{n-1}(Lambda+1 -i) + m 48 | # (Lambda+1- (i+j-x-1)/2)*(i+j-x) 49 | xypositions=([(Lambda+1-(i+j-x-1)/2)*(i+j-x-1)/2+x for x in range(0,len(temp),2)]) 50 | coeff_with_position=zip(xypositions,temp[0::2]) 51 | else: 52 | xypositions=([(Lambda+2-(i+j-x-1)/2)*(i+j-x-1)/2+x for x in range(1,len(temp),2)]) 53 | coeff_with_position=zip(xypositions,temp[1::2]) 54 | [result[column_position].__setitem__(int(x[0]),field(x[1]/2)) for x in coeff_with_position] 55 | return result.transpose() 56 | 57 | def z_zbar_derivative_to_x_y_derivative_Matrix(Lambda,field=RealField(400)): 58 | """ 59 | z_zbar_derivative_to_x_y_derivative_Matrix(Lambda,field=RealField(400)) 60 | returns the matrix to convert the derivatives of real function 61 | w.r.t. z and z_bar to those with x and y. 62 | Assuming the derivatives to be ordered as 63 | f, D_z f, D_z 64 | """ 65 | q=field['x'] 66 | if (Lambda%2): 67 | dimG=(Lambda+1)*(Lambda+3)/4 68 | else: 69 | dimG=((Lambda+2)**2)/4 70 | result=np.ndarray(dimG**2,dtype='O') 71 | result=result.reshape(dimG,dimG) 72 | set_ij_elements = lambda x,a,b,i,j: result[((Lambda+2-a)*a+b)].__setitem__(((Lambda+2-i)*i+j),x) 73 | for i in range(0,(Lambda//2+1)): 74 | for j in range(i,Lambda+1-i): 75 | if (i==j): 76 | temp=((q('x+1')**j)*(q('x-1')**i)).padded_list() 77 | else: 78 | temp=((q('x+1')**j)*(q('x-1')**i)+(q('x-1')**j)*(q('x+1')**i)).padded_list() 79 | if((i+j)%2): 80 | map(lambda x, y:set_ij_elements(x,(i+j-y)/2,y,i,j-i),temp[1::2],range(1,len(temp),2)) 81 | else: 82 | map(lambda x, y:set_ij_elements(x,(i+j-y)/2,y,i,j-i),temp[0::2],range(0,len(temp),2)) 83 | return np.array(map(lambda x: 0 if x==None else x, result.flatten())).reshape(dimG,dimG) 84 | 85 | 86 | cdef class cb_universal_context: 87 | """ 88 | Class to store a bunch of frequently used datum, like 89 | precision, cutoff parameter Lambda, and the matrix representing 90 | the change variables, e.g. {z, z_bar}->(x,y) and r -> x. 91 | """ 92 | def __cinit__(self, int Lambda, mp_prec_t Prec, long nMax,*args,**kwargs): 93 | self.c_context = context_construct(nMax,Prec,Lambda) 94 | self.precision=Prec 95 | self.field=RealField(Prec) 96 | self.Delta_Field=self.field['Delta'] 97 | self.Delta=self.Delta_Field('Delta') 98 | self.Lambda=Lambda 99 | self.maxExpansionOrder=nMax 100 | self.rho_to_z_matrix=np.ndarray([Lambda+1,Lambda+1],dtype='O') 101 | self.polynomial_vector_evaluate=np.vectorize(lambda x, value:self.Delta_Field(x)(value)) 102 | 103 | for i in range(0,Lambda+1): 104 | for j in range(0,Lambda+1): 105 | r=(self.field)._new() 106 | r._parent=self.field 107 | mpfr_init2(r.value,Prec) 108 | mpfr_set(r.value,self.c_context.rho_to_z_matrix[i*(Lambda+1)+j],MPFR_RNDN) 109 | self.rho_to_z_matrix[i][j]=r 110 | 111 | def __init__(self, int Lambda, mp_prec_t Prec, long nMax,*args,**kwargs): 112 | 113 | self.polynomial_vector_shift=np.vectorize(lambda x,shift:self.Delta_Field(x)(self.Delta + shift)) 114 | self.rho=3-2*(self.field)(2).sqrt() 115 | self.convert_to_polynomial_vector=np.vectorize(lambda y:self.Delta_Field(y)) 116 | self.convert_to_real_vector=np.vectorize(lambda y:self.field(y)) 117 | 118 | self.zzbar_to_xy_marix=z_zbar_derivative_to_x_y_derivative_Matrix(self.Lambda, self.field) 119 | self.index_list=reduce(lambda x,y:x+y,map(lambda i: map(lambda j:np.array([i,j]),range(0,self.Lambda+1-2*i)),range(self.Lambda//2 + 1))) 120 | self.rho_to_delta=np.ndarray(self.Lambda+1,dtype='O') 121 | self.rho_to_delta[0]=self.Delta_Field(1) 122 | for i in range(1,self.Lambda+1): 123 | self.rho_to_delta[i]=self.rho_to_delta[i-1]*(self.Delta+1-i)/(self.rho*i) 124 | self.rho_to_delta=self.rho_to_z_matrix.dot(self.rho_to_delta) 125 | self.null_ftype=np.array(map(lambda x:self.field(0),range(0,((Lambda+1)//2)*(((Lambda+1)//2)+1)/2))) 126 | self.null_htype=np.array(map(lambda x:self.field(0),range(0,((Lambda+2)//2)*(((Lambda+2)//2)+1)/2))) 127 | 128 | def dim_f(self): 129 | return int(((self.Lambda+1)//2)*(((self.Lambda+1)//2)+1)/2) 130 | 131 | def dim_h(self): 132 | return int(((self.Lambda+2)//2)*(((self.Lambda+2)//2)+1)/2) 133 | 134 | def __call__(self,x): 135 | """ 136 | The default action of this class is 137 | to convert numbers into real numbers with the default precision. 138 | """ 139 | return self.field(x) 140 | 141 | def __repr__(self): 142 | return "Conformal bootstrap context with Lambda = {0}, precision = {1}, nMax = {2}".format(self.Lambda,self.precision,self.maxExpansionOrder) 143 | 144 | def __deallocate__(self): 145 | clear_cb_context((self).c_context) 146 | 147 | def identity_vector(self): 148 | res = np.concatenate([self.null_ftype,self.null_htype]) 149 | res[0]=self.field(1) 150 | return res 151 | 152 | def v_to_d(self,d): 153 | """ 154 | compute the table of derivative of v = (z*z_bar)^d 155 | in the x_y basis 156 | """ 157 | local_table=[d.parent(1)] 158 | local_res=[] 159 | for i in range(1,self.Lambda+1): 160 | local_table.append(local_table[-1]*(d.parent(-2)*(d-d.parent(len(local_table)-1)))/d.parent(len(local_table))) 161 | 162 | for i in range(0,self.Lambda+1): 163 | for j in range(i,self.Lambda+1-i): 164 | local_res.append((local_table[i]*local_table[j]+local_table[j]*local_table[i])/2) 165 | return self.zzbar_to_xy_marix.dot(np.array(local_res)) 166 | 167 | def v_to_d_and_anti_symmetrizing_matrix(self,d): 168 | return self.make_F_minus_matrix(d) 169 | 170 | def make_F_minus_matrix(self,d): 171 | return self.F_minus_matrix(d) 172 | 173 | def F_minus_matrix(self,d): 174 | """ 175 | compute a numpy matrix corresponding to 176 | v^d multiplication followed by x<-> -x anti-symmetrization. 177 | For example, the vector for 178 | F^{-}_{d,\Delta, l}(x,y) is computed by 179 | F_minus = v_to_d_and_anti_symmetrizing_matrix(d).dot(gBlock(ell,Delta,S,P)) 180 | """ 181 | aligned_index = lambda x: (self.Lambda + 2 - x[0])*x[0]+x[1] 182 | local_v=self.v_to_d(d) 183 | return ((self.field(1)/4)**d)*np.array(map(lambda i: (np.array(map(lambda m: local_v[aligned_index(i-m)] if ((i-m)[0]>=0 and (i-m)[1]>=0 ) else d.parent(0),self.index_list))) 184 | ,[x for x in self.index_list if x[1]%2])) 185 | 186 | def v_to_d_and_symmetrizing_matrix(self,d): 187 | return self.F_plus_matrix(d) 188 | 189 | def make_F_plus_matrix(self,d): 190 | return self.F_plus_matrix(d) 191 | 192 | def F_plus_matrix(self,d): 193 | """ 194 | compute a numpy matrix corresponding to 195 | v^d multiplication followed by x<-> -x symmetrization. 196 | For example, the vector for 197 | F^{+}_{d,\Delta, l}(x,y) is computed by 198 | F_minus = v_to_d_and_symmetrizing_matrix(d).dot(gBlock(ell,Delta,S,P)) 199 | """ 200 | aligned_index = lambda x: (self.Lambda + 2 - x[0])*x[0]+x[1] 201 | local_v=self.v_to_d(d) 202 | return ((self.field(1)/4)**d)*np.array(map(lambda i: (np.array(map(lambda m: local_v[aligned_index(i-m)] if ((i-m)[0]>=0 and (i-m)[1]>=0 ) else d.parent(0),self.index_list))) 203 | ,[x for x in self.index_list if not x[1]%2])) 204 | 205 | def univariate_func_prod(self,x,y): 206 | return np.array(map(lambda i:x[0:i+1].dot(y[i::-1]),range(0,self.Lambda+1))) 207 | 208 | def SDP(self,normalization,objective,pvm,label=None): 209 | return SDP(normalization,objective,pvm,label=label,context=self) 210 | 211 | def positive_matrix_with_prefactor(self,pref,array): 212 | return positive_matrix_with_prefactor(pref,array,self) 213 | def damped_rational(self,poles,c): 214 | return damped_rational(poles,4*self.rho,c,self) 215 | 216 | def prefactor_numerator(self,pref,array): 217 | return prefactor_numerator(pref,array,self) 218 | 219 | def pochhammer(self,x,unsigned long n): 220 | x_c=self.field(x) 221 | cdef mpfr_t temp1 222 | mpfr_init2(temp1,self.precision) 223 | result=(self.field)._new() 224 | (result)._parent=self.field 225 | mpfr_init2(( result).value,self.precision) 226 | mpfr_set_ui(( result).value,1,MPFR_RNDN) 227 | for j in range(0,n): 228 | mpfr_add_ui(temp1,(x_c).value, j,MPFR_RNDN) 229 | mpfr_mul((result).value, (result).value,temp1,MPFR_RNDN) 230 | mpfr_clear(temp1) 231 | return result 232 | 233 | def vector_to_prefactor_numerator(self,vector): 234 | """ 235 | Convert a constant (i.e., non-polynomial) vector into positive_matrix_with_prefactor. 236 | """ 237 | pref=self.damped_rational([],1) 238 | if len(vector.shape)==1: 239 | return self.prefactor_numerator(pref,vector.reshape(1,1,len(vector))) 240 | else: 241 | return self.prefactor_numerator(pref,vector) 242 | 243 | def lcms(self,preflist): 244 | res={} 245 | for pref in preflist: 246 | d_order=pref.poles 247 | for Delta in d_order: 248 | try: 249 | m=res[Delta] 250 | m_new=d_order[Delta] 251 | if m_new > m: 252 | res.update({Delta:m_new}) 253 | except KeyError: 254 | m_new=d_order[Delta] 255 | res.update({Delta:m_new}) 256 | rems=[] 257 | for pref in preflist: 258 | d_order=pref.poles 259 | rem=[] 260 | for Delta in res: 261 | mr=res[Delta] 262 | try: 263 | m = d_order[Delta] 264 | if mr - m > 0: 265 | rem.append((Delta,mr-m)) 266 | except KeyError: 267 | rem.append((Delta,mr)) 268 | rems.append(dict(rem)) 269 | res=self.damped_rational(res,self(1)) 270 | return (res,rems) 271 | 272 | def join(self,l): 273 | dims={} 274 | pns=[] 275 | pnindices=[] 276 | nBlock=len(l) 277 | bodies={} 278 | nrow=None 279 | for n,mat in enumerate(l): 280 | if not nrow: 281 | nrow=len(mat) 282 | else: 283 | if not nrow==len(mat): 284 | raise RuntimeError("unequal dim") 285 | for i,row in enumerate(mat): 286 | if not nrow==len(row): 287 | raise RuntimeError("unequal dim") 288 | for j,x in enumerate(row): 289 | if isinstance(x,prefactor_numerator): 290 | len_x=x.matrix.shape[-1] 291 | pns.append(x) 292 | pnindices.append((n,i,j)) 293 | else: 294 | len_x=int(x) 295 | v=np.ndarray(len_x,dtype='O') 296 | v[:]=self(0) 297 | bodies.update({(n,i,j):v}) 298 | try: 299 | if not dims[n]==len_x: 300 | raise RuntimeError("Input has inconsistent dimensions.") 301 | except KeyError: 302 | dims.update({n:len_x}) 303 | 304 | res_pref, pref_rems=self.lcms([pn.prefactor for pn in pns]) 305 | vecs=[(ind,__mult_poles(rem,pn.prefactor.pref_constant*pn.matrix,self)) 306 | for ind, pn, rem in zip(pnindices, pns, pref_rems)] 307 | bodies.update(dict(vecs)) 308 | res=np.ndarray((nrow,nrow,sum([dims[x] for x in dims])),dtype='O') 309 | for i in range(nrow): 310 | for j in range(nrow): 311 | v=(bodies[(n,i,j)].reshape((dims[n],)) for n in range(0,nBlock)) 312 | vv=np.concatenate(tuple(v)) 313 | res[i,j]=vv 314 | return prefactor_numerator(res_pref,res,self) 315 | 316 | def sumrule_to_SDP(self,normalization,objective,svs,**kwargs): 317 | n_block=len(svs[0]) 318 | dims={} 319 | shapes=[] 320 | res=[] 321 | tbs=dict([(n,[]) for n in range(n_block)]) 322 | for m,sv in enumerate(svs): 323 | if len(sv)!=n_block: 324 | raise RuntimeError("Sum rule vector has in equal dimensions!") 325 | psv=[] 326 | for n,component in enumerate(sv): 327 | if not isinstance(component,list): 328 | pcomponent=[[component]] 329 | else: 330 | pcomponent=component 331 | for i, row in enumerate(pcomponent): 332 | for j,x in enumerate(row): 333 | if isinstance(x,prefactor_numerator): 334 | try: 335 | givendim=dims[n] 336 | if givendim!=x.matrix.shape[-1]: 337 | raise RuntimeError("Found inconsistent dimension.") 338 | except KeyError: 339 | dims[n]=x.matrix.shape[-1] 340 | elif isinstance(x,np.ndarray): 341 | pcomponent[i][j]=self.vector_to_prefactor_numerator(x) 342 | try: 343 | givendim=dims[n] 344 | if givendim!=x.shape[-1]: 345 | raise RuntimeError("Found inconsistent dimension.") 346 | except KeyError: 347 | dims[n]=x.shape[-1] 348 | else: 349 | x=int(x) 350 | tbs[n].append((m,n,i,j)) 351 | psv.append(pcomponent) 352 | res.append(psv) 353 | if n_block > len(dims.keys()): 354 | raise RuntimeError("There exists a component zero for all") 355 | for k in dims: 356 | try: 357 | mlist=tbs[k] 358 | except KeyError: 359 | mlist=[] 360 | for m,n,i,j in mlist: 361 | res[m][n][i][j]=dims[k] 362 | if isinstance(normalization,np.ndarray): 363 | norm=normalization 364 | elif isinstance(normalization,list): 365 | norm_list=[] 366 | for n,v in enumerate(normalization): 367 | if isinstance(v,np.ndarray): 368 | norm_list.append(v) 369 | elif v==0: 370 | tba=np.ndarray((dims[n],),dtype='O') 371 | tba[:]=self(0) 372 | norm_list.append(tba) 373 | norm=np.concatenate(norm_list) 374 | else: 375 | raise NotImplemented 376 | 377 | if isinstance(objective,np.ndarray): 378 | obj=objective 379 | elif isinstance(objective,list): 380 | obj_list=[] 381 | for n,v in enumerate(objective): 382 | if isinstance(v,np.ndarray): 383 | obj_list.append(v) 384 | elif v==0: 385 | tba=np.ndarray((dims[n],),dtype='O') 386 | tba[:]=self(0) 387 | obj_list.append(tba) 388 | obj=np.concatenate(obj_list) 389 | else: 390 | try: 391 | if int(objective)==0: 392 | obj=np.ndarray((sum([dims[n] for n in dims]),),dtype='O') 393 | obj[:]=self(0) 394 | else: 395 | raise NotImplementedError("Got unrecognizable input for objective") 396 | except TypeError: 397 | raise NotImplementedError("Got unrecognizable input for objective") 398 | return self.SDP(norm,obj,[self.join(sv) for sv in res],**kwargs) 399 | 400 | def dot(self,x,y): 401 | # Unfortunately __numpy_ufunc__ seems to be disabled (temporarily?) 402 | # so I cannot override np.dot 403 | # 404 | if isinstance(x,prefactor_numerator): 405 | if isinstance(y,prefactor_numerator): 406 | pref=x.prefactor*y.prefactor 407 | return prefactor_numerator(pref,np.dot(x.matrix,y.matrix),self) 408 | else: 409 | return prefactor_numerator(x.prefactor,np.dot(x.matrix,y),self) 410 | else: 411 | if isinstance(y,prefactor_numerator): 412 | return prefactor_numerator(y.prefactor,np.dot(x,y.matrix),self) 413 | else: 414 | return np.dot(x,y) 415 | # def concatenate(self,pns): 416 | # if not isinstance(pns,list): 417 | # raise TypeError("argument must be a list") 418 | # nparray=[] 419 | # shape=[len(pns),None] 420 | # for i,e in enumerate(pns): 421 | # if isinstance(e,list): 422 | # if not is_square(len(e)): 423 | # raise RuntimeError("The {0}th column of the input is not square".format(str(i))) 424 | # if not shape[1]: 425 | # shape[1]=sqrt(len(e)) 426 | # 427 | # e.append([[x for x in e[j:j+shape[1]] 428 | # 429 | # #nparray.append([e[j) 430 | 431 | 432 | cpdef fast_partial_fraction(pole_data,prec): 433 | cdef int n = len(pole_data) 434 | cdef int result_length=sum([x[1] for x in pole_data]) 435 | cdef mpfr_t* pole_locations_c = malloc(sizeof(mpfr_t)*n) 436 | cdef int* double_or_single_c = malloc(sizeof(int)*n) 437 | for i in range(0,n): 438 | mpfr_init2(pole_locations_c[i],prec) 439 | mpfr_set(pole_locations_c[i],(RealField(prec)(pole_data[i][0])).value,MPFR_RNDN) 440 | if pole_data[i][1]==1: 441 | double_or_single_c[i]=0 442 | else: 443 | double_or_single_c[i]=1 444 | 445 | cdef mpfr_t *result = fast_partial_fraction_c(pole_locations_c, double_or_single_c, n, prec) 446 | 447 | for i in range(0,n): 448 | mpfr_clear(pole_locations_c[i]) 449 | free(pole_locations_c) 450 | free(double_or_single_c) 451 | 452 | cdef int count=0 453 | result_py=np.ndarray([result_length,3],dtype='O') 454 | 455 | field=RealField(prec) 456 | 457 | for i in range(0,n): 458 | result_py[count][2]=(field)._new() 459 | (result_py[count][2])._parent=field 460 | mpfr_init2((result_py[count][2]).value,prec) 461 | mpfr_set((result_py[count][2]).value, result[count],MPFR_RNDN) 462 | mpfr_clear(result[count]) 463 | result_py[count][0]=pole_data[i][0] 464 | if pole_data[i][1]==1: 465 | result_py[count][1]=1 466 | if pole_data[i][1]==2: 467 | result_py[count][1]=2 468 | count=count+1 469 | result_py[count][2]=(field)._new() 470 | (result_py[count][2])._parent=RealField(prec) 471 | mpfr_init2((result_py[count][2]).value,prec) 472 | mpfr_set((result_py[count][2]).value, result[count],MPFR_RNDN) 473 | mpfr_clear(result[count]); 474 | result_py[count][0]=pole_data[i][0] 475 | result_py[count][1]=1 476 | 477 | count=count+1 478 | free(result) 479 | return result_py 480 | 481 | cpdef simple_or_double_pole_integral(x_power_max,base,pole_position, order_of_pole, mp_prec_t prec): 482 | a=RealField(2*prec)(pole_position) 483 | b=RealField(2*prec)(base) 484 | if (a==0): 485 | if order_of_pole >=2: 486 | raise RuntimeError("diverging integral") 487 | elif order_of_pole==1: 488 | incomplete_gamma = 1 489 | else: 490 | raise NotImplementedError("pole order must be 1 or 2") 491 | else: 492 | incomplete_gamma = b**a*gamma(0,a*(b.log())) 493 | 494 | if not incomplete_gamma.is_real(): 495 | raise RuntimeError("could not obtain sensible value in the integral.") 496 | else: 497 | incomplete_gamma=RealField(prec)(incomplete_gamma) 498 | 499 | field=RealField(prec) 500 | a=field(pole_position) 501 | b=field(base) 502 | 503 | cdef mpfr_t* result; 504 | if order_of_pole==1: 505 | result = simple_pole_case_c( x_power_max, (b).value, ( a).value,( incomplete_gamma).value,prec) 506 | elif order_of_pole==2: 507 | result = double_pole_case_c( x_power_max, (b).value, ( a).value,( incomplete_gamma).value,prec) 508 | result_py=np.ndarray(x_power_max+1,dtype='O') 509 | for i in range(0,x_power_max+1): 510 | result_py[i]=(field)._new() 511 | (result_py[i])._parent=field 512 | mpfr_init2((result_py[i]).value,prec) 513 | mpfr_set((result_py[i]).value, result[i],MPFR_RNDN) 514 | mpfr_clear(result[i]); 515 | free(result) 516 | return result_py 517 | 518 | cdef mpfr_t* pole_integral_c(x_power_max,base, pole_position, order_of_pole, mp_prec_t prec): 519 | a=RealField(2*prec)(pole_position) 520 | b=RealField(2*prec)(base) 521 | if a<0: 522 | incomplete_gamma = b**a*gamma(0,a*(b.log())) 523 | elif a==0: 524 | incomplete_gamma = RealField(prec)(prec) 525 | else: 526 | raise RuntimeError("A pole exists in the prefactor") 527 | if not incomplete_gamma.is_real(): 528 | raise RuntimeError("Integral not real ... perhaps a mistake in pole data.") 529 | else: 530 | incomplete_gamma=RealField(prec)(incomplete_gamma) 531 | 532 | field=RealField(prec) 533 | a=field(pole_position) 534 | b=field(base) 535 | 536 | cdef mpfr_t* result; 537 | if order_of_pole==1: 538 | result = simple_pole_case_c( x_power_max, (b).value, ( a).value,( incomplete_gamma).value,prec) 539 | elif order_of_pole==2: 540 | result = double_pole_case_c( x_power_max, (b).value, ( a).value,( incomplete_gamma).value,prec) 541 | return result 542 | 543 | 544 | cpdef prefactor_integral(pole_data, base, int x_power, prec,c=1): 545 | field=RealField(prec) 546 | cdef int n = len(pole_data) 547 | cdef int number_of_factors = sum([x[1] for x in pole_data]) 548 | 549 | cdef int count = 0 550 | index_list = [] 551 | for i in range(0,len(pole_data)): 552 | if field(pole_data[i][0]) > 0: 553 | raise NotImplementedError("There exists a pole on the integration contour of the prefactor!") 554 | if pole_data[i][1]==1: 555 | index_list.append([i,1]) 556 | elif pole_data[i][1]==2: 557 | index_list.append([i,2]) 558 | index_list.append([i,1]) 559 | else: 560 | raise NotImplementedError 561 | if n==0: 562 | minus_ln_b = -1/((RealField(prec)(base)).log()) 563 | result = np.ndarray(x_power+1,dtype='O') 564 | result[0]=minus_ln_b * RealField(prec)(c) 565 | for i in range (1,x_power+1): 566 | result[i]=result[i-1]*minus_ln_b*i 567 | return result 568 | cdef mpfr_t *pole_data_to_c = malloc(sizeof(mpfr_t)*len(pole_data)) 569 | if(pole_data_to_c==NULL): 570 | raise NotImplementedError 571 | cdef int * is_double = malloc(sizeof(int)*len(pole_data)) 572 | 573 | base_c = field(base); 574 | for i in range(0,n): 575 | r=field(pole_data[i][0]) 576 | mpfr_init2(pole_data_to_c[i],prec) 577 | mpfr_set(pole_data_to_c[i],(r).value,MPFR_RNDN) 578 | if pole_data[i][1]==2: 579 | is_double[i]=1 580 | else: 581 | is_double[i]=0 582 | decompose_coeffs=fast_partial_fraction_c(pole_data_to_c,is_double,n,prec) 583 | 584 | for i in range(0,len(pole_data)): 585 | mpfr_clear(pole_data_to_c[i]) 586 | 587 | free(pole_data_to_c) 588 | free(is_double) 589 | 590 | cdef mpfr_t temp1 591 | mpfr_init2(temp1,prec); 592 | cdef mpfr_t temp2 593 | mpfr_init2(temp2,prec); 594 | result=np.ndarray(x_power+1,dtype='O') 595 | for i in range(0,x_power+1): 596 | result[i]=(field)._new() 597 | mpfr_init2(( result[i]).value,prec) 598 | #mpfr_set_ui(( result[i]).value,0,MPFR_RNDN) 599 | mpfr_set_zero(( result[i]).value,1) 600 | ( result[i])._parent = field 601 | 602 | cdef mpfr_t* temp_mpfrs 603 | 604 | for i in range(0,number_of_factors): 605 | temp_mpfrs = pole_integral_c(x_power, base, pole_data[index_list[i][0]][0], index_list[i][1], prec) 606 | 607 | for j in range(0,x_power+1): 608 | mpfr_mul(temp1,decompose_coeffs[i],temp_mpfrs[j],MPFR_RNDN) 609 | mpfr_add(( result[j]).value,( result[j]).value,temp1,MPFR_RNDN) 610 | mpfr_clear(temp_mpfrs[j]) 611 | free(temp_mpfrs) 612 | 613 | for i in range(0,number_of_factors): 614 | mpfr_clear(decompose_coeffs[i]) 615 | free(decompose_coeffs) 616 | return RealField(prec)(c)*result 617 | 618 | cpdef anti_band_cholesky_inverse(v,n_order_max,prec): 619 | field=RealField(prec) 620 | n_max=int(n_order_max) 621 | if not isinstance(n_max,int): 622 | raise TypeError 623 | else: 624 | if (len(v) < (n_max*2+1)): 625 | print ("input vector is too short..") 626 | raise TypeError 627 | elif (n_max < 0): 628 | print ("expected n_max to be positive integer...") 629 | raise TypeError 630 | 631 | cdef mpfr_t* anti_band_input = malloc(sizeof(mpfr_t)*len(v)) 632 | for i in range(0,len(v)): 633 | r=field(v[i]) 634 | mpfr_init2(anti_band_input[i],prec) 635 | mpfr_set(anti_band_input[i],(r).value,MPFR_RNDN) 636 | cdef mpfr_t* anti_band_mat = form_anti_band(anti_band_input, (n_max+1),int(prec)) 637 | for i in range(0,len(v)): 638 | mpfr_clear(anti_band_input[i]) 639 | free(anti_band_input) 640 | cdef mpfr_t* cholesky_decomposed = mpfr_cholesky(anti_band_mat, (n_max+1), int(prec)) 641 | for i in range(0,(n_max-1)**2): 642 | mpfr_clear(anti_band_mat[i]) 643 | free (anti_band_mat) 644 | 645 | cdef mpfr_t* inversed = mpfr_triangular_inverse(cholesky_decomposed,(n_max+1), int(prec)) 646 | for i in range(0,(n_max+1)**2): 647 | mpfr_clear(cholesky_decomposed[i]) 648 | free(cholesky_decomposed) 649 | 650 | result = np.ndarray([n_max+1,n_max+1],dtype='O') 651 | for i in range(0,n_max+1): 652 | for j in range(0,n_max+1): 653 | result[i][j]=(field)._new() 654 | mpfr_init2((result[i][j]).value,prec) 655 | mpfr_set((result[i][j]).value,inversed[i*(n_max+1)+j],MPFR_RNDN) 656 | (result[i][j])._parent=field 657 | mpfr_clear(inversed[i*(n_max+1)+j]) 658 | 659 | free(inversed) 660 | return result 661 | 662 | 663 | def max_index(_v): 664 | return sorted(map(lambda x,y:[x,y],_v,range(0,len(_v))),key=lambda x:x[0].abs(),reverse=True)[0][1] 665 | 666 | def normalizing_component_subtract(m,normalizing_vector): 667 | __index = max_index(normalizing_vector) 668 | __deleted_normalizing_vector = (1/normalizing_vector[__index])*np.delete(normalizing_vector,__index) 669 | if not (len(m) == len(normalizing_vector)): 670 | raise RuntimeError("length of normalizing vector and target object must be equal.") 671 | return np.insert(np.delete(m,__index,0)-__deleted_normalizing_vector*m[__index],0,m[__index]/normalizing_vector[__index]) 672 | 673 | def recover_functional(alpha,normalizing_vector): 674 | __index = max_index(normalizing_vector) 675 | __deleted_normalizing_vector = (1/normalizing_vector[__index])*np.delete(normalizing_vector,__index) 676 | if not (len(alpha) == (len(normalizing_vector)-1)): 677 | raise RuntimeError("length of normalizing vector and target object must be equal.") 678 | alpha_deleted=(1/normalizing_vector[__index])-alpha.dot(__deleted_normalizing_vector) 679 | return np.insert(alpha,__index,alpha_deleted) 680 | 681 | 682 | find_y=re.compile(r'y *= *\{([^\}]+)\}') 683 | 684 | def efm_from_sdpb_output(file_path,normalizing_vector,context): 685 | data_stream=open(file_path) 686 | data_text=data_stream.read() 687 | data_stream.close() 688 | yres_text=find_y.search(data_text).groups()[0] 689 | vector_text=re.split(r', ', yres_text) 690 | y_result=np.array([context.field(x) for x in vector_text]) 691 | return recover_functional(y_result,normalizing_vector) 692 | 693 | 694 | def write_real_num(file_stream,real_num,tag): 695 | file_stream.write(("<"+tag+">")) 696 | file_stream.write(repr(real_num)) 697 | file_stream.write(("\n")) 698 | 699 | def write_vector(file_stream,name,vector): 700 | file_stream.write("<"+name+">\n") 701 | map(lambda x:write_real_num(file_stream,x,"elt"),vector) 702 | file_stream.write("\n") 703 | 704 | def write_polynomial(file_stream,polynomial): 705 | file_stream.write("\n") 706 | try: 707 | __temp=polynomial.list() 708 | except AttributeError: 709 | __temp=[polynomial] 710 | #map(lambda x:write_real_num(file_stream,x,"coeff"), (lambda y: [0] if y ==[] else y )(polynomial.list())) 711 | if __temp==[]: 712 | __temp=[0] 713 | map(lambda x:write_real_num(file_stream,x,"coeff"),__temp) 714 | file_stream.write("\n") 715 | 716 | def write_polynomial_vector(file_stream,polynomialVector): 717 | file_stream.write("\n") 718 | map(lambda x:write_polynomial(file_stream,x),polynomialVector) 719 | file_stream.write("\n") 720 | 721 | def laguerre_sample_points(n,field,rho): 722 | return map(lambda k:(field(3.141592))**2*(-1+4*k)**2/(-64*n*(4*rho).log()),range(0,n)) 723 | 724 | def format_poleinfo(poles,context=None): 725 | if context==None: 726 | field=lambda x:x 727 | else: 728 | field=context.field 729 | if isinstance(poles,dict): 730 | res=[[field(x),poles[x]] for x in poles] 731 | return dict(res) 732 | elif isinstance(poles,list): 733 | if poles==[]: 734 | return {} 735 | elif not isinstance(poles[0],list): 736 | m=dict([[x,1] for x in poles]) 737 | for x in m: 738 | m[x]=poles.count(x) 739 | return dict([[field(x),m[x]] for x in m]) 740 | elif len(poles[0])==2: 741 | try: 742 | res=[[field(x[0]),x[1]] for x in poles] 743 | return dict(res) 744 | except TypeError: 745 | raise TypeError("unreadable initialization for poles") 746 | else: 747 | raise TypeError("unreadable initialization for poles") 748 | 749 | 750 | def __dict_add(dict1,dict2): 751 | return dict([(x,dict1[x]+dict2[x]) for x in dict2 if x in dict1]\ 752 | +[(x,dict2[x]) for x in dict2 if x not in dict1]\ 753 | +[(x,dict1[x]) for x in dict1 if x not in dict2]) 754 | 755 | 756 | cdef class damped_rational: 757 | def __cinit__(self,poles,base,c,cb_universal_context context): 758 | self.base=context.field(base) 759 | self.pref_constant=context.field(c) 760 | self.context=context 761 | 762 | def __init__(self,poles,base,c,cb_universal_context context): 763 | self.poles=format_poleinfo(poles,context) 764 | 765 | def shift(self,shift): 766 | new_poles=[[x-shift,self.poles[x]] for x in self.poles.keys()] 767 | new_const=self.pref_constant*self.base**shift 768 | return damped_rational(new_poles,self.base,new_const,self.context) 769 | 770 | def __call__(self,x): 771 | return self.pref_constant*(self.base**x)*(1/reduce(lambda z,w:z*w,[(x-y)**(self.poles[y]) for y in self.poles.keys()],1)) 772 | def orthogonal_polynomial(self,order): 773 | passed_poles=[[x,self.poles[x]] for x in self.poles.keys()] 774 | return anti_band_cholesky_inverse(prefactor_integral(passed_poles,self.base, order, self.context.precision, self.pref_constant), order//2,self.context.precision) 775 | 776 | def __mul__(self,y): 777 | if isinstance(y,damped_rational): 778 | res_poles=copy.copy(self.poles) 779 | orig_keys=res_poles.keys() 780 | for x in y.poles.keys(): 781 | if x in orig_keys: 782 | res_poles[x]=res_poles[x]+y.poles[x] 783 | else: 784 | res_poles.update({x:y.poles[x]}) 785 | new_base=self.base*y.base 786 | new_const=self.pref_constant*y.pref_constant 787 | return damped_rational(res_poles,new_base,new_const,self.context) 788 | else: 789 | raise TypeError("damped_rational must be multiplied with itself") 790 | 791 | def add_poles(self,location): 792 | location_new=format_poleinfo(location) 793 | res_poles=copy.copy(self.poles) 794 | for x in location_new.keys(): 795 | if x in res_poles.keys(): 796 | res_poles[x]=res_poles[x]+location_new[x] 797 | else: 798 | res_poles.update({x:location_new[x]}) 799 | return damped_rational(res_poles,self.base,self.pref_constant,self.context) 800 | def remove_poles(self,location): 801 | res_poles=copy.copy(self.poles) 802 | location_new=format_poleinfo(location) 803 | for x in location_new.keys(): 804 | if x in res_poles.keys(): 805 | ind=res_poles[x]-location_new[x] 806 | if ind>0: 807 | res_poles[x]=ind 808 | elif ind==0: 809 | del res_poles[x] 810 | else: 811 | raise RuntimeError("could not delete pole") 812 | else: 813 | raise RuntimeError("could not delete pole") 814 | return damped_rational(res_poles,self.base,self.pref_constant,self.context) 815 | 816 | #def lcm_new(self,p): 817 | def lcm(self,p): 818 | if isinstance(p,damped_rational): 819 | if not self.base==p.base: 820 | raise RuntimeError("two damped-rational must have the same base!") 821 | if p==self: 822 | return (self,{},{}) 823 | else: 824 | raise TypeError("lcm supported only between damped_rationals") 825 | 826 | dict1=self.poles 827 | dict2=p.poles 828 | 829 | def help_lcm(x): 830 | val1=dict1[x] 831 | val2=dict2[x] 832 | if val1 > val2: 833 | return ((x,val1),(x,0),(x,val1-val2)) 834 | elif val2 > val1: 835 | return ((x,val2),(x,val2-val1),(x,0)) 836 | else: 837 | return ((x,val2),(x,0),(x,0)) 838 | 839 | result_1,self_rem,p_rem =\ 840 | zip(*(help_lcm(x) for x in dict2 if x in dict1)) 841 | 842 | l1=[(x,dict2[x]) for x in dict2 if x not in dict1] 843 | l2=[(x,dict1[x]) for x in dict1 if x not in dict2] 844 | 845 | result_poles=dict(list(result_1)+l1+l2) 846 | numerator_for_self = dict(l1+[x for x in self_rem if x[1]!=0]) 847 | numerator_for_p = dict(l2+[x for x in p_rem if x[1]!=0]) 848 | 849 | res=damped_rational(result_poles,self.base,\ 850 | self.context(1),self.context) 851 | return res, numerator_for_self, numerator_for_p 852 | 853 | def __repr__(self): 854 | output=repr(self.pref_constant)+"*("+repr(self.base)+")**Delta /" 855 | for x in self.poles: 856 | output=output+"(Delta" 857 | if x>0: 858 | output=output+"-"+repr(x) + ")" 859 | elif x==0: 860 | output=output+")" 861 | else: 862 | output=output+"+"+repr(-x) + ")" 863 | if not self.poles[x]==1: 864 | output=output+"**"+repr(self.poles[x]) 865 | output=output+"*" 866 | return output[:-1] 867 | 868 | def __richcmp__(x, y, op): 869 | if op == 2:#Py_EQ 870 | return x.__is_equal(y) 871 | if op == 3:#Py_NE 872 | return not x.__is_equal(y) 873 | else: 874 | assert False 875 | 876 | def __is_equal(self,x): 877 | if not isinstance(x,damped_rational): 878 | return False 879 | if self.base==x.base and self.pref_constant==x.pref_constant\ 880 | and self.poles == x.poles: 881 | return True 882 | else: 883 | return False 884 | 885 | cdef class positive_matrix_with_prefactor: 886 | def __cinit__(self, damped_rational prefactor, matrix, cb_universal_context context): 887 | self.prefactor=prefactor 888 | self.context = context 889 | 890 | def __init__(self, damped_rational prefactor, matrix, context): 891 | self.matrix=(matrix) 892 | 893 | def shift(self,x): 894 | return positive_matrix_with_prefactor(self.prefactor.shift(x),self.context.polynomial_vector_shift(self.matrix,x),self.context) 895 | 896 | def degree_max(self): 897 | try: 898 | return max((np.vectorize(lambda y:self.context.Delta_Field(y).degree())(self.matrix)).flatten()) 899 | except AttributeError: 900 | return 0 901 | 902 | def normalization_subtract(self,v): 903 | return normalizing_component_subtract(self.matrix,v) 904 | 905 | def write(self,file_stream,v): 906 | shuffled_matrix=np.array(map(lambda x:map(lambda y:normalizing_component_subtract(y,v),x),self.matrix)) 907 | sample_points = laguerre_sample_points(self.degree_max()+1,self.context.field,self.context.rho) 908 | sample_scalings=map(self.prefactor,sample_points) 909 | orthogonal_polynomial_vector=map(self.context.Delta_Field,self.prefactor.orthogonal_polynomial(self.degree_max())) 910 | 911 | file_stream.write("\n") 912 | file_stream.write("\n") 913 | file_stream.write(repr(len(shuffled_matrix))) 914 | file_stream.write("\n") 915 | file_stream.write("\n") 916 | file_stream.write(repr(len(shuffled_matrix[0]))) 917 | file_stream.write("\n") 918 | file_stream.write("\n") 919 | map(lambda x:map(lambda y:write_polynomial_vector(file_stream,y),x),shuffled_matrix) 920 | file_stream.write("\n") 921 | write_vector(file_stream,"samplePoints",sample_points) 922 | write_vector(file_stream,"sampleScalings",sample_scalings) 923 | file_stream.write("\n") 924 | map(lambda x :write_polynomial(file_stream,x),orthogonal_polynomial_vector) 925 | file_stream.write("\n") 926 | file_stream.write("\n") 927 | 928 | def reshape(self,shape=None): 929 | if len(self.matrix.shape)==3 and self.matrix.shape[0]==self.matrix.shape[1] and not shape: 930 | return self 931 | if not shape: 932 | shape=(1,1,self.matrix.shape[-1]) 933 | new_b=self.matrix.reshape(shape) 934 | return prefactor_numerator(self.prefactor,new_b,self.context) 935 | 936 | 937 | 938 | 939 | cdef class prefactor_numerator(positive_matrix_with_prefactor): 940 | def add_poles(self,poles): 941 | new_pref=self.prefactor.add_poles(poles) 942 | return prefactor_numerator(new_pref,self.matrix,self.context) 943 | 944 | def rdot(self,M): 945 | newBody=M.dot(self.matrix) 946 | return prefactor_numerator(self.prefactor,newBody,self.context) 947 | 948 | def shift(self,x): 949 | return prefactor_numerator(self.prefactor.shift(x),self.context.polynomial_vector_shift(self.matrix,x),self.context) 950 | 951 | def multiply_factored_polynomial(self,factors,C): 952 | """ 953 | multiply C*\Prod _x (Delta - x)**(factors[x])! 954 | where x in factors 955 | """ 956 | formated_poles=format_poleinfo(factors) 957 | res_poles=copy.copy(self.prefactor.poles) 958 | numr_new=format_poleinfo(factors) 959 | pole_keys=res_poles.keys() 960 | remnant={} 961 | for x in numr_new.keys(): 962 | if x in pole_keys: 963 | val_pole=res_poles[x] 964 | val_numr=numr_new[x] 965 | if val_pole < val_numr: 966 | del res_poles[x] 967 | remnant.update({x:val_numr-val_pole}) 968 | elif val_pole==val_numr: 969 | del res_poles[x] 970 | else: 971 | res_poles[x]=val_pole-val_numr 972 | else: 973 | remnant.update({x:numr_new[x]}) 974 | remnant_poly=self.prefactor.pref_constant*reduce(lambda x,y:x*y,[(self.context.Delta -z)**remnant[z] for z in remnant],1) 975 | result_numr=C*remnant_poly*self.matrix 976 | result_pref=damped_rational(res_poles,self.prefactor.base,1,self.context) 977 | return prefactor_numerator(result_pref,result_numr,self.context) 978 | 979 | def multiply_factored_rational(self,poles,factors,C): 980 | return self.add_poles(poles).multiply_factored_polynomial(factors,C) 981 | 982 | def __rmul__(self,x): 983 | new_mat=x*self.matrix 984 | return prefactor_numerator(self.prefactor,new_mat,self.context) 985 | 986 | def __neg__(self): 987 | new_mat=-self.matrix 988 | return prefactor_numerator(self.prefactor,new_mat,self.context) 989 | 990 | def __div__(self,x): 991 | new_mat=self.matrix/x 992 | return prefactor_numerator(self.prefactor,new_mat,self.context) 993 | 994 | def __add__(self,other): 995 | if not isinstance(other,prefactor_numerator): 996 | raise TypeError("must be added to another prefactor_numerator") 997 | new_pref,remnant_1,remnant_2=self.prefactor.lcm(other.prefactor) 998 | res_poles=new_pref.poles 999 | remnant_poly1=reduce(lambda x,y:x*y,[(self.context.Delta -z)**remnant_1[z] for z in remnant_1],\ 1000 | self.prefactor.pref_constant) 1001 | remnant_poly2=reduce(lambda x,y:x*y,[(self.context.Delta -z)**remnant_2[z] for z in remnant_2],\ 1002 | other.prefactor.pref_constant) 1003 | new_matrix=remnant_poly1*self.matrix \ 1004 | + remnant_poly2*other.matrix 1005 | return prefactor_numerator(new_pref,new_matrix,self.context) 1006 | 1007 | 1008 | # def __add__(self,other): 1009 | # if not isinstance(other,prefactor_numerator): 1010 | # raise TypeError("must be added to another prefactor_numerator") 1011 | # new_pref=self.prefactor.lcm(other.prefactor)[0] 1012 | # res_poles=new_pref.poles 1013 | # remnant_1=copy.copy(res_poles) 1014 | # remnant_2=copy.copy(res_poles) 1015 | # for x in self.prefactor.poles: 1016 | # if x in remnant_1: 1017 | # new_v=res_poles[x]-self.prefactor.poles[x] 1018 | # if new_v==0: 1019 | # del remnant_1[x] 1020 | # else: 1021 | # remnant_1[x]=new_v 1022 | # for x in other.prefactor.poles: 1023 | # if x in remnant_2: 1024 | # new_v=res_poles[x]-other.prefactor.poles[x] 1025 | # if new_v==0: 1026 | # del remnant_2[x] 1027 | # else: 1028 | # remnant_2[x]=new_v 1029 | # remnant_poly1=reduce(lambda x,y:x*y,[(self.context.Delta -z)**remnant_1[z] for z in remnant_1],\ 1030 | # self.prefactor.pref_constant) 1031 | # remnant_poly2=reduce(lambda x,y:x*y,[(self.context.Delta -z)**remnant_2[z] for z in remnant_2],\ 1032 | # other.prefactor.pref_constant) 1033 | # new_matrix=remnant_poly1*self.matrix + remnant_poly2*other.matrix 1034 | # return prefactor_numerator(new_pref,new_matrix,self.context) 1035 | 1036 | def new_join(self,other): 1037 | if not isinstance(other,prefactor_numerator): 1038 | raise TypeError("must be joined with another prefactor_numerator instance") 1039 | new_pref, remnant_1,remnant_2=self.prefactor.lcm(other.prefactor) 1040 | res_poles=new_pref.poles 1041 | remnant_poly1=reduce(lambda x,y:x*y,[(self.context.Delta -z)**remnant_1[z] for z in remnant_1],\ 1042 | self.prefactor.pref_constant) 1043 | remnant_poly2=reduce(lambda x,y:x*y,[(self.context.Delta -z)**remnant_2[z] for z in remnant_2],\ 1044 | other.prefactor.pref_constant) 1045 | new_matrix=np.concatenate((remnant_poly1*self.matrix,remnant_poly2*other.matrix)) 1046 | return prefactor_numerator(new_pref,new_matrix,self.context) 1047 | 1048 | def __sub__(self,x): 1049 | if not isinstance(x,prefactor_numerator): 1050 | raise TypeError("must be added to another prefactor_numerator") 1051 | return self.__add__(x.__neg__()) 1052 | 1053 | def __call__(self,x): 1054 | pref=self.prefactor(x) 1055 | body=self.context.polynomial_vector_evaluate(self.matrix,x) 1056 | return pref*body 1057 | 1058 | def __repr__(self): 1059 | return repr(self.prefactor)+"\n*"+repr(self.matrix) 1060 | 1061 | 1062 | def find_local_minima(pol,label,field=RR,context=None): 1063 | solpol=pol.derivative() 1064 | solpol2=solpol.derivative()*pol - solpol**2 1065 | sols=solpol.roots() 1066 | sols=[x[0] for x in sols if x[0]>0 ] 1067 | minsols=[[label,RR(x)] for x in sols if (solpol2(x) > 0)] 1068 | return minsols 1069 | 1070 | def functional_to_spectra(ef_path,problem,context,label=None): 1071 | norm=problem.normalization 1072 | pvm=problem.pvm 1073 | alpha=efm_from_sdpb_output(ef_path,norm,context) 1074 | polys=[Matrix(x.matrix.dot(alpha)).det() for x in pvm] 1075 | if label==None: 1076 | label=range(0,len(polys)) 1077 | efmread=map(lambda x: find_local_minima(x[0],x[1]),zip(polys,label)) 1078 | return efmread 1079 | 1080 | 1081 | class SDP: 1082 | def __init__(self,normalization,objective,pvm,label=None,context=None): 1083 | self.pvm = [x.reshape() if (isinstance(x,positive_matrix_with_prefactor)\ 1084 | or isinstance(x,prefactor_numerator)) \ 1085 | else 1086 | context.vector_to_prefactor_numerator(x).reshape() \ 1087 | for x in pvm] 1088 | self.normalization=normalization 1089 | self.objective=objective 1090 | self.label=label 1091 | self.context=context 1092 | def write(self,file_path): 1093 | file_stream=open(file_path,'w') 1094 | file_stream.write("\n") 1095 | write_vector(file_stream,"objective",normalizing_component_subtract(self.objective,self.normalization)) 1096 | file_stream.write("\n") 1097 | for x in self.pvm: 1098 | x.write(file_stream,self.normalization) 1099 | file_stream.write("\n") 1100 | file_stream.write("\n") 1101 | file_stream.close() 1102 | -------------------------------------------------------------------------------- /context_variables.c: -------------------------------------------------------------------------------- 1 | #include "context_variables.h" 2 | 3 | 4 | /* basic constructor for cb_context */ 5 | cb_context context_construct(long n_Max, mpfr_prec_t prec, int lambda){ 6 | cb_context result; 7 | result.n_Max = n_Max; 8 | result.prec = prec; 9 | result.rnd = MPFR_RNDN; 10 | result.rho_to_z_matrix = compute_rho_to_z_matrix(lambda,prec); 11 | 12 | result.lambda = lambda; 13 | mpfr_init2(result.rho, prec); 14 | mpfr_set_ui(result.rho,8, MPFR_RNDN); 15 | mpfr_sqrt(result.rho,result.rho,MPFR_RNDN); 16 | mpfr_ui_sub(result.rho,3,result.rho,MPFR_RNDN); 17 | return result; 18 | } 19 | 20 | void clear_cb_context(cb_context context){ 21 | for(int i=0;i<=context.lambda;i++){ 22 | for(int j=0;j<=context.lambda;j++){ 23 | mpfr_clear(context.rho_to_z_matrix[i*(context.lambda+1)+j]); 24 | } 25 | } 26 | free(context.rho_to_z_matrix); 27 | mpfr_clear(context.rho); 28 | } 29 | 30 | mpfr_t* compute_rho_to_z_matrix(unsigned long Lambda_arg, long prec){ 31 | /* To avoid writing lambda + 1 so many times...*/ 32 | unsigned long Lambda=Lambda_arg+1; 33 | mpfr_t* temps=malloc(sizeof(mpfr_t)*(Lambda)); 34 | mpfr_init2(temps[0],prec); 35 | mpfr_set_ui(temps[0],8,MPFR_RNDN); 36 | mpfr_sqrt(temps[0],temps[0],MPFR_RNDN); 37 | mpfr_neg(temps[0],temps[0],MPFR_RNDN); 38 | for(unsigned long j=1;j 0.001: 41 | D_try=(upper+lower)/2 42 | prob=sdp_method(delta,{0:D_try}) 43 | prob.write("3d_Ising_binary.xml") 44 | sdpbargs=[sdpb,"-s","3d_Ising_binary.xml"]+sdpbparams 45 | out, err=Popen(sdpbargs,stdout=PIPE,stderr=PIPE).communicate() 46 | sol=re.compile(r'found ([^ ]+) feasible').search(out).groups()[0] 47 | if sol=="dual": 48 | print("(Delta_phi, Delta_epsilon)={0} is excluded."\ 49 | .format((float(delta),float(D_try)))) 50 | upper=D_try 51 | elif sol=="primal": 52 | print("(Delta_phi, Delta_epsilon)={0} is not excluded."\ 53 | .format((float(delta),float(D_try)))) 54 | lower=D_try 55 | else: 56 | raise RuntimeError("Unexpected return from sdpb") 57 | return upper 58 | 59 | def make_SDP_for_cc(delta,gap_dict={0:1}): 60 | delta=context(delta) 61 | Fs=[make_F(delta,spin,gap_dict) for spin in cbs.keys()] 62 | mat_F=context.F_minus_matrix(delta) 63 | norm=context.dot(mat_F,context.gBlock(2,3,0,0)) 64 | obj=context.dot(mat_F,context.gBlock(0,0,0,0)) 65 | return context.SDP(norm,obj,Fs) 66 | 67 | def cc(delta): 68 | prob=make_SDP_for_cc(delta) 69 | prob.write("3d_Ising_cc.xml") 70 | sdpbargs=[sdpb,"-s","3d_Ising_cc.xml","--noFinalCheckpoint"] 71 | out, err=Popen(sdpbargs,stdout=PIPE,stderr=PIPE).communicate() 72 | sol=re.compile(r'primalObjective *= *([^ ]+) *$',re.MULTILINE)\ 73 | .search(out).groups()[0] 74 | return -delta**2/float(sol) 75 | 76 | def make_SDP_epsilon_prime(delta,gap_dict): 77 | delta=context(delta) 78 | Fs=[make_F(delta,spin,gap_dict) for spin in cbs.keys()] 79 | mat_F=context.F_minus_matrix(delta) 80 | Fs+=[context.dot(mat_F,context.gBlock(0,delta,0,0))] 81 | norm=context.dot(mat_F,context.gBlock(0,0,0,0)) 82 | obj=norm*0 83 | return context.SDP(norm,obj,Fs) 84 | 85 | if __name__=='__main__': 86 | # The default example 87 | delta=0.518 88 | print(bs(delta)) 89 | 90 | # =============================================== 91 | # if you want to derive the central charge lower bound, 92 | # uncomment the follwing lines. 93 | #delta=0.518 94 | #print("central charge lower bound at delta={0} is {1}"\ 95 | # .format(delta,cc(delta))) 96 | 97 | # =============================================== 98 | # The upper bound on epsilon' dimension. 99 | #Delta_epsilon=0.8 100 | #print(bs(Delta_epsilon,sdp_method=make_SDP_epsilon_prime)) 101 | -------------------------------------------------------------------------------- /examples/3dOn.py: -------------------------------------------------------------------------------- 1 | import sage.cboot as cb 2 | import numpy as np 3 | from subprocess import Popen, PIPE 4 | import re 5 | 6 | context=cb.context_for_scalar(epsilon=0.5,Lambda=13) 7 | lmax=25 8 | nu_max=12 9 | cbs={} 10 | for spin in range(0,lmax): 11 | g=context.approx_cb(nu_max,spin) 12 | cbs.update({spin:g}) 13 | 14 | def make_F(delta,sector,spin,gap_dict,NSO): 15 | delta=context(delta) 16 | try: 17 | gap=context(gap_dict[(sector,spin)]) 18 | except KeyError: 19 | if spin==0: 20 | gap=context.epsilon 21 | else: 22 | gap=2*context.epsilon+spin 23 | g_shift=cbs[spin].shift(gap) 24 | 25 | g_num=g_shift.matrix 26 | g_pref=g_shift.prefactor 27 | F=context.F_minus_matrix(delta).dot(g_num) 28 | H=context.F_plus_matrix(delta).dot(g_num) 29 | 30 | if sector=="S": 31 | num=np.concatenate((context.null_ftype,F,H)) 32 | 33 | elif sector=="T": 34 | num=np.concatenate((F,(1-2/context(NSO))*F,-(1+2/context(NSO))*H)) 35 | 36 | elif sector=="A": 37 | num=np.concatenate((-F,F,-H)) 38 | 39 | return context.prefactor_numerator(g_pref,num) 40 | 41 | def make_SDP(delta,gap_dict,NSO=2): 42 | delta=context(delta) 43 | pvms=[] 44 | for sector in ("S","T","A"): 45 | if sector is not "A": 46 | spins=[spin for spin in cbs.keys() if not spin%2] 47 | else: 48 | spins=[spin for spin in cbs.keys() if spin%2] 49 | for spin in spins: 50 | pvms.append(make_F(delta,sector,spin,gap_dict,NSO)) 51 | 52 | norm_F=context.F_minus_matrix(delta).dot(context.gBlock(0,0,0,0)) 53 | norm_H=context.F_plus_matrix(delta).dot(context.gBlock(0,0,0,0)) 54 | norm=np.concatenate((context.null_ftype,norm_F,norm_H)) 55 | 56 | obj=norm*0 57 | return context.SDP(norm,obj,pvms) 58 | 59 | sdpb="sdpb" 60 | sdpbparams=["--findPrimalFeasible","--findDualFeasible","--noFinalCheckpoint"] 61 | 62 | def bs(delta,upper=3,lower=1,sector="S",sdp_method=make_SDP,NSO=2): 63 | upper=context(upper) 64 | lower=context(lower) 65 | while upper - lower > 0.001: 66 | D_try=(upper+lower)/2 67 | prob=sdp_method(delta,{(sector,0):D_try},NSO=NSO) 68 | prob.write("3d_Ising_binary.xml") 69 | sdpbargs=[sdpb,"-s","3d_Ising_binary.xml"]+sdpbparams 70 | out, err=Popen(sdpbargs,stdout=PIPE,stderr=PIPE).communicate() 71 | sol=re.compile(r'found ([^ ]+) feasible').search(out).groups()[0] 72 | if sol=="dual": 73 | print("(Delta_phi, Delta_{1})={0} is excluded."\ 74 | .format((float(delta),float(D_try)),sector)) 75 | upper=D_try 76 | elif sol=="primal": 77 | print("(Delta_phi, Delta_{1})={0} is not excluded."\ 78 | .format((float(delta),float(D_try)),sector)) 79 | lower=D_try 80 | else: 81 | raise RuntimeError("Unexpected return from sdpb") 82 | return upper 83 | 84 | 85 | if __name__=="__main__": 86 | # The default example 87 | print bs(0.52) 88 | 89 | # ====================================== 90 | # if you want to derive the bound on Delta_T 91 | #print bs(0.52,sector="T") 92 | 93 | 94 | -------------------------------------------------------------------------------- /examples/3dOn2.py: -------------------------------------------------------------------------------- 1 | import sage.cboot as cb 2 | import numpy as np 3 | from subprocess import Popen, PIPE 4 | import re 5 | 6 | context=cb.context_for_scalar(epsilon=0.5,Lambda=13) 7 | lmax=25 8 | nu_max=12 9 | cbs={} 10 | for spin in range(0,lmax): 11 | g=context.approx_cb(nu_max,spin) 12 | cbs.update({spin:g}) 13 | 14 | def make_F(delta,sector,spin,gap_dict,NSO,Delta=None): 15 | delta=context(delta) 16 | if Delta==None: 17 | try: 18 | gap=context(gap_dict[(sector,spin)]) 19 | except KeyError: 20 | if spin==0: 21 | gap=context.epsilon 22 | else: 23 | gap=2*context.epsilon+spin 24 | g=cbs[spin].shift(gap) 25 | else: 26 | Delta=context(Delta) 27 | g=context.gBlock(spin,Delta,0,0) 28 | F=context.dot(context.F_minus_matrix(delta),g) 29 | H=context.dot(context.F_plus_matrix(delta),g) 30 | 31 | if sector=="S": 32 | return [0,F,H] 33 | 34 | elif sector=="T": 35 | return [F,(1-2/context(NSO))*F,-(1+2/context(NSO))*H] 36 | 37 | elif sector=="A": 38 | return [-F,F,-H] 39 | 40 | def make_SDP(delta,gap_dict,NSO=2): 41 | delta=context(delta) 42 | pvms=[] 43 | for sector in ("S","T","A"): 44 | if sector is not "A": 45 | spins=[spin for spin in cbs.keys() if not spin%2] 46 | else: 47 | spins=[spin for spin in cbs.keys() if spin%2] 48 | for spin in spins: 49 | pvms.append(make_F(delta,sector,spin,gap_dict,NSO)) 50 | 51 | norm=make_F(delta,"S",0,None,NSO,Delta=0) 52 | obj=0 53 | return context.sumrule_to_SDP(norm,obj,pvms) 54 | 55 | 56 | sdpb="sdpb" 57 | sdpbparams=["--findPrimalFeasible","--findDualFeasible","--noFinalCheckpoint","--maxThreads","12"] 58 | 59 | def bs(delta,upper=3,lower=1,sector="S",sdp_method=make_SDP,NSO=2): 60 | upper=context(upper) 61 | lower=context(lower) 62 | while upper - lower > 0.001: 63 | D_try=(upper+lower)/2 64 | prob=sdp_method(delta,{(sector,0):D_try},NSO=NSO) 65 | prob.write("3d_On_binary.xml") 66 | sdpbargs=[sdpb,"-s","3d_On_binary.xml"]+sdpbparams 67 | out, err=Popen(sdpbargs,stdout=PIPE,stderr=PIPE).communicate() 68 | sol=re.compile(r'found ([^ ]+) feasible').search(out).groups()[0] 69 | if sol=="dual": 70 | print("(Delta_phi, Delta_{1})={0} is excluded."\ 71 | .format((float(delta),float(D_try)),sector)) 72 | upper=D_try 73 | elif sol=="primal": 74 | print("(Delta_phi, Delta_{1})={0} is not excluded."\ 75 | .format((float(delta),float(D_try)),sector)) 76 | lower=D_try 77 | else: 78 | raise RuntimeError("Unexpected return from sdpb") 79 | return upper 80 | 81 | def make_SDP_ccc(delta,gap_dict,NSO): 82 | delta=context(delta) 83 | pvms=[] 84 | for sector in ("S","T","A"): 85 | if sector is not "A": 86 | spins=[spin for spin in cbs.keys() if not spin%2] 87 | else: 88 | spins=[spin for spin in cbs.keys() if spin%2] 89 | for spin in spins: 90 | pvms.append(make_F(delta,sector,spin,gap_dict,NSO)) 91 | 92 | norm=make_F(delta,"A",1,None,NSO,Delta=1+2*context.epsilon) 93 | obj=make_F(delta,"S",0,None,NSO,Delta=0) 94 | return context.sumrule_to_SDP(norm,obj,pvms) 95 | 96 | def ccc(delta,NSO=20): 97 | prob=make_SDP_ccc(delta,{},NSO) 98 | prob.write("3d_On_ccc.xml") 99 | sdpbargs=[sdpb,"-s","3d_On_ccc.xml","--noFinalCheckpoint"] 100 | out, err=Popen(sdpbargs,stdout=PIPE,stderr=PIPE).communicate() 101 | sol=re.compile(r'primalObjective *= *([^ ]+) *$',re.MULTILINE)\ 102 | .search(out).groups()[0] 103 | return -1/float(sol) 104 | 105 | if __name__=="__main__": 106 | # The default example 107 | print bs(0.52) 108 | 109 | # ====================================== 110 | # if you want to derive the bound on Delta_T 111 | #print bs(0.52,sector="T") 112 | 113 | # ====================================== 114 | # Current central charge lowr bound for O(20) 115 | #print ccc(0.50639,NSO=20)/2 116 | # Delta_phi value 0.50369 is taken from 1307.6856 117 | #Large N prediction for O(20) vector model is 0.9639 118 | -------------------------------------------------------------------------------- /examples/mixed_ising.py: -------------------------------------------------------------------------------- 1 | import sage.cboot as cb 2 | from sage.misc.cachefunc import cached_function 3 | from subprocess import Popen, PIPE 4 | import re 5 | 6 | sdpb="sdpb" 7 | sdpbparams=["--findPrimalFeasible","--findDualFeasible","--noFinalCheckpoint"] 8 | 9 | context=cb.context_for_scalar(epsilon=0.5,Lambda=11) 10 | lmax=20 11 | nu_max=8 12 | 13 | @cached_function 14 | def prepare_g_0(spin,Delta=None): 15 | return context.approx_cb(nu_max,spin) 16 | 17 | @cached_function 18 | def prepare_g_se(spin,Delta_se,Delta=None): 19 | g_se=context.approx_cb(nu_max,spin,Delta_1_2=Delta_se,Delta_3_4=Delta_se) 20 | return g_se 21 | 22 | @cached_function 23 | def prepare_g_es(spin,Delta_se,Delta=None): 24 | g_es=context.approx_cb(nu_max,spin,Delta_1_2=-Delta_se,Delta_3_4=Delta_se) 25 | return g_es 26 | 27 | def prepare_g(spin,Delta_se,Delta=None): 28 | if Delta==None: 29 | return (prepare_g_0(spin), 30 | prepare_g_se(spin,Delta_se), 31 | prepare_g_es(spin,Delta_se)) 32 | else: 33 | g_0=context.gBlock(spin,Delta,0,0) 34 | if not (Delta==0 and spin==0): 35 | g_se=context.gBlock(spin,Delta,Delta_se,Delta_se) 36 | g_es=context.gBlock(spin,Delta,-Delta_se,Delta_se) 37 | else: 38 | g_se=None 39 | g_es=None 40 | return (g_0,g_se,g_es) 41 | 42 | def make_F(deltas,sector,spin,gap_dict,Delta=None): 43 | delta_s=context(deltas[0]) 44 | delta_e=context(deltas[1]) 45 | Delta_se=delta_s-delta_e 46 | if Delta==None: 47 | try: 48 | shift=context(gap_dict[(sector,spin)]) 49 | except KeyError: 50 | if spin==0: 51 | shift=context.epsilon 52 | else: 53 | shift=2*context.epsilon+spin 54 | gs=[x.shift(shift) for x in prepare_g(spin,Delta_se,Delta=Delta)] 55 | else: 56 | gs=prepare_g(spin,Delta_se,Delta=Delta) 57 | 58 | if sector=="even": 59 | F_s_s=context.dot(context.F_minus_matrix(delta_s),gs[0]) 60 | F_e_e=context.dot(context.F_minus_matrix(delta_e),gs[0]) 61 | 62 | F_s_e=context.dot(context.F_minus_matrix((delta_s+delta_e)/2),gs[0]) 63 | H_s_e=context.dot(context.F_plus_matrix((delta_s+delta_e)/2),gs[0]) 64 | return [[[F_s_s,0], 65 | [0,0]], 66 | [[0,0], 67 | [0,F_e_e]], 68 | [[0,0], 69 | [0,0]], 70 | [[0,F_s_e/2], 71 | [F_s_e/2,0]], 72 | [[0,H_s_e/2], 73 | [H_s_e/2,0]]] 74 | 75 | elif sector=="odd+": 76 | F_s_e=context.dot(context.F_minus_matrix((delta_s+delta_e)/2),gs[1]) 77 | F_e_s=context.dot(context.F_minus_matrix(delta_s),gs[2]) 78 | H_e_s=context.dot(context.F_plus_matrix(delta_s),gs[2]) 79 | 80 | return [0,0,F_s_e,F_e_s,-H_e_s] 81 | 82 | elif sector=="odd-": 83 | F_s_e=context.dot(context.F_minus_matrix((delta_s+delta_e)/2),gs[1]) 84 | F_e_s=context.dot(context.F_minus_matrix(delta_s),gs[2]) 85 | H_e_s=context.dot(context.F_plus_matrix(delta_s),gs[2]) 86 | 87 | return [0,0,-F_s_e,F_e_s,-H_e_s] 88 | else: raise RuntimeError("unknown sector name") 89 | 90 | def make_SDP(deltas): 91 | pvms=[] 92 | gaps={("even",0):3,("odd+",0):3} 93 | for spin in range(0,lmax): 94 | if not spin%2: 95 | pvms.append(make_F(deltas,"even",spin,gaps)) 96 | pvms.append(make_F(deltas,"odd+",spin,gaps)) 97 | else: 98 | pvms.append(make_F(deltas,"odd-",spin,gaps)) 99 | 100 | epsilon_contribution=make_F(deltas,"even",0,{},Delta=deltas[1]) 101 | sigma_contribution=make_F(deltas,"odd+",0,{},Delta=deltas[0]) 102 | for m,x in zip(epsilon_contribution,sigma_contribution): 103 | m[0][0]+=x 104 | pvms.append(epsilon_contribution) 105 | norm=[] 106 | for v in make_F(deltas,"even",0,{},Delta=0): 107 | norm.append(v[0][0]+v[0][1]+v[1][0]+v[1][1]) 108 | obj=0 109 | return context.sumrule_to_SDP(norm,obj,pvms) 110 | 111 | def check(*deltas): 112 | prob=make_SDP(deltas) 113 | prob.write("3d_mixed.xml") 114 | sdpbargs=[sdpb,"-s","3d_mixed.xml"]+sdpbparams 115 | out, err=Popen(sdpbargs,stdout=PIPE,stderr=PIPE).communicate() 116 | sol=re.compile(r'found ([^ ]+) feasible').search(out).groups()[0] 117 | if sol=="dual": 118 | print("(Delta_sigma, Delta_epsilon)={0} is excluded."\ 119 | .format(deltas)) 120 | elif sol=="primal": 121 | print("(Delta_sigma, Delta_epsilon)={0} is not excluded."\ 122 | .format(deltas)) 123 | else: 124 | raise RuntimeError 125 | 126 | if __name__=="__main__": 127 | for delta_s in [0.518+0.002*x for x in range(-1,2)]: 128 | for delta_e in [1.41+0.02*y for y in range(-1,2)]: 129 | check(delta_s,delta_e) 130 | -------------------------------------------------------------------------------- /examples/super_Ising.py: -------------------------------------------------------------------------------- 1 | from sage.all import * 2 | import sage.cboot as cb 3 | import numpy as np 4 | from subprocess import Popen, PIPE 5 | import re 6 | 7 | 8 | context=cb.context_for_scalar(epsilon=0.5,Lambda=13) 9 | lmax=20 10 | nu_max=12 11 | 12 | sdpb="sdpb" 13 | sdpbparams=["--findPrimalFeasible","--findDualFeasible","--noFinalCheckpoint"] 14 | 15 | def cSCblock(nu_max,spin,Delta=None): 16 | d=context.epsilon*2+2 17 | epsilon=context.epsilon 18 | pole_add_data=[((1,1),[-spin-1],[-spin],(spin+2*epsilon)/4/(spin+epsilon)),\ 19 | ((0,2),[epsilon,epsilon-1,context(-1-spin),spin+d-3],\ 20 | [0,d-3,context(-spin),context(spin+2*epsilon)],1/context(16))] 21 | if spin > 0: 22 | pole_add_data.append(((-1,1),[spin+d-3],[spin+2*epsilon]\ 23 | ,context(spin)/context(4*(spin+epsilon)))) 24 | if Delta ==None: 25 | res_g=context.approx_cb(nu_max,spin,0,0) 26 | res_g_tilde=res_g 27 | bosonic = res_g 28 | else: 29 | Delta=context(Delta) 30 | res_g=context.gBlock(spin,Delta,0,0) 31 | res_g_tilde=np.copy(res_g) 32 | bosonic=np.copy(res_g) 33 | if Delta==0: 34 | return (res_g,res_g_tilde,bosonic) 35 | for shift,poles,factors,C in pole_add_data: 36 | if Delta==None: 37 | g=context.approx_cb(nu_max,spin+shift[0]).shift(shift[1])\ 38 | .multiply_factored_rational(poles,factors,C) 39 | else: 40 | g=context.gBlock(spin+shift[0],Delta+shift[1],0,0) 41 | for x in poles: 42 | g=g/(Delta-context(x)) 43 | for x in factors: 44 | g*=(Delta-context(x)) 45 | g=g*C 46 | res_g+=g 47 | if shift[0]%2: 48 | res_g_tilde=res_g_tilde-g 49 | else: 50 | res_g_tilde=res_g_tilde+g 51 | return (res_g, res_g_tilde, bosonic) 52 | 53 | cbs={} 54 | for spin in range(0,lmax): 55 | cbs.update({spin:cSCblock(nu_max,spin)}) 56 | 57 | 58 | def make_F(delta,sector,spin,gap_dict,Delta=None): 59 | delta=context(delta) 60 | if Delta==None: 61 | try: 62 | gap=context(gap_dict[(sector,spin)]) 63 | except KeyError: 64 | if sector=="0+" or sector=="0-": 65 | gap=spin+context.epsilon*2 66 | elif sector=="2": 67 | gap=abs(2*delta-2*context.epsilon-1)+spin+(2*context.epsilon+1) 68 | gs=[x.shift(gap) for x in cbs[spin]] 69 | else: 70 | Delta=context(Delta) 71 | gs=cSCblock(0,spin,Delta=Delta) 72 | 73 | F=context.dot(context.F_minus_matrix(delta),gs[0]) 74 | H=context.dot(context.F_plus_matrix(delta),gs[0]) 75 | Ftilde=context.dot(context.F_minus_matrix(delta),gs[1]) 76 | Htilde=context.dot(context.F_plus_matrix(delta),gs[1]) 77 | Fbos=context.dot(context.F_minus_matrix(delta),gs[2]) 78 | Hbos=context.dot(context.F_plus_matrix(delta),gs[2]) 79 | 80 | if sector=="0+": 81 | return [F,Ftilde,Htilde] 82 | elif sector=="0-": 83 | return [F,-Ftilde,-Htilde] 84 | elif sector=="2": 85 | return [0,Fbos,-Hbos] 86 | 87 | def make_SDP(delta,gap_dict,norm_point=("0+",0,0),obj_point=None): 88 | delta=context(delta) 89 | pvms=[] 90 | for spin in cbs: 91 | if not spin%2: 92 | pvms.append(make_F(delta,"0+",spin,gap_dict)) 93 | pvms.append(make_F(delta,"2",spin,gap_dict)) 94 | pvms.append(make_F(delta,"2",spin,gap_dict,Delta=2*delta+spin)) 95 | 96 | else: 97 | pvms.append(make_F(delta,"0-",spin,gap_dict)) 98 | 99 | if delta < (2*context.epsilon + 2)/4: 100 | pvms.append(make_F(delta,"2",0,gap_dict,\ 101 | Delta=2*context.epsilon+2-2*delta)) 102 | 103 | norm=make_F(delta,norm_point[0],norm_point[1],{},Delta=norm_point[2]) 104 | if not obj_point: 105 | obj=0 106 | else: 107 | obj=make_F(delta,obj_point[0],obj_point[1],{},Delta=obj_point[2]) 108 | 109 | return context.sumrule_to_SDP(norm,obj,pvms) 110 | 111 | def bs(delta,upper=3,lower=1,sector="0+",sdp_method=make_SDP): 112 | upper=context(upper) 113 | lower=context(lower) 114 | while upper - lower > 0.001: 115 | D_try=(upper+lower)/2 116 | prob=sdp_method(delta,{(sector,0):D_try}) 117 | prob.write("3d_sc_binary.xml") 118 | sdpbargs=[sdpb,"-s","3d_sc_binary.xml"]+sdpbparams 119 | out, err=Popen(sdpbargs,stdout=PIPE,stderr=PIPE).communicate() 120 | sol=re.compile(r'found ([^ ]+) feasible').search(out).groups()[0] 121 | if sol=="dual": 122 | print("(Delta_phi, Delta_{1})={0} is excluded."\ 123 | .format((float(delta),float(D_try)),sector)) 124 | upper=D_try 125 | elif sol=="primal": 126 | print("(Delta_phi, Delta_{1})={0} is not excluded."\ 127 | .format((float(delta),float(D_try)),sector)) 128 | lower=D_try 129 | else: 130 | raise RuntimeError("Unexpected return from sdpb") 131 | return upper 132 | 133 | def cc(delta): 134 | prob=make_SDP(delta,{},norm_point=("0-",1,1+2*context.epsilon),\ 135 | obj_point=("0+",0,0)) 136 | prob.write("3dsc_cc.xml") 137 | sdpbargs=[sdpb,"-s","3dsc_cc.xml","--noFinalCheckpoint"] 138 | 139 | out,err=Popen(sdpbargs,stdout=PIPE,stderr=PIPE).communicate() 140 | sol=re.compile(r'primalObjective *= *([^ ]+) *$',re.MULTILINE)\ 141 | .search(out).groups()[0] 142 | return -delta**2/float(sol) 143 | 144 | 145 | if __name__=='__main__': 146 | 147 | # binary search for the N=2 super Ising model 148 | print bs(0.6666) 149 | 150 | # =============================================== 151 | # If you want to derive the central charge lower bound, 152 | # uncomment the following. 153 | #print cc(0.6666) 154 | -------------------------------------------------------------------------------- /integral_decomp.c: -------------------------------------------------------------------------------- 1 | #include "integral_decomp.h" 2 | #define deb(d)\ 3 | printf("deb %f\n",d) 4 | #undef debug_mode 5 | //#define debug_mode 1 6 | 7 | mpfr_t* simple_pole_case_c(long pole_order_max, mpfr_t base, mpfr_t pole_position, mpfr_t incomplete_gamma_factor, mpfr_prec_t prec){ 8 | 9 | mpfr_t* result=malloc(sizeof(mpfr_t)*(pole_order_max+1)); 10 | 11 | mpfr_t temp1; 12 | mpfr_init2(temp1,prec); 13 | mpfr_t temp2; 14 | mpfr_init2(temp2,prec); 15 | 16 | mpfr_t temp3; 17 | mpfr_init2(temp3,prec); 18 | 19 | mpfr_t minus_pole_position; 20 | mpfr_init2(minus_pole_position,prec); 21 | mpfr_neg(minus_pole_position,pole_position,MPFR_RNDN); 22 | 23 | mpfr_t factorial; 24 | mpfr_init2(factorial,prec); 25 | mpfr_set_ui(factorial,1,MPFR_RNDN); 26 | 27 | mpfr_t minus_log_base; 28 | mpfr_init2(minus_log_base,prec); 29 | mpfr_log(minus_log_base,base,prec); 30 | mpfr_neg(minus_log_base,minus_log_base,MPFR_RNDN); 31 | mpfr_ui_div(minus_log_base,1,minus_log_base,MPFR_RNDN); 32 | 33 | mpfr_t log_base_power; 34 | mpfr_init2(log_base_power,prec); 35 | mpfr_set(log_base_power,minus_log_base,MPFR_RNDN); 36 | 37 | mpfr_set_ui(temp1,0,MPFR_RNDN); 38 | mpfr_mul(temp2,pole_position,incomplete_gamma_factor,MPFR_RNDN); 39 | 40 | mpfr_init2(result[0],prec); 41 | mpfr_set(result[0],incomplete_gamma_factor,MPFR_RNDN); 42 | for(long j=1;j<=pole_order_max;j++){ 43 | mpfr_init2(result[j],prec); 44 | mpfr_mul(temp1,temp1,pole_position,MPFR_RNDN); 45 | mpfr_mul(temp3,factorial,log_base_power,MPFR_RNDN); 46 | mpfr_add(temp1,temp3,temp1,MPFR_RNDN); 47 | mpfr_add(result[j],temp1,temp2,MPFR_RNDN); 48 | 49 | if(j= 1){ 128 | single_pole_coeffs=malloc(sizeof(mpfr_t)*(pole_order_max)); 129 | /* x^(j+1)=( 130 | * single_pole_coeffs[0] x^(j-1) + 131 | * single_pole_coeffs[1] x^(j-2) + ... + 132 | * single_pole_coeffs[j-1] x^0 133 | * )*(x-a)^2 + 134 | * 135 | * single_pole_coeffs[j](x-a) * ((x-a) + a) 136 | * 137 | * + a^(j+1) 138 | * 139 | * => single_pole_coeffs[j+1] 140 | * 141 | * single_pole_coeffs[j+1] = single_pole_coeffs[j]*a + a^j+1 142 | * single_pole_coeffs[0] = 143 | * */ 144 | if(pole_order_max>=2){ 145 | factorial_times_power_lnb=malloc(sizeof(mpfr_t)*(pole_order_max-1)); 146 | mpfr_init2(factorial_times_power_lnb[0],prec); 147 | mpfr_set(factorial_times_power_lnb[0],minus_log_base,MPFR_RNDN); 148 | } 149 | 150 | mpfr_set(temp1,pole_position,MPFR_RNDN); 151 | /* below temp1 is used as pole_position^j*/ 152 | 153 | mpfr_init2(single_pole_coeffs[0],prec); 154 | mpfr_set_ui(single_pole_coeffs[0], 1 ,MPFR_RNDN); 155 | mpfr_add(result[1],result[1],incomplete_gamma_factor,MPFR_RNDN); 156 | 157 | for(int j=1;j<=pole_order_max-1;j++){ 158 | mpfr_init2(single_pole_coeffs[j],prec); 159 | mpfr_mul(single_pole_coeffs[j],single_pole_coeffs[j-1],pole_position,MPFR_RNDN); 160 | mpfr_add(single_pole_coeffs[j],single_pole_coeffs[j],temp1,MPFR_RNDN); 161 | 162 | mpfr_mul(temp2,single_pole_coeffs[j],incomplete_gamma_factor,MPFR_RNDN); 163 | mpfr_add(result[j+1],result[j+1],temp2,MPFR_RNDN); 164 | if(j<=pole_order_max-2){ 165 | mpfr_init2(factorial_times_power_lnb[j],prec); 166 | mpfr_mul(temp1,temp1,pole_position,MPFR_RNDN); 167 | 168 | mpfr_mul(factorial_times_power_lnb[j],factorial_times_power_lnb[j-1],minus_log_base,MPFR_RNDN); 169 | mpfr_mul_ui(factorial_times_power_lnb[j],factorial_times_power_lnb[j],j,MPFR_RNDN); 170 | } 171 | } 172 | } 173 | #ifdef debug_mode 174 | for(int j=0;j<=pole_order_max-1;j++){ 175 | mpfr_printf("single_pole_coeffs[%d] = %.16RNf\n",j,single_pole_coeffs[j]); 176 | } 177 | #endif 178 | #ifdef debug_mode 179 | for(int j=0;j<=pole_order_max-2;j++){ 180 | mpfr_printf("factorial_times_power_lnb[%d] = %.16RNf\n",j,factorial_times_power_lnb[j]); 181 | } 182 | #endif 183 | for(int j=0;j<=pole_order_max-2;j++){ 184 | for(int k=0;k<=j;k++){ 185 | mpfr_mul(temp2,factorial_times_power_lnb[k],single_pole_coeffs[j-k],MPFR_RNDN); 186 | mpfr_add(result[j+2],result[j+2],temp2,MPFR_RNDN); 187 | } 188 | } 189 | 190 | for(int i=0;i<=pole_order_max-1;i++){ 191 | mpfr_clear(single_pole_coeffs[i]); 192 | } 193 | for(int i=0;i<=pole_order_max-2;i++){ 194 | mpfr_clear(factorial_times_power_lnb[i]); 195 | } 196 | if(pole_order_max > 0){ 197 | free(single_pole_coeffs); 198 | } 199 | if(pole_order_max > 1){ 200 | free(factorial_times_power_lnb); 201 | } 202 | mpfr_clear(temp1); 203 | mpfr_clear(double_pole_integral); 204 | mpfr_clear(temp2); 205 | mpfr_clear(minus_pole_position); 206 | //mpfr_clear(factorial); 207 | mpfr_clear(minus_log_base); 208 | mpfr_clear(log_base_power); 209 | return result; 210 | } 211 | -------------------------------------------------------------------------------- /integral_decomp.h: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | #include "stdio.h" 3 | #include "mpfr.h" 4 | 5 | mpfr_t* simple_pole_case_c(long pole_order_max, mpfr_t base, mpfr_t pole_position, mpfr_t incomplete_gamma_factor, mpfr_prec_t prec); 6 | mpfr_t* double_pole_case_c(long pole_order_max, mpfr_t base, mpfr_t pole_position, mpfr_t incomplete_gamma_factor, mpfr_prec_t prec); 7 | -------------------------------------------------------------------------------- /partial_fraction.c: -------------------------------------------------------------------------------- 1 | #include "partial_fraction.h" 2 | #define deb(num)\ 3 | printf("deb %f\n",num) 4 | 5 | mpfr_t* fast_partial_fraction_c(mpfr_t* pole_locations, int* double_or_single, int n_poles, mpfr_prec_t prec){ 6 | int expected_result_length=n_poles; 7 | for(int i=0;i0) 19 | * and 20 | * set_zero_spin_rec_coeffs 21 | * 22 | * */ 23 | 24 | void set_nonzero_spin_rec_coeffs(mpfr_t result[8][5], mpfr_t epsilon, mpfr_t ell, mpfr_t Delta, mpfr_t S, mpfr_t P, mpfr_prec_t prec, mp_rnd_t rnd); 25 | void set_zero_spin_rec_coeffs(mpfr_t result[6][4], mpfr_t epsilon, mpfr_t Delta, mpfr_t S, mpfr_t P, mpfr_prec_t prec, mp_rnd_t rnd); 26 | 27 | void set_nonzero_spin_rec_coeffs_deriv(mpfr_t result[8][5], mpfr_t epsilon, mpfr_t ell, mpfr_t Delta, mpfr_t S, mpfr_t P, mpfr_prec_t prec, mp_rnd_t rnd); 28 | void set_zero_spin_rec_coeffs_deriv(mpfr_t result[6][4], mpfr_t epsilon, mpfr_t Delta, mpfr_t S, mpfr_t P, mpfr_prec_t prec, mp_rnd_t rnd); 29 | 30 | void initialize_spin_nonzero_coeffs_folder(mpfr_t a[8][5], mpfr_prec_t prec); 31 | void initialize_spin_zero_coeffs_folder(mpfr_t a[6][4], mpfr_prec_t prec); 32 | 33 | void deallocate_spin_nonzero_coeffs_folder(mpfr_t a[8][5]); 34 | void deallocate_spin_zero_coeffs_folder(mpfr_t a[6][4]); 35 | 36 | void spin_nonzero_evaluate_at_n(mpfr_t a[8], mpfr_t rho[8][5], long n, mpfr_prec_t prec, mp_rnd_t rnd); 37 | void spin_zero_evaluate_at_n(mpfr_t a[6], mpfr_t rho[6][4], long n, mpfr_prec_t prec, mp_rnd_t rnd); 38 | #endif 39 | 40 | -------------------------------------------------------------------------------- /scalar/hor_recursion.c: -------------------------------------------------------------------------------- 1 | #include "hor_recursion.h" 2 | #include "stdio.h" 3 | #define deb(x)\ 4 | printf("debug at position %f\n",x) 5 | 6 | 7 | mpfr_t* recursionNonZeroVector(unsigned long nMax, mpfr_t epsilon, mpfr_t ell, mpfr_t Delta, mpfr_t S, mpfr_t P, mpfr_prec_t prec, mp_rnd_t rnd){ 8 | if(nMax<=7){ 9 | printf("error: too small order of expansion in \"recursionSpinZeroVector\" function."); 10 | return NULL; 11 | } 12 | unsigned long order; 13 | order = nMax+1; 14 | mpfr_t *result=malloc(sizeof(mpfr_t)*order); 15 | mpfr_t *result_deriv=malloc(sizeof(mpfr_t)*order); 16 | 17 | mpfr_init2(result[0],prec); 18 | mpfr_set_ui(result[0],1,rnd); 19 | mpfr_t smallNumber; 20 | mpfr_init2(smallNumber,prec); 21 | mpfr_set_si_2exp(smallNumber,1,-(prec*3)/8+15,rnd); 22 | mpfr_t temp; 23 | mpfr_t temp2; 24 | 25 | mpfr_init2(temp,prec); 26 | mpfr_init2(temp2,prec); 27 | 28 | mpfr_t recCoeffs[8][5]; 29 | mpfr_t recCoeffs_deriv[8][5]; 30 | 31 | int has_a_zero_been_zero=0; 32 | 33 | initialize_spin_nonzero_coeffs_folder(recCoeffs, prec); 34 | set_nonzero_spin_rec_coeffs(recCoeffs, epsilon,ell,Delta,S,P,prec,rnd); 35 | 36 | mpfr_t as[8]; 37 | 38 | for(int i=0;i<=7;i++){ 39 | mpfr_init2(as[i],prec); 40 | } 41 | for(unsigned long i=1;i<=7;i++){ 42 | mpfr_set_si(temp,0,rnd); 43 | spin_nonzero_evaluate_at_n(as, recCoeffs, i, prec, rnd); 44 | if(mpfr_cmp_ui(as[0],0)==0){ 45 | for(unsigned long k=0;k=0&&n>=0){ 387 | return (context.lambda+2-n)*n+m; 388 | } 389 | else{ 390 | return -1; 391 | } 392 | } 393 | 394 | 395 | void element_helper(cb_context context, mpfr_t* array,mpfr_t r,int m, int n){ 396 | long j=indexOfConformalBlock(context,m,n); 397 | if(j>=0){ 398 | mpfr_set(r,*(array+j),MPFR_RNDN); 399 | } 400 | else{ 401 | mpfr_set_zero(r,1); 402 | } 403 | } 404 | 405 | 406 | mpfr_t* casimirExpander(mpfr_t* realAxisResult, mpfr_t epsilon, mpfr_t ell, mpfr_t Delta, mpfr_t S, mpfr_t P, cb_context context){ 407 | mpfr_t* result; 408 | if(context.lambda%2){ 409 | result=malloc(sizeof(mpfr_t)*((context.lambda+5)*(context.lambda-1)/4 +2)); 410 | } 411 | else{ 412 | result=malloc(sizeof(mpfr_t)*((context.lambda+4)*(context.lambda)/4 +1)); 413 | } 414 | for(int i=0;i<=context.lambda;++i){ 415 | mpfr_init2(result[i],context.prec); 416 | mpfr_set(result[i],realAxisResult[i],MPFR_RNDN); 417 | } 418 | 419 | mpfr_t Casimir; 420 | mpfr_t temp1, temp2, temp3, r; 421 | mpfr_init2(temp1,context.prec); 422 | mpfr_init2(temp2,context.prec); 423 | mpfr_init2(temp3,context.prec); 424 | mpfr_init2(temp3,context.prec); 425 | mpfr_init2(r,context.prec); 426 | mpfr_init2(Casimir,context.prec); 427 | 428 | /*computing quadratic Casimir times 2 */ 429 | mpfr_mul_ui(temp3,epsilon,2,MPFR_RNDN); 430 | mpfr_sub(temp2,Delta,temp3,MPFR_RNDN); 431 | mpfr_sub_ui(temp2,temp2,2,MPFR_RNDN); 432 | mpfr_mul(temp2,temp2,Delta,MPFR_RNDN); 433 | 434 | mpfr_add(temp3,temp3,ell,MPFR_RNDN); 435 | mpfr_mul(temp3,temp3,ell,MPFR_RNDN); 436 | mpfr_add(Casimir,temp3,temp2,MPFR_RNDN); 437 | 438 | for(int i=1;i<=(context.lambda/2);i++){ 439 | for(int j=0;j<=context.lambda-2*i;++j){ 440 | mpfr_init2(result[indexOfConformalBlock(context,i,j)],context.prec); 441 | mpfr_set_zero(temp1,1); 442 | /* The first line in arXiv 1203.6064 (C.1) 443 | * note: n(there) = i (here), and m(there)=j (here) 444 | * (a/2)=x 445 | * (b/2)=sqrt(y) 446 | * d/da ^m d/db ^n (g) = h_{n,m} = (1/2)^(m+n)d/dx ^m d/ dy ^n g 447 | * and h_{m,n}=(1/2)^(i+j) * i!j!h_{i,j} 448 | * */ 449 | element_helper(context,result,r,i,j-2); 450 | mpfr_mul_ui(temp2,r,4,MPFR_RNDN); 451 | element_helper(context,result,r,i,j-3); 452 | mpfr_mul_ui(temp3,r,8,MPFR_RNDN); 453 | mpfr_add(temp2,temp2,temp3,MPFR_RNDN); 454 | 455 | element_helper(context,result,r,i,j-1); 456 | mpfr_mul_ui(temp3,r,2,MPFR_RNDN); 457 | mpfr_sub(temp2,temp2,temp3,MPFR_RNDN); 458 | 459 | mpfr_mul_ui(temp3,epsilon,2,MPFR_RNDN); 460 | mpfr_add_si(temp3,temp3,2*i-1,MPFR_RNDN); 461 | mpfr_mul_ui(temp3,temp3,2,MPFR_RNDN); 462 | mpfr_mul(temp2,temp2,temp3,MPFR_RNDN); 463 | mpfr_add(temp1,temp1,temp2,MPFR_RNDN); 464 | 465 | /* The second line */ 466 | element_helper(context,result,r,i-1,j+2); 467 | mpfr_mul_si(temp2,r,-(j+2)*(j+1),MPFR_RNDN); 468 | mpfr_div_ui(temp2,temp2,i,MPFR_RNDN); 469 | mpfr_add(temp1,temp1,temp2,MPFR_RNDN); 470 | 471 | mpfr_mul_ui(temp2,epsilon,2,MPFR_RNDN); 472 | mpfr_add_si(temp2,temp2, -j-4*i +6,MPFR_RNDN); 473 | 474 | 475 | mpfr_mul_ui(temp3,S,2,MPFR_RNDN); 476 | mpfr_add(temp2,temp2,temp3,MPFR_RNDN); 477 | /* 478 | * 479 | *add 2*alpha + 2*beta = 2*S to the above! 480 | * -done 481 | * */ 482 | element_helper(context,result,r,i-1,j+1); 483 | mpfr_mul(temp2,temp2,r,MPFR_RNDN); 484 | mpfr_mul_si(temp2,temp2,2*(j+1),MPFR_RNDN); 485 | mpfr_div_ui(temp2,temp2,i,MPFR_RNDN); 486 | mpfr_add(temp1,temp1,temp2,MPFR_RNDN); 487 | 488 | /* The third line */ 489 | mpfr_mul_si(temp2,epsilon,4*(j+i-1),MPFR_RNDN); 490 | mpfr_add_si(temp2,temp2,j*j+8*j*i-5*j+4*i*i-2*i-2,MPFR_RNDN); 491 | 492 | mpfr_mul_ui(temp3,P,2,MPFR_RNDN); 493 | mpfr_add(temp2,temp2,temp3,MPFR_RNDN); 494 | mpfr_mul_si(temp3,S,8*i+4*j-8,MPFR_RNDN); 495 | mpfr_add(temp2,temp2,temp3,MPFR_RNDN); 496 | 497 | /* 498 | * 499 | *add 4*alpha*beta + alpha*(8*i +4* j-8) + beta*(8*i+4*j - 8) to the above! 500 | * 2*P + S*(8*i+4*j - 8) 501 | * -done 502 | * 503 | * */ 504 | 505 | mpfr_mul_ui(temp3,Casimir,2,MPFR_RNDN); 506 | mpfr_add(temp2,temp2,temp3,MPFR_RNDN); 507 | element_helper(context,result,r,i-1,j); 508 | mpfr_mul(temp2,temp2,r,MPFR_RNDN); 509 | mpfr_mul_ui(temp2,temp2,4,MPFR_RNDN); 510 | mpfr_div_ui(temp2,temp2,i,MPFR_RNDN); 511 | mpfr_add(temp1,temp1,temp2,MPFR_RNDN); 512 | 513 | /* The fourth line */ 514 | mpfr_mul_si(temp2,epsilon,2*(j-2*i+1),MPFR_RNDN); 515 | mpfr_add_si(temp2,temp2,j*j+12*j*i-13*j+12*i*i-34*i+22,MPFR_RNDN); 516 | 517 | mpfr_mul_ui(temp3,P,2,MPFR_RNDN); 518 | mpfr_add(temp2,temp2,temp3,MPFR_RNDN); 519 | mpfr_mul_si(temp3,S,8*i+2*j-10,MPFR_RNDN); 520 | mpfr_add(temp2,temp2,temp3,MPFR_RNDN); 521 | 522 | /* 523 | * 524 | *add 4*alpha*beta + (alpha+beta)*(8*i+2*j-10) to the above!! 525 | * =2*P+S*(8*i+2*j -10) 526 | * 527 | * */ 528 | 529 | element_helper(context,result,r,i-1,j-1); 530 | mpfr_mul(temp2,temp2,r,MPFR_RNDN); 531 | mpfr_mul_ui(temp2,temp2,8,MPFR_RNDN); 532 | mpfr_div_ui(temp2,temp2,i,MPFR_RNDN); 533 | mpfr_add(temp1,temp1,temp2,MPFR_RNDN); 534 | 535 | /* The last line */ 536 | mpfr_mul_ui(temp2,epsilon,2,MPFR_RNDN); 537 | mpfr_add_si(temp2,temp2,-3*j-4*i+6,MPFR_RNDN); 538 | 539 | mpfr_mul_si(temp3, S, -2,MPFR_RNDN); 540 | mpfr_add(temp2,temp2,temp3,MPFR_RNDN); 541 | /* 542 | * 543 | * add -2*(alpha + beta ) to this.. 544 | * = -2*S 545 | * -done 546 | * */ 547 | element_helper(context,result,r,i-2,j+1); 548 | mpfr_mul(temp2,temp2,r,MPFR_RNDN); 549 | mpfr_mul_ui(temp2,temp2,8*(j+1),MPFR_RNDN); 550 | 551 | element_helper(context,result,r,i-2,j+2); 552 | mpfr_mul_ui(temp3,r,4*(j+1)*(j+2),MPFR_RNDN); 553 | mpfr_sub(temp2,temp3,temp2,MPFR_RNDN); 554 | mpfr_div_ui(temp2,temp2,i,MPFR_RNDN); 555 | mpfr_add(temp1,temp1,temp2,MPFR_RNDN); 556 | 557 | /* finally division by 2(D+2n-3) */ 558 | mpfr_mul_ui(temp2,epsilon,4,MPFR_RNDN); 559 | mpfr_add_si(temp2,temp2,4*i-2,MPFR_RNDN); 560 | mpfr_div(result[indexOfConformalBlock(context,i,j)],temp1,temp2,MPFR_RNDN); 561 | } 562 | } 563 | mpfr_clear(temp1); 564 | mpfr_clear(temp2); 565 | mpfr_clear(temp3); 566 | mpfr_clear(Casimir); 567 | return result; 568 | 569 | } 570 | 571 | 572 | mpfr_t* gBlock_full(mpfr_t epsilon, mpfr_t ell, mpfr_t Delta, mpfr_t S, mpfr_t P,cb_context context){ 573 | 574 | mpfr_t* realAxisResult=real_axis_result(epsilon,ell,Delta,S,P,context); 575 | mpfr_t* result=casimirExpander(realAxisResult,epsilon,ell,Delta,S,P,context); 576 | for(unsigned long j=0;j<=context.lambda;j++){ 577 | mpfr_clear(realAxisResult[j]); 578 | } 579 | free(realAxisResult); 580 | return result; 581 | } 582 | 583 | mpfr_t* hBlock_times_rho_n(unsigned long n, mpfr_t epsilon, mpfr_t ell, mpfr_t Delta, mpfr_t S, mpfr_t P, cb_context context){ 584 | /* * 585 | * gives (4*rho)^{n} * h(\Delta, l,...) = (4*rho)^{n-\Delta}g*(\Delta, l, ...) 586 | * , evaluated in x-y coordinate 587 | * */ 588 | mpfr_t* hBlock; 589 | if(mpfr_cmp_ui(ell,0)==0){ 590 | hBlock = recursionSpinZeroVector(context.n_Max,epsilon,Delta,S,P,context.prec, context.rnd); 591 | } 592 | else{ 593 | hBlock = recursionNonZeroVector(context.n_Max,epsilon,ell,Delta,S,P,context.prec, context.rnd); 594 | } 595 | mpfr_t* result_in_rho=malloc(sizeof(mpfr_t)*(context.lambda+1)); 596 | mpfr_t temp1; 597 | mpfr_t temp2; 598 | mpfr_t temp3; 599 | mpfr_init2(temp1,context.prec); 600 | mpfr_init2(temp2,context.prec); 601 | mpfr_init2(temp3,context.prec); 602 | 603 | mpfr_init2(result_in_rho[0],context.prec); 604 | mpfr_set_si(result_in_rho[0],0,context.rnd); 605 | mpfr_mul_ui(temp1,context.rho,4,context.rnd); 606 | mpfr_pow_ui(temp1,temp1,n, context.rnd); 607 | for(unsigned long j=0;j<=context.n_Max;j++){ 608 | mpfr_mul(hBlock[j],hBlock[j],temp1,context.rnd); 609 | mpfr_add(result_in_rho[0],result_in_rho[0],hBlock[j],context.rnd); 610 | if(j 5 | #include 6 | 7 | #ifndef CONFORMAL_BLOCK_KTYPE 8 | #define CONFORMAL_BLOCK_KTYPE 9 | void set_k_coeffs(mpfr_t a[4][3], mpfr_t h, mpfr_t S, mpfr_t P, mpfr_prec_t prec, mp_rnd_t rnd); 10 | //void initialize_k_coeffs(mpfr_t a[4][3], mpfr_prec_t prec); 11 | //void deallocate_k_coeffs(mpfr_t a[4][3], mpfr_prec_t prec); 12 | void k_evaluate_at_n(mpfr_t a[4], mpfr_t[4][3],long n, mpfr_prec_t prec, mp_rnd_t rnd); 13 | mpfr_t* recursion_k(unsigned long nMax, mpfr_t h, mpfr_t S, mpfr_t P, mpfr_prec_t prec, mp_rnd_t rnd); 14 | 15 | mpfr_t* k_table_c(mpfr_t h,mpfr_t S, mpfr_t P, cb_context context); 16 | mpfr_t* chiral_h_times_rho_to_n_c(unsigned long n, mpfr_t h,mpfr_t S, mpfr_t P, cb_context context); 17 | mpfr_t* chiral_h_asymptotic_c(mpfr_t S, cb_context context); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /scalar/scalar_context.pxd: -------------------------------------------------------------------------------- 1 | from sage.libs.mpfr cimport * 2 | from sage.rings.real_mpfr cimport * 3 | from sage.cboot.context_object cimport * 4 | 5 | cdef extern from "stdlib.h": 6 | void* malloc(size_t size) 7 | void free (void* ptr) 8 | 9 | #cdef extern from "sage/cb/hor_formula.h": 10 | # pass 11 | 12 | cdef extern from "hor_recursion.h": 13 | mpfr_t* h_asymptotic(mpfr_t epsilon, mpfr_t S,cb_context context) 14 | mpfr_t* real_axis_result(mpfr_t epsilon, mpfr_t ell, mpfr_t Delta, mpfr_t S, mpfr_t P, cb_context context) 15 | mpfr_t* gBlock_full(mpfr_t epsilon, mpfr_t ell, mpfr_t Delta, mpfr_t S, mpfr_t P, cb_context context) 16 | mpfr_t* hBlock_times_rho_n(unsigned long n, mpfr_t epsilon, mpfr_t ell, mpfr_t Delta, mpfr_t S, mpfr_t P, cb_context context) 17 | 18 | cdef extern from "k_compute.h": 19 | mpfr_t* k_table_c(mpfr_t h, mpfr_t S,mpfr_t P,cb_context context) 20 | mpfr_t* chiral_h_times_rho_to_n_c(unsigned long n, mpfr_t h,mpfr_t S, mpfr_t P, cb_context context) 21 | mpfr_t* chiral_h_asymptotic_c(mpfr_t S, cb_context context) 22 | 23 | 24 | -------------------------------------------------------------------------------- /scalar/scalar_context.pyx: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from sage.cboot.context_object cimport * 3 | from sage.cboot.context_object import SDP 4 | from sage.all import matrix, ZZ, Integer, cached_method 5 | include "sage/ext/interrupt.pxi" 6 | 7 | class k_poleData: 8 | """ 9 | poleData(type,k,a,b,context): 10 | A class containing the information about the poles and residues of 11 | chiral conformal blockm k_{\\beta,\\Delta_{1,2},\\Delta_{3,4}} w.r.t. \\beta. 12 | 13 | k, ell has the same meaning, epsilon (here) = \\nu (there) 14 | a = - \Delta_{12}/2 15 | b = + \Delta_{34}/2 16 | 17 | """ 18 | def __init__(self,k,a,b,context): 19 | self.k=k 20 | self.a=context.field(a) 21 | self.b=context.field(b) 22 | self.context=context 23 | def S(self): 24 | return (self.a+self.b) 25 | def P(self): 26 | return (2*self.a*self.b) 27 | def descendant_level(self): 28 | return self.k 29 | def polePosition(self): 30 | return self.context.field(1-self.k)/2 31 | def residueDelta(self): 32 | return self.context.field(1+self.k)/2 33 | def coeff(self): 34 | if self.k%2: 35 | local_sign=-1 36 | else: 37 | local_sign=1 38 | return (-local_sign*(self.k)/(2*self.context.pochhammer(1,self.k)**2))*self.context.pochhammer((1-self.k+2*self.a)/2,self.k)*self.context.pochhammer((1-self.k + 2*self.b)/2,self.k) 39 | def residue_of_h(self): 40 | return self.coeff()*self.context.chiral_h_times_rho_to_n(self.descendant_level(),self.residueDelta(),-2*self.a,2*self.b) 41 | 42 | class k_rational_approx_data: 43 | """ 44 | rational_aprrox_data(self,cutoff,epsilon,ell,Delta_1_2=0,Delta_3_4=0,is_correlator_multiple=True,scheme="no approx pole",cutoff_for_approximating_pole=0) 45 | computes and holds rational approximation of conformal block datum. 46 | """ 47 | def __init__(self,context,cutoff,Delta_1_2,Delta_3_4,is_correlator_multiple,approximate_poles): 48 | self.cutoff=cutoff 49 | self.a = -Delta_1_2/2 50 | self.b = Delta_3_4/2 51 | self.S = self.a+self.b 52 | self.P = 2*self.a*self.b 53 | self.context=context 54 | self.approx_poles=[] 55 | if is_correlator_multiple: 56 | self.poles=[k_poleData(x,self.a,self.b,context) for x in range(1,cutoff+1)] 57 | else: 58 | self.poles =[k_poleData(x,self.a,self.b,context) for x in range(2,cutoff+2,2)] 59 | if approximate_poles: 60 | unitarity_bound = context.field(0.5)**10 61 | dim_approx_base = len(self.poles) 62 | self.approx_column = lambda x: [1/(unitarity_bound-x.polePosition())**i for i in range(1,dim_approx_base//2 + 2)]+ [(x.polePosition())**i for i in range(0,(dim_approx_base+1)//2-1)] 63 | self.approx_matrix=matrix(map(self.approx_column,self.poles)) 64 | if is_correlator_multiple: 65 | self.approx_poles=[k_poleData(x,self.a,self.b,context) for x in range(cutoff+1,2*cutoff+1)] 66 | else: 67 | self.approx_poles =[k_poleData(x,self.a,self.b,context) for x in range(2*(cutoff//2)+2,2*cutoff+2,2)] 68 | 69 | def prefactor(self): 70 | __q=sorted([x.polePosition() for x in self.poles],reverse=True) 71 | __poles=[[__q[0],1]] 72 | __count=0 73 | for i in range(1,len(__q)): 74 | if __q[i]==__q[i-1]: 75 | __poles[__count][1]=__poles[__count][1]+1 76 | else: 77 | __poles.append([__q[i],1]) 78 | __count=__count+1 79 | return damped_rational(__poles,4*self.context.rho,self.context.field(1),self.context) 80 | 81 | def approx_chiral_h(self): 82 | res=self.context.chiral_h_asymptotic(self.S)*reduce(lambda y,w:y*w,[(self.context.Delta - x.polePosition()) for x in self.poles]) 83 | _polys= [reduce(lambda y,z:y*z,[(self.context.Delta - w.polePosition()) for w in self.poles if not w==x]) for x in self.poles] 84 | res+=reduce(lambda y,w:y+w, map(lambda x,y:x.residue_of_h()*y,self.poles,_polys)) 85 | if not self.approx_poles==[]: 86 | approx_matrix_inv=self.approx_matrix.transpose().inverse() 87 | approx_target=matrix(map(self.approx_column,self.approx_poles)).transpose() 88 | approx_polys=list((matrix(_polys)*approx_matrix_inv*approx_target)[0]) 89 | for x ,y in zip(self.approx_poles,approx_polys): 90 | res+=x.residue_of_h()*y 91 | return res 92 | def approx_k(self): 93 | return self.context.univariate_func_prod(self.context.rho_to_delta,self.approx_chiral_h()) 94 | 95 | class g_rational_approx_data_two_d: 96 | """ 97 | We use a different class for d=2, 98 | utilizing the exact formula by Dolan and Osborn. 99 | The usage is similar to . 100 | """ 101 | def __init__(self,context,cutoff,ell,Delta_1_2,Delta_3_4,is_correlator_multiple,approximate_poles=True): 102 | self.cutoff=cutoff 103 | self.ell=ell 104 | self.a = -Delta_1_2/2 105 | self.b = Delta_3_4/2 106 | self.S = self.a+self.b 107 | self.P = 2*self.a*self.b 108 | self.context=context 109 | self.chiral_approx_data=k_rational_approx_data(context,cutoff,Delta_1_2,Delta_3_4,is_correlator_multiple,approximate_poles) 110 | def prefactor(self): 111 | __chiral_poles = self.chiral_approx_data.prefactor().poles.keys() 112 | __q = [ 2*x+self.ell for x in __chiral_poles]+[ 2*x-self.ell for x in __chiral_poles] 113 | __q=sorted(__q,reverse=True) 114 | __poles=[[__q[0],1]] 115 | __count=0 116 | for i in range(1,len(__q)): 117 | if __q[i]==__q[i-1]: 118 | __poles[__count][1]=__poles[__count][1]+1 119 | else: 120 | __poles.append([__q[i],1]) 121 | __count=__count+1 122 | return damped_rational(__poles,4*self.context.rho,self.context.field(4)**(len(__chiral_poles)),self.context) 123 | 124 | def approx_g(self): 125 | __chiral_block = self.chiral_approx_data.approx_k() 126 | left_contribution=[x((self.context.Delta+self.ell)/2) for x in __chiral_block] 127 | right_contribution=[x((self.context.Delta-self.ell)/2) for x in __chiral_block] 128 | __zz_res=[] 129 | for i in range(0,self.context.Lambda+1): 130 | for j in range(i,self.context.Lambda-i+1): 131 | __zz_res.append((left_contribution[i]*right_contribution[j]+left_contribution[j]*right_contribution[i])/2) 132 | return self.context.zzbar_to_xy_marix.dot(np.array(__zz_res)) 133 | 134 | def approx(self): 135 | pref=self.prefactor() 136 | body=self.approx_g() 137 | return prefactor_numerator(pref,body,self.context) 138 | 139 | cdef class scalar_cb_context_generic(cb_universal_context): 140 | """ 141 | Context object for the bootstrap. 142 | Frequently used quantities are stored here. 143 | """ 144 | cdef public object epsilon 145 | def __init__(self,Lambda,Prec,nMax,epsilon): 146 | cb_universal_context.__init__(self,Lambda,Prec,nMax) 147 | self.epsilon=self.field(epsilon) 148 | def h_times_rho_k(self,unsigned long k, ell, Delta, S, P): 149 | ell_c=self.field(ell) 150 | Delta_c=self.field(Delta) 151 | S_c=self.field(S) 152 | P_c=self.field(P) 153 | cdef mpfr_t* array 154 | sig_on() 155 | array=hBlock_times_rho_n(k, (self.epsilon).value, (ell_c).value, (Delta_c).value, (S_c).value, (P_c).value, self.c_context) 156 | sig_off() 157 | res=np.ndarray(self.Lambda+1,dtype='O') 158 | for i in range(0,self.Lambda+1): 159 | res[i]=(self.field)._new() 160 | # res[i]=RealNumber.__new__(RealNumber) 161 | (res[i])._parent=self.field 162 | mpfr_init2((res[i]).value, self.precision) 163 | mpfr_set((res[i]).value, array[i], MPFR_RNDN) 164 | mpfr_clear(array[i]) 165 | #(res[i]).init=1 166 | free(array) 167 | return res 168 | 169 | cpdef h_asymptotic_form(self, S): 170 | S_c=self.field(S) 171 | cdef mpfr_t* _array 172 | _array=h_asymptotic((self.epsilon).value, (S_c).value, (self.c_context)) 173 | res=np.ndarray(self.Lambda+1,dtype='O') 174 | for i in range(0,self.Lambda+1): 175 | # res[i]=RealNumber.__new__(RealNumber) 176 | res[i]=(self.field)._new() 177 | 178 | (res[i])._parent=self.field 179 | mpfr_init2((res[i]).value,self.precision) 180 | mpfr_set((res[i]).value, _array[i], MPFR_RNDN) 181 | mpfr_clear(_array[i]) 182 | #(res[i]).init=1 183 | return np.array(res) 184 | 185 | def gBlock(self, ell, Delta,Delta_1_2, Delta_3_4): 186 | """ 187 | gBlock(epsilon, ell, Delta, Delta_1_2, Delta_3_4, self=self): 188 | computes conformal block in the notation of arXiv/1305.1321 189 | """ 190 | 191 | ell_c=self.field(ell) 192 | Delta_c=self.field(Delta) 193 | S_c=self.field(-Delta_1_2 + Delta_3_4)/2 194 | P_c=self.field(-Delta_1_2)*self.field(Delta_3_4)/2 195 | 196 | # In case Delta and ell = 0, return the identity_vector. 197 | if (mpfr_zero_p((ell_c).value))!=0 and mpfr_zero_p((Delta_c).value)!=0: 198 | if mpfr_zero_p((S_c).value)!=0 and mpfr_zero_p((P_c).value)!=0: 199 | return self.identity_vector() 200 | else: 201 | raise ValueError("Delta, ell =0 while Delta_1_2 = {0} and Delta_3_4 = {1}".format(Delta_1_2,Delta_3_4)) 202 | 203 | cdef mpfr_t* array 204 | sig_on() 205 | array=gBlock_full((self.epsilon).value, (ell_c).value, (Delta_c).value, (S_c).value, (P_c).value,self.c_context) 206 | sig_off() 207 | 208 | if(self.Lambda%2): 209 | dimGBlock=((self.Lambda+1)*(self.Lambda+3)/4) 210 | else: 211 | dimGBlock=((self.Lambda+2)**2)/4 212 | res=np.ndarray(dimGBlock,dtype='O') 213 | for i in range(0,dimGBlock): 214 | res[i]=(self.field)._new() 215 | (res[i])._parent=self.field 216 | mpfr_init2((res[i]).value, self.precision) 217 | mpfr_set((res[i]).value, array[i], MPFR_RNDN) 218 | mpfr_clear(array[i]) 219 | 220 | free(array) 221 | return res 222 | 223 | def c2_expand(self, array_real,ell,Delta,S,P): 224 | """ 225 | c2_expand(array_real,self.epsilon,ell,Delta,S,P) 226 | computes y-derivatives of scalar conformal blocks 227 | from x-derivatives of conformal block called array_real, 228 | which is a (self.Lambda + 1)-dimensional array. 229 | """ 230 | local_c2=(ell*(ell+2*self.epsilon)+Delta*(Delta-2-2*self.epsilon)) 231 | aligned_index = lambda y_del, x_del: (self.Lambda + 2 - y_del)*y_del+x_del 232 | if (self.Lambda%2): 233 | local_dim_answer=(self.Lambda+1)*(self.Lambda+3)//4 234 | else: 235 | local_dim_answer=(self.Lambda+2)*(self.Lambda+2)//4 236 | ans=np.ndarray(local_dim_answer,dtype='O') 237 | ans[0:(self.Lambda+1)]=array_real 238 | for i in range(1,(self.Lambda//2)+1): 239 | for j in range(0,self.Lambda - 2*i+1): 240 | ans[aligned_index(i,j)]=(0) 241 | if (j>=3): 242 | ans[aligned_index(i,j)]+=ans[aligned_index(i,j-3)]*16*(2*self.epsilon + 2*i - 1) 243 | ans[aligned_index(i,j)]+=ans[aligned_index(i,j-2)]*8*(2*self.epsilon + 2*i - 1) 244 | ans[aligned_index(i,j)]+=-ans[aligned_index(i,j-1)]*4*(2*self.epsilon + 2*i - 1) 245 | elif (j>=2): 246 | ans[aligned_index(i,j)]+=ans[aligned_index(i,j-2)]*8*(2*self.epsilon + 2*i - 1) 247 | ans[aligned_index(i,j)]+=-ans[aligned_index(i,j-1)]*4*(2*self.epsilon + 2*i - 1) 248 | elif (j>=1): 249 | ans[aligned_index(i,j)]+=-ans[aligned_index(i,j-1)]*4*(2*self.epsilon + 2*i - 1) 250 | ans[aligned_index(i,j)]+=(4*(2*P + 8*S*i + 4*S*j - 8*S + 2*local_c2 + 4*self.epsilon*i + 4*self.epsilon*j-4*self.epsilon + 4*i**2 + 8*i*j - 2*i + j**2 - 5*j - 2)/(i))*ans[aligned_index(i-1,j)] 251 | ans[aligned_index(i,j)]+=(-self.field((j + 1)*(j + 2))/i)*ans[aligned_index(i-1,j+2)] 252 | ans[aligned_index(i,j)]+=(2*(j + 1)*(2*S + 2*self.epsilon - 4*i - j + 6)/i)*ans[aligned_index(i-1,j+1)] 253 | if (j>=1): 254 | ans[aligned_index(i,j)]+=(8*(2*P + 8*S*i + 2*S*j - 10*S - 4*self.epsilon*i + 2*self.epsilon*j + 2*self.epsilon + 12*i**2 + 12*i*j - 34*i + j**2 - 13*j + 22)/self.field(i))*ans[aligned_index(i-1,j-1)] 255 | if (i>=2): 256 | ans[aligned_index(i,j)]+=(4*self.field((j + 1)*(j + 2))/i)*ans[aligned_index(i-2,j+2)] 257 | ans[aligned_index(i,j)]+=(8*(j + 1)*self.field(2*S - 2*self.epsilon + 4*i + 3*j - 6)/i)*ans[aligned_index(i-2,j+1)] 258 | 259 | ans[aligned_index(i,j)]=ans[aligned_index(i,j)]/(2*self.field(2*self.epsilon + 2*i - 1)) 260 | return ans 261 | 262 | def rational_approx_data(self,cutoff,ell,Delta_1_2=0,Delta_3_4=0,is_correlator_multiple=False,approximate_poles=True): 263 | return rational_approx_data_generic_dim(self,cutoff,ell,Delta_1_2,Delta_3_4,is_correlator_multiple,approximate_poles) 264 | 265 | def approx_cb(self,cutoff,ell,Delta_1_2=0,Delta_3_4=0,include_odd=False,approximate_poles=True): 266 | if not include_odd: 267 | if Delta_1_2 !=0 or Delta_3_4 !=0: 268 | include_odd=True 269 | g=self.rational_approx_data(cutoff,ell,Delta_1_2,Delta_3_4,is_correlator_multiple=include_odd,approximate_poles=approximate_poles).approx() 270 | return g 271 | 272 | class poleData: 273 | """ 274 | poleData(type,k ,ell,a,b: 275 | A class containing the information about the poles and residues of 276 | conformal block w.r.t. \Delta. 277 | 278 | type = 1 or 2 or 3 refers to the rows of the Section 4, Table 1 of 1406.4858. 279 | k, ell has the same meaning, epsilon (here) = \\nu (there) 280 | a = - \Delta_{12}/2 281 | b = + \Delta_{34}/2 282 | 283 | """ 284 | def __init__(self,type,k,ell,a,b,context): 285 | self.type=type 286 | self.ell=context.field(ell) 287 | if (k>ell) and type==3: 288 | raise NotImplementedError 289 | self.k=k 290 | self.epsilon=context.epsilon 291 | self.a=context.field(a) 292 | self.b=context.field(b) 293 | self.context=context 294 | def S(self): 295 | return (self.a+self.b) 296 | def P(self): 297 | return (2*self.a*self.b) 298 | def descendant_level(self): 299 | if self.type==1: 300 | return self.k 301 | elif self.type==2: 302 | return 2*self.k 303 | elif self.type==3: 304 | return self.k 305 | else: 306 | raise NotImplementedError 307 | 308 | def polePosition(self): 309 | if self.type==1: 310 | return self.context.field(1-self.ell-self.k) 311 | elif self.type==2: 312 | return self.context.field(1+self.epsilon-self.k) 313 | elif self.type==3: 314 | return self.context.field(1+self.ell+2*self.epsilon-self.k) 315 | else: 316 | raise NotImplementedError 317 | 318 | def residueDelta(self): 319 | if self.type==1: 320 | return 1-self.ell 321 | elif self.type==2: 322 | return 1+self.epsilon+self.k 323 | elif self.type==3: 324 | return 1+self.ell+2*self.epsilon 325 | else: 326 | raise NotImplementedError 327 | 328 | def residueEll(self): 329 | if self.type==1: 330 | return self.ell+self.k 331 | elif self.type==2: 332 | return self.ell 333 | elif self.type==3: 334 | return self.ell-self.k 335 | else: 336 | raise NotImplementedError 337 | def coeff(self): 338 | if self.k%2: 339 | local_sign=-1 340 | else: 341 | local_sign=1 342 | if self.type==1: 343 | return (-local_sign*(self.k)/(self.context.pochhammer(1,self.k)**2))*self.context.pochhammer(self.ell+2*self.epsilon,self.k)*self.context.pochhammer((1-self.k+2*self.a)/2,self.k)*self.context.pochhammer((1-self.k + 2*self.b)/2,self.k)/(self.context.pochhammer(self.ell+self.epsilon,self.k)) 344 | elif self.type==2: 345 | return (-local_sign*(self.k)/(self.context.pochhammer(1,self.k)**2))*self.context.pochhammer(self.epsilon-self.k,2*self.k)/( self.context.pochhammer(self.ell+self.epsilon - self.k,2*self.k)*self.context.pochhammer(self.ell+self.epsilon+1-self.k,2*self.k) )* self.context.pochhammer((1-self.k+self.ell-2*self.a+self.epsilon)/2,self.k)*self.context.pochhammer((1-self.k+self.ell+2*self.a+self.epsilon)/2,self.k)*self.context.pochhammer((1-self.k+self.ell-2*self.b+self.epsilon)/2,self.k)*self.context.pochhammer((1-self.k+self.ell+2*self.b+self.epsilon)/2,self.k) 346 | 347 | elif self.type==3: 348 | if self.k <= self.ell: 349 | return (-local_sign*(self.k)/(self.context.pochhammer(1,self.k)**2))*self.context.pochhammer(self.ell+1-self.k,self.k)*self.context.pochhammer((1-self.k+2*self.a)/2,self.k)*self.context.pochhammer((1-self.k + 2*self.b)/2,self.k)/(self.context.pochhammer(1+self.ell+self.epsilon-self.k,self.k)) 350 | else: 351 | raise RuntimeError("pole identifier k must be k <= ell for type 3 pole.") 352 | else: 353 | raise NotImplementedError("pole type unrecognizable.") 354 | 355 | def residue_of_h(self): 356 | return self.coeff()*self.context.h_times_rho_k(self.descendant_level(),self.residueEll(),self.residueDelta(),self.S(),self.P()) 357 | 358 | class rational_approx_data_generic_dim: 359 | """ 360 | rational_aprrox_data(self,cutoff,epsilon,ell,Delta_1_2=0,Delta_3_4=0,approximate_poles=True) 361 | computes and holds rational approximation of conformal block datum. 362 | """ 363 | def __init__(self,context,cutoff,ell,Delta_1_2,Delta_3_4,is_correlator_multiple,approximate_poles): 364 | self.epsilon=context.epsilon 365 | self.ell=ell 366 | self.cutoff=cutoff 367 | self.a=-Delta_1_2/2 368 | self.b=Delta_3_4/2 369 | self.S = self.a+self.b 370 | self.P = 2*self.a*self.b 371 | self.context=context 372 | self.approx_poles=[] 373 | if is_correlator_multiple: 374 | self.poles=[poleData(1,x,ell,self.a,self.b,context) for x in range(1,self.cutoff+1)]+[poleData(2,x,ell,self.a,self.b,context) for x in range(1,(cutoff//2)+1)]+[poleData(3,x,ell,self.a,self.b,context) for x in range(1,min(ell,cutoff//2)+1)] 375 | else: 376 | self.poles =[poleData(1,x,ell,self.a,self.b,context) for x in range(2,2*(cutoff//2)+2,2)]+[poleData(2,x,ell,self.a,self.b,context) for x in range(1,(cutoff//2)+1)]+[poleData(3,x,ell,self.a,self.b,context) for x in range(2,2*(min(ell,cutoff)//2)+2,2)] 377 | if approximate_poles: 378 | if ell==0: 379 | unitarity_bound = self.epsilon + context.field(0.5)**10 380 | else: 381 | unitarity_bound = ell+2*self.epsilon + context.field(0.5)**10 382 | dim_approx_base = len(self.poles) 383 | self.approx_column = lambda x: [1/(unitarity_bound-x.polePosition())**i for i in range(1,dim_approx_base//2 + 2)]+ [(x.polePosition())**i for i in range(0,(dim_approx_base+1)//2-1)] 384 | self.approx_matrix=matrix(map(self.approx_column,self.poles)) 385 | if is_correlator_multiple: 386 | self.approx_poles=[poleData(1,x,ell,self.a,self.b,context) for x in range(cutoff+1,2*cutoff+1)]+[poleData(2,x,ell,self.a,self.b,context) for x in range((cutoff//2)+1,2*(cutoff//2)+1)]+[poleData(3,x,ell,self.a,self.b,context) for x in range(min(ell,cutoff//2)+1,ell+1)] 387 | else: 388 | self.approx_poles =[poleData(1,x,ell,self.a,self.b,context) for x in range(2*(cutoff//2)+2,2*cutoff+2,2)]+[poleData(2,x,ell,self.a,self.b,context) for x in range((cutoff//2)+1,2*(cutoff//2)+1)]+[poleData(3,x,ell,self.a,self.b,context) for x in range(2*(min(ell,cutoff)//2)+2,2*(ell//2)+2,2)] 389 | 390 | def prefactor(self): 391 | __q=sorted([x.polePosition() for x in self.poles],reverse=True) 392 | __poles=[[__q[0],1]] 393 | __count=0 394 | for i in range(1,len(__q)): 395 | if __q[i]==__q[i-1]: 396 | __poles[__count][1]=__poles[__count][1]+1 397 | else: 398 | __poles.append([__q[i],1]) 399 | __count=__count+1 400 | return damped_rational(__poles,4*self.context.rho,self.context.field(1),self.context) 401 | 402 | def approx_h(self): 403 | res=self.context.h_asymptotic_form(self.S)*reduce(lambda y,w:y*w,[(self.context.Delta - x.polePosition()) for x in self.poles]) 404 | _polys= [reduce(lambda y,z:y*z,[(self.context.Delta - w.polePosition()) for w in self.poles if not w==x]) for x in self.poles] 405 | res+=reduce(lambda y,w:y+w, map(lambda x,y:x.residue_of_h()*y,self.poles,_polys)) 406 | if not self.approx_poles==[]: 407 | approx_matrix_inv=self.approx_matrix.transpose().inverse() 408 | approx_target=matrix(map(self.approx_column,self.approx_poles)).transpose() 409 | approx_polys=list((matrix(_polys)*approx_matrix_inv*approx_target)[0]) 410 | for x ,y in zip(self.approx_poles,approx_polys): 411 | res+=x.residue_of_h()*y 412 | return res 413 | 414 | def approx_g(self): 415 | return self.context.c2_expand(self.context.univariate_func_prod(self.context.rho_to_delta,self.approx_h()),self.ell,self.context.Delta,self.S,self.P) 416 | 417 | def approx(self): 418 | pref=self.prefactor() 419 | body=self.approx_g() 420 | return prefactor_numerator(pref,body,self.context) 421 | 422 | def context_for_scalar(epsilon=0.5, Lambda=15, Prec=800, nMax=250): 423 | try: 424 | temp=Integer(epsilon) 425 | if temp==0: 426 | return scalar_cb_2d_context(Lambda,Prec,nMax,) 427 | elif temp==1: 428 | return scalar_cb_4d_context(Lambda,Prec,nMax,) 429 | else: 430 | raise RuntimeError("Sorry, space-time dimensions d={0} is unsupported. Create it yourself and let me know!".format(2+2*epsilon)) 431 | except TypeError: 432 | return scalar_cb_context_generic(Lambda,Prec,nMax,epsilon,) 433 | 434 | def zzbar_anti_symm_to_xy_matrix(Lambda,field=RealField(400)): 435 | q=ZZ['x'] 436 | 437 | if (Lambda%2): 438 | dimG=(Lambda+1)*(Lambda+3)/4 439 | else: 440 | dimG=((Lambda+2)**2)/4 441 | tempres={} 442 | if (Lambda%2): 443 | dimG=(Lambda+1)*(Lambda+3)/4 444 | else: 445 | dimG=((Lambda+2)**2)/4 446 | result=np.ndarray(dimG**2,dtype='O') 447 | result[:]=field(0) 448 | result=result.reshape(dimG,dimG) 449 | for i in range(0,Lambda//2+2): 450 | for j in range(i+1,Lambda+2-i): 451 | temp=((q('x+1')**j)*(q('x-1')**i)-(q('x-1')**j)*(q('x+1')**i)).padded_list() 452 | tempres.update({repr(i)+","+repr(j):temp}) 453 | column_position=(Lambda+2-i)*i+(j-i-1) 454 | if ((i+j)%2): 455 | xypositions=([(Lambda+2-(i+j-x-1)/2)*(i+j-x-1)/2+x for x in range(0,len(temp),2)]) 456 | coeff_with_position=zip(xypositions,temp[0::2]) 457 | 458 | else: 459 | xypositions=([(Lambda+2-(i+j-x-1)/2)*(i+j-x-1)/2+x for x in range(1,len(temp),2)]) 460 | coeff_with_position=zip(xypositions,temp[1::2]) 461 | 462 | [result[column_position].__setitem__(int(x[0]),field(x[1]/2)) for x in coeff_with_position] 463 | 464 | return result.transpose() 465 | 466 | cdef class scalar_cb_2d_context(scalar_cb_context_generic): 467 | def __init__(self,int Lambda, mp_prec_t Prec, long nMax): 468 | scalar_cb_context_generic.__init__(self,Lambda, Prec, nMax,0) 469 | k_context=cb_universal_context(Lambda,Prec, nMax) 470 | def chiral_h_asymptotic(self,S): 471 | S_c=self.field(S) 472 | cdef mpfr_t* _array 473 | _array=chiral_h_asymptotic_c((S_c).value, (self.c_context)) 474 | res=np.ndarray(self.Lambda+1,dtype='O') 475 | for i in range(0,self.Lambda+1): 476 | res[i]=(self.field)._new() 477 | (res[i])._parent=self.field 478 | mpfr_init2((res[i]).value,self.precision) 479 | mpfr_set((res[i]).value, _array[i], MPFR_RNDN) 480 | mpfr_clear(_array[i]) 481 | #(res[i]).init=1 482 | return np.array(res) 483 | 484 | cpdef chiral_h_times_rho_to_n(self,long n,h,Delta_1_2=0,Delta_3_4=0): 485 | S_c=self.field(-Delta_1_2+Delta_3_4)/2 486 | P_c=self.field(-Delta_1_2*Delta_3_4)/2 487 | h_c=self.field(h) 488 | cdef mpfr_t* _array 489 | sig_on() 490 | _array=chiral_h_times_rho_to_n_c(n, (h_c).value, (S_c).value, (P_c).value, (self.c_context)) 491 | sig_off() 492 | res=np.ndarray(self.Lambda+1,dtype='O') 493 | for i in range(0,self.Lambda+1): 494 | res[i]=(self.field)._new() 495 | (res[i])._parent=self.field 496 | mpfr_init2((res[i]).value,self.precision) 497 | mpfr_set((res[i]).value, _array[i], MPFR_RNDN) 498 | mpfr_clear(_array[i]) 499 | return np.array(res) 500 | cpdef k_table(self,h,Delta_1_2,Delta_3_4): 501 | S_c=self.field(-Delta_1_2+Delta_3_4)/2 502 | P_c=self.field(-Delta_1_2*Delta_3_4)/2 503 | h_c=self.field(h) 504 | cdef mpfr_t* _array 505 | _array=k_table_c((h_c).value, (S_c).value, (P_c).value, (self.c_context)) 506 | res=np.ndarray(self.Lambda+1,dtype='O') 507 | for i in range(0,self.Lambda+1): 508 | res[i]=(self.field)._new() 509 | (res[i])._parent=self.field 510 | mpfr_init2((res[i]).value,self.precision) 511 | mpfr_set((res[i]).value, _array[i], MPFR_RNDN) 512 | mpfr_clear(_array[i]) 513 | return np.array(res) 514 | 515 | def k_rational_approx_data(self,cutoff,Delta_1_2=0,Delta_3_4=0,is_correlator_multiple=False,approximate_poles=True): 516 | return k_rational_approx_data(self,cutoff,Delta_1_2,Delta_3_4,is_correlator_multiple,approximate_poles) 517 | 518 | def rational_approx_data(self,cutoff,ell,Delta_1_2=0,Delta_3_4=0,is_correlator_multiple=True,approximate_poles=True): 519 | return g_rational_approx_data_two_d(self,cutoff,ell,Delta_1_2,Delta_3_4,is_correlator_multiple,approximate_poles) 520 | 521 | 522 | cdef class scalar_cb_4d_context(scalar_cb_context_generic): 523 | cdef public scalar_cb_2d_context k_context 524 | cdef public object zzbar_anti_symm_to_xy_matrix 525 | def __init__(self,int Lambda, mp_prec_t Prec, long nMax): 526 | scalar_cb_context_generic.__init__(self,Lambda, Prec, nMax,1) 527 | self.k_context=scalar_cb_2d_context(Lambda+1,Prec, nMax) 528 | self.epsilon=self.field(1) 529 | self.zzbar_anti_symm_to_xy_matrix=zzbar_anti_symm_to_xy_matrix(Lambda,field=self.field) 530 | 531 | def chiral_h_asymptotic(self,S): 532 | return self.k_context.chiral_h_asymptotic(S) 533 | def chiral_h_times_rho_to_n(self,long n,h,Delta_1_2=0,Delta_3_4=0): 534 | return self.k_context.chiral_h_times_rho_to_n(n,h,Delta_1_2=Delta_1_2,Delta_3_4=Delta_3_4) 535 | def k_table(self,h,Delta_1_2,Delta_3_4): 536 | return self.k_context.k_table(h,Delta_1_2,Delta_3_4) 537 | 538 | def k_rational_approx_data(self,cutoff,Delta_1_2=0,Delta_3_4=0,is_correlator_multiple=True,approximate_poles=True): 539 | return self.k_context.k_rational_approx_data(cutoff,Delta_1_2,Delta_3_4,is_correlator_multiple,approximate_poles=approximate_poles) 540 | 541 | def rational_approx_data(self,cutoff,ell,Delta_1_2=0,Delta_3_4=0,is_correlator_multiple=True,approximate_poles=True): 542 | return g_rational_approx_data_four_d(self,cutoff,ell,Delta_1_2,Delta_3_4,is_correlator_multiple,approximate_poles) 543 | 544 | class g_rational_approx_data_four_d: 545 | def __init__(self,context,cutoff,ell,Delta_1_2,Delta_3_4,is_correlator_multiple,approximate_poles=True): 546 | self.cutoff=cutoff 547 | self.ell=ell 548 | self.a = -Delta_1_2/2 549 | self.b = Delta_3_4/2 550 | self.S = self.a+self.b 551 | self.P = 2*self.a*self.b 552 | self.context=context 553 | self.chiral_approx_data=k_rational_approx_data(context.k_context,cutoff,Delta_1_2,Delta_3_4,is_correlator_multiple,approximate_poles) 554 | 555 | def prefactor(self): 556 | __chiral_poles = self.chiral_approx_data.prefactor().poles.keys() 557 | __q = [ 2*x-self.ell for x in __chiral_poles]+[ 2*x+self.ell+2 for x in __chiral_poles] 558 | __q=sorted(__q,reverse=True) 559 | __poles=[[__q[0],1]] 560 | __count=0 561 | for i in range(1,len(__q)): 562 | if __q[i]==__q[i-1]: 563 | __poles[__count][1]=__poles[__count][1]+1 564 | else: 565 | __poles.append([__q[i],1]) 566 | __count=__count+1 567 | return damped_rational(__poles,4*self.context.rho,1/(4*self.context.rho*self.context.field(self.ell+1))*self.context.field(4)**(len(__chiral_poles)),self.context) 568 | 569 | def approx_g(self): 570 | __chiral_block = self.chiral_approx_data.approx_k() 571 | __chiral_block_with_z=self.context.field(0.5)*__chiral_block+np.insert(__chiral_block[:-1],0,0) 572 | #z-multiply!!!! 573 | left_contribution=[x((self.context.Delta+self.ell)/2) for x in __chiral_block_with_z] 574 | right_contribution=[x((self.context.Delta-self.ell-2)/2) for x in __chiral_block_with_z] 575 | __zz_res=[] 576 | for i in range(0,self.context.Lambda//2+2): 577 | for j in range(i+1,self.context.Lambda-i+2): 578 | __zz_res.append((-left_contribution[i]*right_contribution[j]+left_contribution[j]*right_contribution[i])) 579 | return self.context.zzbar_anti_symm_to_xy_matrix.dot(np.array(__zz_res)) 580 | def approx(self): 581 | pref=self.prefactor() 582 | body=self.approx_g() 583 | return prefactor_numerator(pref,body,self.context) 584 | -------------------------------------------------------------------------------- /tutorial.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tohtsky/cboot/32cb55bbe6eff0fdc5e1375729d93abeecc2fe14/tutorial.pdf --------------------------------------------------------------------------------