## Introduction

Arbitrary precision complex ball arithmetic is supplied by Arb which provides a ball representation which tracks error bounds rigorously. Complex numbers are represented in in rectangular form $a+bi$ where $a,b$ are arb balls.

The Arb complex field is constructed using the AcbField constructor. This constructs the parent object for the Arb complex field.

We define

ComplexField = AcbField


so that one can construct the Arb complex field parent using ComplexField instead of AcbField.

The types of complex boxes in Nemo are given in the following table, along with the libraries that provide them and the associated types of the parent objects.

Library Field Element type Parent type
Arb $\mathbb{C}$ (boxes) acb AcbField

All the complex field types belong to the Field abstract type and the types of elements in this field, i.e. complex boxes in this case, belong to the FieldElem abstract type.

## Complex field constructors

In order to construct complex boxes in Nemo, one must first construct the Arb complex field itself. This is accomplished with the following constructor.

AcbField(prec::Int)


Return the Arb complex field with precision in bits prec used for operations on interval midpoints. The precision used for interval radii is a fixed implementation-defined constant (30 bits).

We define

ComplexField = AcbField


so that one can use ComplexField instead of AcbField.

Here is an example of creating an Arb complex field and using the resulting parent object to coerce values into the resulting field.

CC = ComplexField(64)

a = CC("0.25")
b = CC("0.1")
c = CC(0.5)
d = CC(12)


Note that whilst one can coerce double precision floating point values into an Arb complex field, unless those values can be represented exactly in double precision, the resulting ball can't be any more precise than the double precision supplied.

If instead, values can be represented precisely using decimal arithmetic then one can supply them to Arb using a string. In this case, Arb will store them to the precision specified when creating the Arb complex field.

If the values can be stored precisely as a binary floating point number, Arb will store the values exactly. See the function isexact below for more information.

## Complex ball constructors

Once an Arb complex field is constructed, there are various ways to construct boxes in that field.

Apart from coercing elements into the Arb complex field as above, we offer the following functions.

# Base.zeroMethod.

zero(R::AcbField)


Return exact zero in the given Arb complex field.

# Base.oneMethod.

one(R::AcbField)


Return exact one in the given Arb complex field.

# Nemo.oneiMethod.

onei(R::AcbField)


Return exact one times $i$ in the given Arb complex field.

Here are some examples of constructing complex boxes.

CC = ComplexField(64)

a = zero(CC)
b = one(CC)
c = onei(CC)


## Basic functionality

The following basic functionality is provided by the default Arb complex field implementation in Nemo, to support construction of generic rings over complex fields. Any custom complex field implementation in Nemo should provide analogues of these functions along with the usual arithmetic operations.

parent_type(::Type{acb})


Gives the type of the parent object of an Arb complex field element.

elem_type(R::AcbField)


Given the parent object for an Arb complex field, return the type of elements of the field.

mul!(c::acb, a::acb, b::acb)


Multiply $a$ by $b$ and set the existing Arb complex field element $c$ to the result. This function is provided for performance reasons as it saves allocating a new object for the result and eliminates associated garbage collection.

addeq!(c::acb, a::acb)


In-place addition. Adds $a$ to $c$ and sets $c$ to the result. This function is provided for performance reasons as it saves allocating a new object for the result and eliminates associated garbage collection.

deepcopy(a::acb)


Return a copy of the Arb complex field element $a$, recursively copying the internal data. Arb complex field elements are mutable in Nemo so a shallow copy is not sufficient.

Given the parent object R for an Arb complex field, the following coercion functions are provided to coerce various elements into the Arb complex field. Developers provide these by overloading the call operator for the complex field parent objects.

R()


Coerce zero into the Arb complex field.

R(n::Integer)
R(f::fmpz)
R(q::fmpq)


Coerce an integer or rational value into the Arb complex field.

R(f::Float64)
R(f::BigFloat)


Coerce the given floating point number into the Arb complex field.

R(f::AbstractString)
R(f::AbstractString, g::AbstractString)


Coerce the decimal number, given as a string, into the Arb complex field. In each case $f$ is the real part and $g$ is the imaginary part.

R(f::arb)


Coerce the given Arb real ball into the Arb complex field.

R(f::acb)


Take an Arb complex field element that is already in an Arb field and simply return it. A copy of the original is not made.

Here are some examples of coercing elements into the Arb complex field.

