The finesse.cmath extension

Using fast mathematical routines

The sub-module finesse.cmath is a Cython extension containing external declarations from the C headers "math.h" and "complex.h" as well as namespaces (implemented as cdef classes consisting purely of static-methods) defining “pure Cython” functions for use by other Cython extensions in Finesse.

The complex data type

One of the key elements exposed by finesse.cmath to other Cython extensions is the C type definition complex_t - defined as np.complex128_t which is just equivalent to the double complex C type.

Whenever your Cython extension requires complex numbers, always use this type definition rather than defining your own or redefining from elsewhere. To do this, simply add the following to your .pyx file(s):

from finesse.cmath cimport complex_t

Importing "math.h" and "complex.h" functions from finesse.cmath

If the fast function you need in your extension is one defined in these C headers then you can simply import this function in your .pyx file(s) with:

from finesse.cmath.cmath cimport <function_name>

And if this function is not yet included in the cdef extern block of finesse/cmath/cmath.pxd then simply add it as a declaration using the function signature given in the Common Mathematical Functions C reference or Complex Number Arithmetic C reference.

Importing custom fast arithmetic functions from finesse.cmath

As well as C level header functions, you can also define and use custom mathematical routines in / from finesse.cmath. Due to the internal mechanics of Cython, these functions are defined as part of cdef classes as cdef static-methods - effectively turning the class into a namespace.

For example, one of the functions defined is finesse.cmath.ComplexMath.rotate which takes a complex number (of type double complex) as the first argument and rotates it by an amount equal to the second argument in radians.

A full breakdown of the namespaces (and functions in each namespace) is given in the finesse.cmath documentation.

Note

If you are implementing a new function in finesse.cmath then make sure to:

  • put it in the correct cdef class / namespace (or create a new one if necessary),

  • use the @staticmethod decorator and define it as a cdef function,

  • only use code which will be translated directly into C with ideally no CPython API interaction (you can check this by looking at the generated cmath.html file in finesse/cmath/ which is produced when building the Cython extensions),

  • and if the function needs to be called in a multi-threaded environment (i.e. within scope of a Cython prange) then declare it as nogil. Note that such a function can only operate on C data types and cannot interact with Python objects in any way.

You can import these custom functions you need into another Cython extension via their namespaces, e.g:

from finesse.cmath cimport complex_t
from finesse.cmath cimport ComplexMath # custom complex arithmetic routines
from finesse.cmath cimport Gaussian # gaussian beam routines

cpdef some_function(complex_t z, double nr, double lambda0):
    cdef:
        inv_z = ComplexMath.inverse(z)
        w0 = Gaussian.w0_size(z, nr, lambda0)

    # etc. ...

Importing mathematical routines from Python

For reasons of performance and the internal mechanics of Cython, all the functions defined in finesse.cmath can only be used from other Cython extensions as they only expose a C API. To use a fast maths routine from the Python code of Finesse, you will need to import from finesse.utilities.maths. This is a Cython extension which exposes fast functions to Python.

Keep in mind, however, that this module does not expose Python wrappers of all the functions defined in finesse.cmath and likely will never need to as the mathematically heavy parts of the code should be in Cython and so will cimport directly from finesse.cmath anyway. If you do, however, need to expose a function from this module to Python then you can follow the pattern given in the example below:

from finesse.cmath cimport complex_t
from finesse.cmath cimport ComplexMath

def rotate(complex_t z, double phr):
    return ComplexMath.rotate(z, phr)

Note the explicit typing of the function arguments here, this allows Cython to optimise the resultant C code file. Also note that one cannot specify a return type for a def function, as CPython always expects PyObject* for the return type of any Python function.

The main purpose of finesse.utilities.maths is not to simply wrap definitions in finesse.cmath, as implied above. The functions in this module should be ones which are called often enough from the Python code itself to warrant having a performance boosted version of the routine. A good example of this is the finesse.utilities.maths.transform_q() function which is called by the beam tracing sub-module frequently.