Skip to content

Commit d4dbfdd

Browse files
merge
2 parents fd34018 + 8ae4c23 commit d4dbfdd

15 files changed

Lines changed: 1606 additions & 27 deletions

src/acb.pyx

Lines changed: 191 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,15 @@ cdef class acb(flint_scalar):
130130
if not arb_set_python(acb_imagref(self.val), imag, 1):
131131
raise TypeError("cannot create arb from type %s" % type(imag))
132132

133+
cpdef bint is_zero(self):
134+
return acb_is_zero(self.val)
135+
136+
cpdef bint is_finite(self):
137+
return acb_is_finite(self.val)
138+
139+
cpdef bint is_exact(self):
140+
return acb_is_exact(self.val)
141+
133142
@property
134143
def real(self):
135144
cdef arb re = arb()
@@ -175,10 +184,17 @@ cdef class acb(flint_scalar):
175184
other = any_as_acb(other)
176185
return bool(acb_contains(self.val, (<acb>other).val))
177186

187+
def contains_interior(self, other):
188+
other = any_as_acb(other)
189+
return bool(acb_contains_interior(self.val, (<acb>other).val))
190+
178191
def overlaps(self, other):
179192
other = any_as_acb(other)
180193
return bool(acb_overlaps((<acb>self).val, (<acb>other).val))
181194

195+
def contains_integer(self):
196+
return bool(acb_contains_int(self.val))
197+
182198
def mid(self):
183199
"""
184200
Returns an exact *acb* representing the midpoint of *self*:
@@ -254,6 +270,23 @@ cdef class acb(flint_scalar):
254270
acb_neg_round((<acb>res).val, (<acb>self).val, getprec())
255271
return res
256272

273+
def neg(self, bint exact=False):
274+
res = acb.__new__(acb)
275+
if exact:
276+
acb_set((<acb>res).val, (<acb>self).val)
277+
else:
278+
acb_set_round((<acb>res).val, (<acb>self).val, getprec())
279+
return res
280+
281+
def conjugate(self, bint exact=False):
282+
res = acb.__new__(acb)
283+
if exact:
284+
acb_conj((<acb>res).val, (<acb>self).val)
285+
else:
286+
acb_set_round((<acb>res).val, (<acb>self).val, getprec())
287+
acb_conj((<acb>res).val, (<acb>res).val)
288+
return res
289+
257290
def __abs__(self):
258291
res = arb.__new__(arb)
259292
acb_abs((<arb>res).val, (<acb>self).val, getprec())
@@ -377,8 +410,9 @@ cdef class acb(flint_scalar):
377410
if ttype == FMPZ_TMP: acb_clear(tval)
378411
return u
379412

413+
# important: must not be cdef because of cython magic
380414
@staticmethod
381-
cdef _div_(s, t):
415+
def _div_(s, t):
382416
cdef acb_struct sval[1]
383417
cdef acb_struct tval[1]
384418
cdef int stype, ttype
@@ -418,6 +452,12 @@ cdef class acb(flint_scalar):
418452
if ttype == FMPZ_TMP: acb_clear(tval)
419453
return u
420454

455+
def union(s, t):
456+
v = acb.__new__(acb)
457+
t = any_as_acb(t)
458+
acb_union((<acb>v).val, (<acb>s).val, (<acb>t).val, getprec())
459+
return v
460+
421461
def pow(s, t, bint analytic=False):
422462
"""
423463
Power `s^t`.
@@ -545,7 +585,10 @@ cdef class acb(flint_scalar):
545585
acb_agm1((<acb>u).val, (<acb>s).val, getprec())
546586
return u
547587
else:
548-
return (s / t).agm() * t
588+
t = acb(t)
589+
u = acb.__new__(acb)
590+
acb_agm((<acb>u).val, (<acb>s).val, (<acb>t).val, getprec())
591+
return u
549592

550593
def gamma(s):
551594
"""
@@ -620,6 +663,16 @@ cdef class acb(flint_scalar):
620663
acb_hurwitz_zeta((<acb>u).val, (<acb>s).val, (<acb>a).val, getprec())
621664
return u
622665

666+
def dirichlet_l(s, chi):
667+
cdef dirichlet_char cchar
668+
if isinstance(chi, dirichlet_char):
669+
cchar = chi
670+
else:
671+
cchar = dirichlet_char(chi[0], chi[1])
672+
u = acb.__new__(acb)
673+
acb_dirichlet_l((<acb>u).val, (<acb>s).val, cchar.G.val, cchar.val, getprec())
674+
return u
675+
623676
@staticmethod
624677
def pi():
625678
"""
@@ -994,7 +1047,7 @@ cdef class acb(flint_scalar):
9941047
acb_hypgeom_erf((<acb>u).val, (<acb>s).val, getprec())
9951048
return u
9961049