RR = RealField(64)
CC = ComplexField(64)

a = CC(3)
b = CC(QQ(2,3))
c = CC("3 +/- 0.0001")
d = CC("-1.24e+12345")
f = CC("nan +/- inf")
g = CC(RR(3))


In addition to the above, developers of custom complex field types must ensure that they provide the equivalent of the function base_ring(R::AcbField) which should return Union{}. In addition to this they should ensure that each complex field element contains a field parent specifying the parent object of the complex field element, or at least supply the equivalent of the function parent(a::acb) to return the parent object of a complex field element.

## Basic manipulation

Numerous functions are provided to manipulate Arb complex field elements. Also see the section on basic functionality above.

# Nemo.base_ringMethod.

base_ring(R::AcbField)


Returns Union{} since an Arb complex field does not depend on any other ring.

# Nemo.base_ringMethod.

base_ring(a::acb)


Returns Union{} since an Arb complex field does not depend on any other ring.

# Base.parentMethod.

parent(x::acb)


Return the parent of the given Arb complex field element.

# Nemo.iszeroMethod.

iszero(x::acb)


Return true if $x$ is certainly zero, otherwise return false.

# Nemo.isoneMethod.

isone(x::acb)


Return true if $x$ is certainly zero, otherwise return false.

# Base.isfiniteMethod.

isfinite(x::acb)


Return true if $x$ is finite, i.e. its real and imaginary parts have finite midpoint and radius, otherwise return false.

# Nemo.isexactMethod.

isexact(x::acb)


Return true if $x$ is exact, i.e. has its real and imaginary parts have zero radius, otherwise return false.

# Nemo.isintMethod.

isint(x::acb)


Return true if $x$ is an exact integer, otherwise return false.

# Base.isrealMethod.

isint(x::acb)


Return true if $x$ is purely real, i.e. having zero imaginary part, otherwise return false.

# Base.realMethod.

real(x::acb)


Return the real part of $x$ as an arb.

# Base.imagMethod.

imag(x::acb)


Return the imaginary part of $x$ as an arb.

# Nemo.accuracy_bitsMethod.

accuracy_bits(x::acb)


Return the relative accuracy of $x$ measured in bits, capped between typemax(Int) and -typemax(Int).

Here are some examples of basic manipulation of Arb complex boxes.

CC = ComplexField(64)

a = CC("1.2 +/- 0.001")
b = CC(3)

iszero(a)
isone(b)
isreal(a)
isfinite(b)
isint(b)
c = real(a)
d = imag(b)
f = accuracy_bits(a)
S = parent(a)
T = base_ring(CC)


## Arithmetic operations

Nemo provides all the standard field operations for Arb complex field elements, as follows. Note that division is represented by // since a field is its own fraction field and since exact division is not generally possible in an inexact field.

Function Operation
-(a::acb) unary minus
-(a::acb, b::acb) subtraction
*(a::acb, b::acb) multiplication
//(a::acb, b::acb) division
^(a::acb, b::acb) powering

Function Operation
-(a::acb, b::Integer) subtraction
-(a::Integer, b::acb) subtraction
-(a::acb, b::fmpz) subtraction
-(a::fmpz, b::acb) subtraction
-(a::acb, b::fmpq) subtraction
-(a::fmpq, b::acb) subtraction
-(a::acb, b::arb) subtraction
-(a::arb, b::acb) subtraction
*(a::acb, b::Integer) multiplication
*(a::Integer, b::acb) multiplication
*(a::acb, b::fmpz) multiplication
*(a::fmpz, b::acb) multiplication
*(a::acb, b::fmpq) multiplication
*(a::fmpq, b::acb) multiplication
*(a::acb, b::arb) multiplication
*(a::arb, b::acb) multiplication
//(a::acb, b::Integer) division
//(a::acb, b::fmpz) division
//(a::acb, b::fmpq) division
//(a::Integer, b::acb) division
//(a::fmpz, b::acb) division
//(a::fmpq, b::acb) division
//(a::arb, b::acb) division
^(a::acb, b::fmpq) powering
^(a::Integer, b::acb) powering
^(a::fmpz, b::acb) powering
^(a::fmpq, b::acb) powering
^(a::arb, b::acb) powering

Here are some examples of arithmetic operations on Arb complex boxes.

CC = ComplexField(64)

x = CC(3)
y = CC(QQ(2,3))

