Using The NAG Library With KDB+ in A Pure Q Environment
Using The NAG Library With KDB+ in A Pure Q Environment
Environment
Christopher Brandt*
September 12, 2018
Abstract
In the present technical report, we demonstrate how to integrate the NAG Library
with kdb+ using the Foreign Function Interface (FFI) from Kx Systems. The procedure
outlined herein leverages FFI to drastically simplify the development process for users.
The enclosed three examples were carefully chosen to illustrate usage cases that extend
to most of the 1700+ routines contained within the NAG Library.
1 Introduction
NAG and Kx Systems share a number of customers, many of whom use the NAG Library
with the q programming language. Within this report, we describe a procedure for using
the NAG Library with kdb+ in a pure q environment that will enable developers to write
less code, employ fewer development tools, and shorten overall development time.
* Numerical Algorithms Group (NAG) Inc., Lisle, IL, USA. Email: [email protected]
1
4 NAG Alternative C Interface
The NAG Library provides two interfaces for the C programming language. The first
interface, known as the NAG C Library, employs C structs and enums to ensure type
correctness and interface consistency across 1700+ routines. The second interface,
known as the alternative C interface, uses only C intrinsic types as arguments for each
routine. Since q is an array-based query language and lacks the internal framework to
create user-defined types that are compatible with comparable C structs and enums,
we recommend that kdb+ users work with the alternative C interface to the NAG
Library.
Originally serving as the C interface to the NAG Fortran Library, the alternative C
interface is available with the NAG C Library beginning with the Mark 26.2 release. The
documentation for this interface appears within the NAG Fortran Library
documentation.
This interface uses several typedefs to maintain compatibility for multiple NAG C
Library implementations across various operating systems and hardware architectures,
and we highlight the most commonly used typedefs below:
• Integer: basic integer type, resolves to a 32-bit or 64-bit C integer type (e.g.
int or long) depending on the implementation
• Charlen: character length argument for associated character arrays, resolves
to the same C intrinsic type as Integer
• NAG_CALL: only necessary when working with user-defined callback routines
for certain implementations of 32-bit Windows distributions; contact NAG
support for details
6 Examples
The following three examples demonstrate how to call NAG C Library routines using the
alternative C interface with q and FFI. These examples were carefully selected, as they
will mirror the majority of usage cases a customer will encounter across all 1700+
routines within the library. If your usage case falls outside of these four examples,
please contact NAG support for assistance.
2
6.1 Example 1: BLAS Routine DAXPBY
Our first example, which follows closely to the BLAS example from the FFI
documentation, requires only integer and floating-point type arguments to perform the
operation
𝑦 ∶= 𝛼𝑥 + 𝛽𝑦.
Below is the alternative C interface signature for NAG Library routine f16ec (BLAS
routine DAXPBY), which requires three Integers, two doubles, and two arrays of
doubles.
void f16ecf_ (
const Integer *n,
const double *alpha,
const double x[],
const Integer *incx,
const double *beta,
double y[],
const Integer *incy
)
Within our q script, we begin by first loading the FFI namespace into our q
environment using the following statement:
To satisfy the signature for our function, we define all scalar arguments as vectors
with one element (i.e. a pointer to the appropriate type). When these arguments are
passed by value to the routine, the address of the vector’s first element is copied to the
parameter, thereby satisfying the signature for our routine (e.g. the vector decays into a
pointer). For this specific routine, we are working only with objects of type Integer
and type double.
/ Parameters
n:1#5j
alpha:1#3.0f
x:5#-6.0 4.5 3.7 2.1 -4.0f
incx:1#1j
beta:1#-1.0f
y:5#-5.1 -5.0 6.4 -2.4 -3.0f
incy:1#1j
To call the NAG routine using pure q, we invoke the cf function from the FFI
namespace, followed by the argument list for the NAG routine. The cf function itself
receives two arguments: (1) a char containing the return type for the chosen routine
(or " " for a void function), and (2) the symbol name of the routine we wish to invoke.
Note that the symbol name of the routine includes the name of the shared object in
which it is located.
3
6.2 Example Two: Nearest Correlation Matrix
Our collection of nearest correlation matrix routines is one of the more popular sections
of the NAG Library. As such, our second example will demonstrate how to call NAG
Library routine g02ab to compute the nearest correlation matrix 𝑋 by minimizing the
weighted Frobenius norm
1 1 2
‖𝑊 2 (𝐺 − 𝑋)𝑊 2 ‖
𝐹
void g02abf_ (
double g[],
const Integer *ldg,
const Integer *n,
const char *opt,
const double *alpha,
double w[],
const double *errtol,
const Integer *maxits,
const Integer *maxit,
double x[],
const Integer *ldx,
Integer *iter,
Integer *feval,
Double *nrmgrd,
Integer *ifail,
const Charlen length_opt
)
We begin again by loading the FFI namespace and defining our arguments as vectors.
Note that the char argument opt is also defined as a vector with one element. The
associated string length argument length_opt must be defined as an atom, and not a
vector of length one, since it must be passed by value to the routine.
/ Parameters
g:16#2.0 -1.0 0.0 0.0 -1.0 2.0 -1.0 0.0
0.0 -1.0 2.0 -1.0 0.0 0.0 -1.0 2.0f
ldg:1#4j
n:1#4j
opt:1#"B"
alpha:1#0.02f
w:4#100.0 20.0 20.0 20.0f
errtol:1#0.0f
maxits:1#0j
maxit:1#0j
x:16#0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0f
ldx:1#4j
iter:1#0j
feval:1#0j
nrmgrd:1#0.0f
ifail:1#0j
4
length_opt:1j
To call the NAG routine using pure q, we again invoke the cf function, passing the
desired function symbol name and its return type as arguments, followed by the
argument list for the NAG routine.
void e04raf_ (
void **handle,
const Integer *nvar,
Integer *ifail
)
5
\l ffi.q
/ Parameters
handle:1#0j
n:1#7j
ifail:1#1j
The next step is to add the quadratic objective function to the problem handle using
NAG Library routine e04rf. The alternative C interface signature and subsequent q code
is displayed below.
void e04rff_ (
void **handle,
const Integer *nnzc,
const Integer idxc[],
const double c[],
const Integer *nnzh,
const Integer irowh[],
const Integer icolh[],
const double h[],
Integer *ifail
)
q code:
Next, we define simple bounds for the variables and add them to the problem handle
using NAG Library routine e04rh.
void e04rhf_ (
void **handle,
const Integer *nvar,
6
const double bl[],
const double bu[],
Integer *ifail
)
q code:
Linear constraints are then added to the problem handle using NAG Library routine
e04rj.
void e04rjf_ (
void **handle,
const Integer *nclin,
const double bl[],
const double bu[],
const Integer *nnzb,
const Integer irowb[],
const Integer icolb[],
const double b[],
Integer *idlc,
Integer *ifail
)
q code:
7
To verify that our problem handle has been defined correctly, we can display its
contents using NAG Library routine e04ry.
void e04ryf_ (
void **handle,
const Integer *nout,
const char *cmdstr,
Integer *ifail,
const Charlen length_cmdstr
)
q code:
/ Parameters
nout:1#6j
str:"overview; simple bounds; objective; linear constraints bounds;
linear constraints detailed; options"
len_str:99j
Our next step is to invoke the e04st solver. As mentioned previously, the alternative
C interface for NAG routine e04st requires six callback routines, which can be seen
below.
void e04stf_ (
void **handle,
void (NAG_CALL *objfun)(const Integer *nvar, const double x[],
double *fx, Integer *inform, Integer iuser[],
double ruser[], void **cpuser
),
void (NAG_CALL *objgrd)(const Integer *nvar, const double x[],
const Integer *nnzfd, double fdx[],
Integer *inform, Integer iuser[], double ruser[],
void **cpuser
),
void (NAG_CALL *confun)(const Integer *nvar, const double x[],
const Integer *ncnln, double gx[],Integer *inform,
Integer iuser[], double ruser[], void **cpuser
),
void (NAG_CALL *congrd)(const Integer *nvar, const double x[],
const Integer *nnzgd, double gdx[],Integer *inform,
Integer iuser[], double ruser[], void **cpuser
),
void (NAG_CALL *hess)(const Integer *nvar, const double x[],
const Integer *ncnln, const Integer *idf,
const double *sigma, const double lambda[],
const Integer *nnzh, double hx[], Integer *inform,
Integer iuser[], double ruser[], void **cpuser
),
void (NAG_CALL *mon)(const Integer *nvar, const double x[],
const Integer *nnzu, const double u[], Integer *inform,
const double rinfo[], const double stats[],
8
Integer iuser[], double ruser[], void **cpuser
),
const Integer *nvar,
double x[],
const Integer *nnzu,
double u[],
double rinfo[],
double stats[],
Integer iuser[],
double ruser[],
void **cpuser,
Integer *ifail
)
To pass the ‘dummy’ routines to the e04st solver using FFI, each callback argument
should be specified as a mixed list with the form (func;arg_types;return_types),
where func is the symbol name of the function, arg_types is a char array containing
the argument types of the function, and return_type is a char matching the return
type of the function (" " for a C void function). The symbol name for each ‘dummy’
routine includes the name of the shared object in which they are located.
/ Initial starting point
x:7#0.0f
Finally, we need to destroy the problem handle and deallocate all memory stored
within it using NAG Library routine e04rz.
void e04rzf_ (
void **handle,
Integer *ifail
)
q code:
9
.ffi.cf[(" ";`libnagc_nag.so`e04rzf_)](handle;ifail)
7 Conclusion
The new Foreign Function Interface (FFI) extension to the q programming language
enables kdb+ users to easily integrate the functionality of the NAG Library with kdb+.
Software developers can now experience shorter development times, writing less code
and employing fewer development tools by following the procedure described in this
report.
To obtain the example scripts for the enclosed example programs, please visit the
NAG GitHub webpage, or contact NAG Support at [email protected].
8 Links
Kx Systems: Using Foreign Functions with Kdb+
https://code.kx.com/q/interfaces/ffi/
10