997-
def modular_theta(z, tau):
1050+
def modular_theta(z, tau, ulong r=0):
9981051
r"""
9991052
Computes the Jacobi theta functions `\theta_1(z,\tau)`,
10001053
`\theta_2(z,\tau)`, `\theta_3(z,\tau)`, `\theta_4(z,\tau)`,
@@ -1011,14 +1064,37 @@ cdef class acb(flint_scalar):
10111064
0.9694430387796704100046143 - 0.03055696120816803328582847j
10121065
1.030556961196006476576271 + 0.03055696120816803328582847j
10131066
"""
1067+
cdef acb_ptr T1, T2, T3, T4
1068+
assert r <= 1000000
10141069
tau = any_as_acb(tau)
10151070
t1 = acb.__new__(acb)
10161071
t2 = acb.__new__(acb)
10171072
t3 = acb.__new__(acb)
10181073
t4 = acb.__new__(acb)
1019-
acb_modular_theta((<acb>t1).val, (<acb>t2).val,
1020-
(<acb>t3).val, (<acb>t4).val,
1021-
(<acb>z).val, (<acb>tau).val, getprec())
1074+
if r == 0:
1075+
acb_modular_theta((<acb>t1).val, (<acb>t2).val,
1076+
(<acb>t3).val, (<acb>t4).val,
1077+
(<acb>z).val, (<acb>tau).val, getprec())
1078+
else:
1079+
T1 = _acb_vec_init(r + 1)
1080+
T2 = _acb_vec_init(r + 2)
1081+
T3 = _acb_vec_init(r + 3)
1082+
T4 = _acb_vec_init(r + 4)
1083+
acb_modular_theta_jet(T1, T2, T3, T4,
1084+
(<acb>z).val, (<acb>tau).val, r + 1, getprec())
1085+
acb_set((<acb>t1).val, T1 + r)
1086+
acb_set((<acb>t2).val, T2 + r)
1087+
acb_set((<acb>t3).val, T3 + r)
1088+
acb_set((<acb>t4).val, T4 + r)
1089+
c = arb.fac_ui(r)
1090+
t1 *= c
1091+
t2 *= c
1092+
t3 *= c
1093+
t4 *= c
1094+
_acb_vec_clear(T1, r + 1)
1095+
_acb_vec_clear(T2, r + 1)
1096+
_acb_vec_clear(T3, r + 1)
1097+
_acb_vec_clear(T4, r + 1)
10221098
return (t1, t2, t3, t4)
10231099

10241100
def modular_eta(tau):
@@ -2267,6 +2343,63 @@ cdef class acb(flint_scalar):
22672343
acb_root_ui((<acb>v).val, (<acb>s).val, n, getprec())
22682344
return v
22692345