a = x + y
b = x*y
d = 1//y - x
d = 3x + ZZ(100)//y
f = (x^2 + y^2) ^ QQ(1,2)


## Containment

It is often necessary to determine whether a given exact value or box is contained in a given complex box or whether two boxes overlap. The following functions are provided for this purpose.

# Nemo.overlapsMethod.

overlaps(x::acb, y::acb)


Returns true if any part of the box $x$ overlaps any part of the box $y$, otherwise return false.

# Base.containsMethod.

contains(x::acb, y::acb)


Returns true if the box $x$ contains the box $y$, otherwise return false.

# Base.containsMethod.

contains(x::acb, y::Integer)


Returns true if the box $x$ contains the given integer value, otherwise return false.

# Base.containsMethod.

contains(x::acb, y::fmpz)


Returns true if the box $x$ contains the given integer value, otherwise return false.

# Base.containsMethod.

contains(x::acb, y::fmpq)


Returns true if the box $x$ contains the given rational value, otherwise return false.

The following functions are also provided for determining if a box intersects a certain part of the complex number plane.

# Nemo.contains_zeroMethod.

contains_zero(x::acb)


Returns true if the box $x$ contains zero, otherwise return false.

Here are some examples of testing containment.

CC = ComplexField(64)
x = CC("1 +/- 0.001")
y = CC("3")

