Methods
The methods for the low level wrapper are automatically generated by parsing the Arb documentation. This is handled by the Arblib.ArbCall
module.
Parsing
The parsing is handled by
Arblib.ArbCall.parse_and_generate_arbdoc
— Functionparse_and_generate_arbdoc(doc_dir, out_dir = "src/arbcalls/"; filenames, verbose)
Parses the Flint documentation and generates corresponding Julia files. The value of doc_dir
should be a path to the directory doc/source/
in the Flint directory.
The filenames
argument can be given to specify specific doc files to use. The verbose
argument can be set to true to give more information about the result of the parsing.
Note that the parsing is done ahead of time and the generated files in src/arbcalls/
are added to git. As a user of the package you therefore typically don't need to care about this step.
Generated methods
The automatic generation of the methods is handled by
Arblib.ArbCall.@arbcall_str
— Macro@arbcall_str str
Parse a string as an Arblib.ArbCall.ArbFunction
, generate the code for a corresponding method with Arblib.ArbCall.jlcode
and evaluate the code.
For example
arbcall"void arb_zero(arb_t x)"
defines the method zero!(x::ArbLike)
.
Arblib.ArbCall.ArbFunction
— TypeArbFunction{T}(fname::String, args::Vector{Carg})
Struct representing a C-function in the Arb library.
Arblib.ArbCall.jlcode
— Methodjlcode(af::ArbFunction, jl_fname = jlfname(af))
Generate the Julia code for calling the Arb function from Julia.
The main things to understand is how the name of the generated function is determined, how the arguments are handled and the return value.
Naming
The name of the Arb function is "Juliafied" using the following guidelines:
- Prefixes and suffixes a function name which only refer to the type of input are removed since Julia has multiple dispatch to deal with this problem.
- Functions which modify the first argument get an
!
appended to the name.
The implementation is based on heuristics for determining when part of the function name is referring to the type or when the function modifies the argument. This works well for the majority of functions but gives a few odd cases.
Arguments
The arguments of the function are represented by
Arblib.ArbCall.Carg
— TypeCarg{T}(name, isconst)
Carg(str::AbstractString)
Struct representing a argument to a C function in the Arb library. The corresponding Julia type is T
, name
is the name of the argument, isconst
is true if the argument is declared as a const.
julia> Arblib.ArbCall.Carg("const arb_t x")
Arblib.ArbCall.Carg{Arb}(:x, true)
For the generated method the allowed types for the argument is determined by
Arblib.ArbCall.jltype
— Functionjltype(ca::Carg{T})
The most general Julia type for which we allow automatic conversion to the Arblib.ArbCall.ctype
of ca
.
These conversations should be done without any loss of information, for example for floating point numbers we only allow conversion from types with lower precision. In general the conversion is done using Base.cconvert
.
Arblib.ArbCall.ctype
— Functionctype(ca::Carg)
The type that should be used for the argument when passed to C code.
Some arguments are automatically converted to keyword arguments.
- For functions which take a precision argument this argument becomes a
prec::Integer
keyword argument which is by default set to the precision of the first argument (if applicable). - For functions which take a rounding mode argument this argument becomes a
rnd::Union{Arblib.arb_rnd,RoundingMode}
keyword argument which is by default set toRoundNearest
. - For functions which takes a flag argument this argument becomes a
flag::Integer
keyword argument which is by default set to0
. - For functions which takes an argument giving the length of the vector preceding the argument this argument becomes a keyword argument which is by default set to the length of the preceding vector. In this case the name of the keyword argument is the same as the argument name in the function declaration.
As with the naming the implementation is based on heuristics for determining when an argument is supposed to be a certain kind of keyword argument.
Return value
The returned value is determined in the following way
- For functions which have the C function has return type
void
and modify the first argument the generated method returns the first argument. This is follows the normal convention in Julia. - For predicates, for which the C function returns
int
, the return value is converted to aBool
. - Otherwise the return type is the same as for the C function.
Examples
For example Arb declares the following functions
void arb_zero(arb_t x)
slong arb_rel_error_bits(const arb_t x)
int arb_is_zero(const arb_t x)
void arb_add(arb_t z, const arb_t x, const arb_t y, slong prec)
void arb_add_arf(arb_t z, const arb_t x, const arf_t y, slong prec)
void arb_add_ui(arb_t z, const arb_t x, ulong y, slong prec)
void arb_add_si(arb_t z, const arb_t x, slong y, slong prec)
void arb_sin(arb_t s, const arb_t x, slong prec)
void arb_cos(arb_t c, const arb_t x, slong prec)
void arb_sin_cos(arb_t s, arb_t c, const arb_t x, slong prec)
int arf_add(arf_t res, const arf_t x, const arf_t y, slong prec, arf_rnd_t rnd)
void arb_poly_sin_series(arb_poly_t s, const arb_poly_t h, slong n, slong prec)
For which the following methods are generated
zero!(x::ArbLike)::ArbLike
rel_error_bits(x::ArbLike)::Int
is_zero(x::ArbLike)::Bool
add!(z::ArbLike, x::ArbLike, y::ArbLike; prec::Integer = _precision(z))::ArbLike
add!(z::ArbLike, x::ArbLike, y::ArfLike; prec::Integer = _precision(z))::ArbLike
add!(z::ArbLike, x::ArbLike, y::Unsigned; prec::Integer = _precision(z))::ArbLike
add!(z::ArbLike, x::ArbLike, y::Integer; prec::Integer = _precision(z))::ArbLike
sin!(s::ArbLike, x::ArbLike; prec::Integer = _precision(s))::ArbLike
cos!(c::ArbLike, x::ArbLike; prec::Integer = _precision(c))::ArbLike
sin_cos!(s::ArbLike, c::ArbLike, x::ArbLike, prec::Integer = _precision(s))::ArbLike
add!(res::ArfLike, x::ArfLike, y::ArfLike; prec::Integer = _precision(res), rnd::Union{Arblib.arb_rnd, RoundingMode} = RoundNearest)::Int32
sin_series!(s::ArbPolyLike, h::ArbPolyLike, n::Integer; prec::Integer = _precision(s))::ArbPolyLike
Series methods
Arb has several functions mean for computing truncated Taylor series (e.g. arb_sin_series
). These functions have special handling, to make them more convenient to use. In addition to the procedure discussed above they generate one more method. This extra method removes the "_series" suffix from the method name, restricts the input type to only series types (and not polynomial types) and takes the default length of the computed series from the first argument. As an example the function
void arb_poly_sin_series(arb_poly_t s, const arb_poly_t h, slong n, slong prec)
generates the method
sin!(s::ArbSeries, h::ArbSeries, n::Integer = length(s); prec::Integer = _precision(s))::ArbSeries
in addition to the usual one (see the examples above).
The main motivation for these extra methods is to make it easier to write generic code using mutability, see Mutable arithmetic.