2346+
@staticmethod
2347+
def zeta_zero(n):
2348+
"""
2349+
Returns the *n*-th nontrivial zero of the Riemann zeta function.
2350+
2351+
>>> showgood(lambda: acb.zeta_zero(1), dps=25)
2352+
0.5000000000000000000000000 + 14.13472514173469379045725j
2353+
>>> showgood(lambda: acb.zeta_zero(2), dps=25)
2354+
0.5000000000000000000000000 + 21.02203963877155499262848j
2355+
>>> showgood(lambda: acb.zeta_zero(100), dps=25)
2356+
0.5000000000000000000000000 + 236.5242296658162058024755j
2357+
>>> showgood(lambda: acb.zeta_zero(10**6), dps=25)
2358+
0.5000000000000000000000000 + 600269.6770124449555212339j
2359+
"""
2360+
n = fmpz(n)
2361+
if n < 1:
2362+
raise ValueError("require n >= 1")
2363+
v = acb.__new__(acb)
2364+
acb_dirichlet_zeta_zero((<acb>v).val, (<fmpz>n).val, getprec())
2365+
return v
2366+
2367+
@staticmethod
2368+
def zeta_zeros(n, long num):
2369+
"""
2370+
Returns *num* consecutive nontrivial zeros of the Riemann zeta function
2371+
starting at index *n*.
2372+
2373+
>>> for r in acb.zeta_zeros(1000, 10):
2374+
... print(r.str(10, radius=False))
2375+
...
2376+
0.5000000000 + 1419.422481j
2377+
0.5000000000 + 1420.416526j
2378+
0.5000000000 + 1421.850567j
2379+
0.5000000000 + 1422.461311j
2380+
0.5000000000 + 1424.463046j
2381+
0.5000000000 + 1425.873469j
2382+
0.5000000000 + 1426.645980j
2383+
0.5000000000 + 1427.365671j
2384+
0.5000000000 + 1428.592306j
2385+
0.5000000000 + 1429.650477j
2386+
"""
2387+
cdef long i
2388+
cdef acb_ptr w
2389+
cdef list v
2390+
n = fmpz(n)
2391+
if n < 1 or num < 0:
2392+
raise ValueError("require n >= 1 and num >= 0")
2393+
v = [acb() for i in range(num)]
2394+
w = <acb_ptr>libc.stdlib.malloc(num * cython.sizeof(acb_struct))
2395+
for i in range(num):
2396+
w[i] = (<acb>(v[i])).val[0]
2397+
acb_dirichlet_zeta_zeros(w, (<fmpz>n).val, num, getprec())
2398+
for i in range(num):
2399+
(<acb>(v[i])).val[0] = w[i]
2400+
libc.stdlib.free(w)
2401+
return v
2402+
22702403
@staticmethod
22712404
def integral(func, a, b, params=None,
22722405
rel_tol=None, abs_tol=None,
@@ -2376,3 +2509,55 @@ cdef class acb(flint_scalar):
23762509
raise ictx.exn_type, ictx.exn_obj, ictx.exn_tb
23772510

23782511
return res
2512+
2513+
def coulomb(self, l, eta):
2514+
r"""
2515+
Computes the Coulomb wave functions `F_{\ell}(\eta,z)`,
2516+
`G_{\ell}(\eta,z)`, `H^{+}_{\ell}(\eta,z)`, `H^{-}_{\ell}(\eta,z)`
2517+
where *z* is given by *self*.
2518+
All function values are computed simultaneously and a tuple
2519+
is returned.
2520+
2521+
>>> showgood(lambda: acb(1).coulomb(0.5, 0.25), dps=10)
2522+
(0.4283180781, 1.218454487, 1.218454487 + 0.4283180781j, 1.218454487 - 0.4283180781j)
2523+
"""
2524+
l = any_as_acb(l)
2525+
eta = any_as_acb(eta)
2526+
F = acb.__new__(acb)
2527+
G = acb.__new__(acb)
2528+
Hpos = acb.__new__(acb)
2529+
Hneg = acb.__new__(acb)
2530+
acb_hypgeom_coulomb((<acb>F).val, (<acb>G).val, (<acb>Hpos).val, (<acb>Hneg).val,
2531+
(<acb>l).val, (<acb>eta).val, (<acb>self).val, getprec())
2532+
return F, G, Hpos, Hneg
2533+
2534+
def coulomb_f(self, l, eta):
2535+
r"""
2536+
Regular Coulomb wave function `F_{\ell}(\eta,z)` where
2537+
*z* is given by *self*.
2538+
2539+
>>> showgood(lambda: acb(1+1j).coulomb_f(0.5, 0.25), dps=25)
2540+
0.3710338871231483199425544 + 0.7267604204004146050054782j
2541+
"""
2542+
l = any_as_acb(l)
2543+
eta = any_as_acb(eta)
2544+
F = acb.__new__(acb)
2545+
acb_hypgeom_coulomb((<acb>F).val, NULL, NULL, NULL,
2546+
(<acb>l).val, (<acb>eta).val, (<acb>self).val, getprec())
2547+
return F
2548+
2549+
def coulomb_g(self, l, eta):
2550+
r"""
2551+
Irregular Coulomb wave function `G_{\ell}(\eta,z)` where
2552+
*z* is given by *self*.
2553+
2554+
>>> showgood(lambda: acb(1+1j).coulomb_g(0.5, 0.25), dps=25)
2555+
1.293346292234270672155324 - 0.3516893313311703662702556j
2556+
"""
2557+
l = any_as_acb(l)
2558+
eta = any_as_acb(eta)
2559+
G = acb.__new__(acb)
2560+
acb_hypgeom_coulomb(NULL, (<acb>G).val, NULL, NULL,
2561+
(<acb>l).val, (<acb>eta).val, (<acb>self).val, getprec())
2562+
return G
2563+

src/acb_series.pyx

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,20 @@ cdef class acb_series(flint_series):
447447
(<acb_series>u).prec = cap
448448
return u
449449

450+
def dirichlet_l(s, chi, bint deflate=0):
451+
cdef long cap
452+
cdef dirichlet_char cchar
453+
if isinstance(chi, dirichlet_char):
454+
cchar = chi
455+
else:
456+
cchar = dirichlet_char(chi[0], chi[1])
457+
cap = getcap()
458+
cap = min(cap, (<acb_series>s).prec)
459+
u = acb_series.__new__(acb_series)
460+
acb_dirichlet_l_series((<acb_series>u).val, (<acb_series>s).val, cchar.G.val, cchar.val, deflate, cap, getprec())
461+
(<acb_series>u).prec = cap
462+
return u
463+
450464
@classmethod
451465
def polylog(cls, s, z):
452466
cdef long cap
@@ -640,6 +654,64 @@ cdef class acb_series(flint_series):
640654
(<acb_series>z).prec = cap
641655
return u, v, w, z
642656

657+
def modular_theta(self, tau):
658+
cdef long cap
659+
tau = acb(tau)
660+
cap = getcap()
661+
cap = min(cap, (<acb_series>self).prec)
662+
t1 = acb_series.__new__(acb_series)
663+
t2 = acb_series.__new__(acb_series)
664+
t3 = acb_series.__new__(acb_series)
665+
t4 = acb_series.__new__(acb_series)
666+
acb_modular_theta_series((<acb_series>t1).val, (<acb_series>t2).val, (<acb_series>t3).val, (<acb_series>t4).val, (<acb_series>self).val, (<acb>tau).val, cap, getprec())
667+
(<acb_series>t1).prec = cap
668+
(<acb_series>t2).prec = cap
669+
(<acb_series>t3).prec = cap
670+
(<acb_series>t4).prec = cap
671+
return t1, t2, t3, t4
672+
673+
def coulomb(self, l, eta):
674+
cdef long cap
675+
l = acb(l)
676+
eta = acb(eta)
677+
cap = getcap()
678+
cap = min(cap, (<acb_series>self).prec)
679+
F = acb_series.__new__(acb_series)
680+
G = acb_series.__new__(acb_series)
681+
Hpos = acb_series.__new__(acb_series)
682+
Hneg = acb_series.__new__(acb_series)
683+
acb_hypgeom_coulomb_series((<acb_series>F).val, (<acb_series>G).val, (<acb_series>Hpos).val, (<acb_series>Hneg).val,
684+
(<acb>l).val, (<acb>eta).val, (<acb_series>self).val, cap, getprec())
685+
(<acb_series>F).prec = cap
686+
(<acb_series>G).prec = cap
687+
(<acb_series>Hpos).prec = cap
688+
(<acb_series>Hneg).prec = cap
689+
return F, G, Hpos, Hneg
690+
691+
def coulomb_f(self, l, eta):
692+
cdef long cap
693+
l = acb(l)
694+
eta = acb(eta)
695+
cap = getcap()
696+
cap = min(cap, (<acb_series>self).prec)
697+
F = acb_series.__new__(acb_series)
698+
acb_hypgeom_coulomb_series((<acb_series>F).val, NULL, NULL, NULL,
699+
(<acb>l).val, (<acb>eta).val, (<acb_series>self).val, cap, getprec())
700+
(<acb_series>F).prec = cap
701+
return F
702+
703+
def coulomb_g(self, l, eta):
704+
cdef long cap
705+
l = acb(l)
706+
eta = acb(eta)
707+
cap = getcap()
708+
cap = min(cap, (<acb_series>self).prec)
709+
G = acb_series.__new__(acb_series)
710+
acb_hypgeom_coulomb_series(NULL, (<acb_series>G).val, NULL, NULL,
711+
(<acb>l).val, (<acb>eta).val, (<acb_series>self).val, cap, getprec())
712+
(<acb_series>G).prec = cap
713+
return G
714+
643715
def fresnel(s, bint normalized=True):
644716
cdef long cap
645717
cap = getcap()

0 commit comments

Comments
 (0)