overlaps(x, y)
contains(x, y)
contains(y, 3)
contains(x, ZZ(1)//2)
contains_zero(x)


## Comparison

Nemo provides a full range of comparison operations for Arb complex boxes.

Firstly, we introduce an exact equality which is distinct from arithmetic equality. This is distinct from arithmetic equality implemented by ==, which merely compares up to the minimum of the precisions of its operands.

# Base.isequalMethod.

isequal(x::acb, y::acb)


Return true if the boxes $x$ and $y$ are precisely equal, i.e. their real and imaginary parts have the same midpoints and radii.

A full range of functions is available for comparing boxes, i.e. == and !=. In fact, these are implemented directly in C. In the table below we document these as though only == had been provided to Julia.

## Function

==(x::acb, y::acb)

As well as these, we provide a full range of ad hoc comparison operators. Again, these are implemented directly in Julia, but we document them as though only == were provided.

## Function

==(x::acb, y::Integer) ==(x::Integer, y::acb) ==(x::acb, y::fmpz) ==(x::fmpz, y::acb) ==(x::arb, y::fmpz) ==(x::fmpz, y::arb) ==(x::acb, y::Float64) ==(x::Float64, y::acb)

Here are some examples of comparison.

CC = ComplexField(64)
x = CC("1 +/- 0.001")
y = CC("3")
z = CC("4")

isequal(y, z)
x != z
x == 3
ZZ(3) == z
x != 1.23


## Absolute value

# Base.absMethod.

abs(x::acb)


Return the complex absolute value of $x$.

Here are some examples of taking the absolute value.

CC = ComplexField(64)
x = CC("-1 +/- 0.001")

a = abs(x)


## Inverse

# Base.invMethod.

inv(x::acb)


Return the multiplicative inverse of $x$, i.e. $1/x$.

Here are some examples of taking the inverse.

CC = ComplexField(64)
x = CC("-3 +/- 0.001")

a = inv(x)


## Shifting

# Base.Math.ldexpMethod.

ldexp(x::acb, y::Int)


Return $2^yx$. Note that $y$ can be positive, zero or negative.

# Base.Math.ldexpMethod.

ldexp(x::acb, y::fmpz)


Return $2^yx$. Note that $y$ can be positive, zero or negative.

Here are some examples of shifting.

CC = ComplexField(64)
x = CC("-3 +/- 0.001")

a = ldexp(x, 23)
b = ldexp(x, -ZZ(15))


## Miscellaneous operations

# Nemo.trimMethod.

trim(x::acb)


Return an acb box containing $x$ but which may be more economical, by rounding off insignificant bits from midpoints.

# Nemo.unique_integerMethod.

unique_integer(x::acb)


Return a pair where the first value is a boolean and the second is an fmpz integer. The boolean indicates whether the box $x$ contains a unique integer. If this is the case, the second return value is set to this unique integer.

# Base.conjMethod.

conj(x::acb)


Return the complex conjugate of $x$.

# Base.angleMethod.

angle(x::acb)


Return the angle in radians that the complex vector $x$ makes with the positive real axis in a counterclockwise direction.

Here are some examples of miscellaneous operations.

CC = ComplexField(64)
x = CC("-3 +/- 0.001", "0.1")

a = trim(x)
b, c = unique_integer(x)
d = conj(x)
f = angle(x)


## Constants

const_pi(::AcbField)


Here are some examples of computing complex constants.

CC = ComplexField(200)

a = const_pi(CC)


## Mathematical functions

# Base.sqrtMethod.

sqrt(x::acb)


Return the square root of $x$.

# Nemo.rsqrtMethod.

rsqrt(x::acb)


Return the reciprocal of the square root of $x$, i.e. $1/\sqrt{x}$.

# Base.logMethod.

log(x::acb)


Return the principal branch of the logarithm of $x$.

# Base.log1pMethod.

log1p(x::acb)


Return $\log(1+x)$, evaluated accurately for small $x$.

# Base.expMethod.

exp(x::acb)


Return the exponential of $x$.

# Nemo.exppiiMethod.

exppii(x::acb)


Return the exponential of $\pi i x$.

# Base.sinMethod.

sin(x::acb)


Return the sine of $x$.

# Base.cosMethod.

cos(x::acb)


Return the cosine of $x$.

# Base.Math.sinpiMethod.

sinpi(x::acb)


Return the sine of $\pi x$.

# Base.Math.cospiMethod.

cospi(x::acb)


Return the cosine of $\pi x$.

# Base.tanMethod.

tan(x::acb)


Return the tangent of $x$.

# Base.Math.cotMethod.

cot(x::acb)


Return the cotangent of $x$.

# Nemo.tanpiMethod.

tanpi(x::acb)


Return the tangent of $\pi x$.

# Nemo.cotpiMethod.

cotpi(x::acb)


Return the cotangent of $\pi x$.

# Base.sinhMethod.

sinh(x::acb)


Return the hyperbolic sine of $x$.

# Base.coshMethod.

cosh(x::acb)


Return the hyperbolic cosine of $x$.

# Base.tanhMethod.

tanh(x::acb)


Return the hyperbolic tangent of $x$.

# Base.Math.cothMethod.

coth(x::acb)


Return the hyperbolic cotangent of $x$.

# Base.atanMethod.

atan(x::acb)


Return the arctangent of $x$.

# Nemo.logsinpiMethod.

logsinpi(x::acb)


Return $\log\sin(\pi x)$, constructed without branch cuts off the real line.

# Base.Math.gammaMethod.

gamma(x::acb)


Return the Gamma function evaluated at $x$.

# Base.Math.lgammaMethod.

lgamma(x::acb)


Return the logarithm of the Gamma function evaluated at $x$.

# Nemo.rgammaMethod.

rgamma(x::acb)


Return the reciprocal of the Gamma function evaluated at $x$.

# Base.Math.digammaMethod.

digamma(x::acb)


Return the logarithmic derivative of the gamma function evaluated at $x$, i.e. $\psi(x)$.

# Base.Math.zetaMethod.

zeta(x::acb)


Return the Riemann zeta function evaluated at $x$.

# Nemo.barnesgMethod.

barnesg(x::acb)


Return the Barnes $G$-function, evaluated at $x$.

# Nemo.logbarnesgMethod.

logbarnesg(x::acb)


Return the logarithm of the Barnes $G$-function, evaluated at $x$.

# Base.Math.erfMethod.

erf(x::acb)


Return the error function evaluated at $x$.

# Base.Math.erfiMethod.

erfi(x::acb)


Return the imaginary error function evaluated at $x$.

# Nemo.eiMethod.

ei(x::acb)


Return the exponential integral evaluated at $x$.

# Nemo.siMethod.

si(x::acb)


Return the sine integral evaluated at $x$.

# Nemo.ciMethod.

ci(x::acb)


Return the exponential cosine integral evaluated at $x$.

# Nemo.shiMethod.

shi(x::acb)


Return the hyperbolic sine integral evaluated at $x$.

# Nemo.chiMethod.

chi(x::acb)


Return the hyperbolic cosine integral evaluated at $x$.

# Nemo.modetaMethod.

modeta(x::acb)


Return the Dedekind eta function $\eta(\tau)$ at $\tau = x$.

# Nemo.modjMethod.

modj(x::acb)


Return the $j$-invariant $j(\tau)$ at $\tau = x$.

# Nemo.modlambdaMethod.

modlambda(x::acb)


Return the modular lambda function $\lambda(\tau)$ at $\tau = x$.

# Nemo.moddeltaMethod.

moddelta(x::acb)


Return the modular delta function $\Delta(\tau)$ at $\tau = x$.

# Nemo.ellipkMethod.

ellipk(x::acb)


Return the complete elliptic integral $K(x)$.

# Nemo.ellipeMethod.

ellipe(x::acb)


Return the complete elliptic integral $E(x)$.

# Nemo.sincosMethod.

sincos(x::acb)


Return a tuple $s, c$ consisting of the sine $s$ and cosine $c$ of $x$.

# Nemo.sincospiMethod.

sincospi(x::acb)


Return a tuple $s, c$ consisting of the sine $s$ and cosine $c$ of $\pi x$.

# Nemo.sinhcoshMethod.

sinhcosh(x::acb)


Return a tuple $s, c$ consisting of the hyperbolic sine and cosine of $x$.

# Nemo.agmMethod.

agm(x::acb)


Return the arithmetic-geometric mean of $1$ and $x$.

# Nemo.agmMethod.

agm(x::acb, y::acb)


Return the arithmetic-geometric mean of $x$ and $y$.

# Base.Math.polygammaMethod.

polygamma(s::acb, a::acb)


Return the generalised polygamma function $\psi(s,z)$.

# Base.Math.zetaMethod.

zeta(s::acb, a::acb)


Return the Hurwitz zeta function $\zeta(s,a)$.

# Nemo.risingfacMethod.

risingfac(x::acb, n::Int)


Return the rising factorial $x(x + 1)\ldots (x + n - 1)$ as an Acb.

# Nemo.risingfac2Method.

risingfac2(x::acb, n::Int)


Return a tuple containing the rising factorial $x(x + 1)\ldots (x + n - 1)$ and its derivative.

# Nemo.polylogMethod.

polylog(s::acb, a::acb)


# Nemo.polylogMethod.

polylog(s::Int, a::acb)


Return the polylogarithm Li$_s(a)$.

# Nemo.liMethod.

li(x::acb)


Return the logarithmic integral, evaluated at $x$.

# Nemo.lioffsetMethod.

lioffset(x::acb)


Return the offset logarithmic integral, evaluated at $x$.

expint(::acb)


# Base.Math.gammaMethod.

gamma(s::acb, x::acb)


Return the upper incomplete gamma function $\Gamma(s,x)$.

# Base.Math.besseljMethod.

besselj(nu::acb, x::acb)


Return the Bessel function $J_{\nu}(x)$.

# Base.Math.besselyMethod.

bessely(nu::acb, x::acb)


Return the Bessel function $Y_{\nu}(x)$.

# Base.Math.besseliMethod.

besseli(nu::acb, x::acb)


Return the Bessel function $I_{\nu}(x)$.

# Base.Math.besselkMethod.

besselk(nu::acb, x::acb)


Return the Bessel function $K_{\nu}(x)$.

# Nemo.hyp1f1Method.

hyp1f1(a::acb, b::acb, x::acb)


Return the confluent hypergeometric function ${}_1F1(a,b,x)$.

# Nemo.hyp1f1rMethod.

hyp1f1r(a::acb, b::acb, x::acb)


Return the regularized confluent hypergeometric function ${}_1F1(a,b,x) / \Gamma(b)$.

# Nemo.hyperuMethod.

hyperu(a::acb, b::acb, x::acb)


Return the confluent hypergeometric function $U(a,b,x)$.

# Nemo.hyp2f1Method.

hyp2f1(a::acb, b::acb, c::acb, x::acb)


Return the Gauss hypergeometric function ${}_2F_1(a,b,c,x)$.

# Nemo.jthetaMethod.

jtheta(z::acb, tau::acb)


Return a tuple of four elements containing the Jacobi theta function values $\theta_1, \theta_2, \theta_3, \theta_4$ evaluated at $z, \tau$.

# Nemo.ellipwpMethod.

ellipwp(z::acb, tau::acb)


Return the Weierstrass elliptic function $\wp(z,\tau)$.

Here are some examples of complex valued mathematical functions.

CC = ComplexField(64)

s = CC(1, 2)
z = CC("1.23", "3.45")

a = sin(z)^2 + cos(z)^2
b = zeta(z)
c = besselj(s, z)
d = hyp1f1(s, s+1, z)