Wrappers for CBLAS and BLIS, using Guile's FFI.
![]() |
7 months ago | |
---|---|---|
mod | 7 months ago | |
test | 7 months ago | |
LICENSE | 1 year ago | |
README.md | 7 months ago | |
TODO | 2 years ago |
This is a set of Guile FFI bindings for two libraries of linear algebra subprograms, CBLAS and BLIS. They provide operations such as vector dot product, matrix-vector product, matrix-matrix product, and so on.
The bindings for either library are independent of each other; you do not need to have BLIS installed to use the CBLAS bindings or viceversa. I am packaging them together because they share a fair amount of code.
CBLAS (or BLAS) is by far the more popular library1, and there are many different implementations. However BLIS is much more regular and nicer to program for. These bindings are for the BLIS' ‘typed’ API.2
Both sets of bindings work in the same way. Upon importing (ffi cblas)
(or
(ffi blis)
), CBLAS (or BLIS) will be loaded from the default dynamic
library path (see ‘Installation notes’ below). There are up to three bindings
for each function, here using ZGEMM
as an example:
cblas_zgemm
(raw binding): the raw C function by pointer->procedure
. Don't
use this if you aren't familiar with Guile's FFI.
zgemm!
(typed binding): takes array arguments of type 'c64
and operates by
effect, without making copies. All the arguments must be properly sized. The
return value is unspecified.
zgemm
(functional binding): takes array arguments of compatible types and
returns a newly constructed array. The arguments will be converted as
necessary, which may result in copies. The returned array will be of 'c64
type.
In principle, for the last two bindings, you don't need to care whether your array is row-major or column-major or what the strides are. The bindings will extract the required strides from the array arguments. However, since CBLAS doesn't support arbitrary strides (e.g. it only supports a column stride for matrix arguments, assuming column-major order), some array arguments will cause the typed binding to fail, or result in extra copies with the functional binding3.
If the function doesn't return an array (e.g. cdot
) then we only provide
two bindings (e.g. cblas_cdot
and cdot
).
The bindings also provide type generic versions of the functions (e.g. dotv
for BLIS sdotv ddotv cdotv zdotv
). These simply call one of the
typed variants according to the type of the first array argument.
Enter ,help (ffi cblas)
(or ,help (ffi blis)
) at the Guile REPL to list all
the bindings available.
Note that this package is a work in progress and that there are bugs. For example, negative strides require specific handling for CBLAS and are not supported yet. BLIS doesn't have this problem.
guile-ffi-cblas
uses dynamic-link
to load the dynamic libraries for
CBLAS/BLIS. To do this, the names of the respective library files must
be known. The default names libcblas
/libblis
can be configured with the
environment variables GUILE_FFI_CBLAS_LIBNAME
/GUILE_FFI_BLIS_LIBNAME
. The
name for BLIS is a safe bet but the name for CBLAS is sadly variable;
possible alternative names are libblas
or libatlas
.
If your CBLAS/BLIS libraries are not installed in the default dynamic
library search path, you can configure specific paths for guile-ffi-cblas
with
the environment variables
GUILE_FFI_CBLAS_LIBPATH
/GUILE_FFI_BLIS_LIBPATH
. There are other variables
that control where dynamic-link
searches for libraries (LTDL_LIBRARY_PATH
,
LD_LIBRARY_PATH
) and you may prefer to set those instead. See also
https://notabug.org/ZelphirKaltstahl/guile-ml#using-guile-ffi-cblas for
notes on using guile-ffi-cblas
on Guix.
The tests use SRFI-64.
$GUILE -L mod -s test/test-ffi-cblas.scm
$GUILE -L mod -s test/test-ffi-blis.scm
Depending on your installation (see above) you might need
GUILE_FFI_CBLAS_LIBNAME=libotherblas \
GUILE_FFI_CBLAS_LIBPATH=/custom/path/lib \
$GUILE ... etc.
and similarly for BLIS
.
¹ See http://www.netlib.org/blas/ or https://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms. ↩
² See (https://github.com/flame/blis/blob/master/docs/BLISTypedAPI.md). ↩
³ The situation with BLIS is a bit complicated. By default (2020/07) BLIS
will flag overlapping stride combinations in any of the array arguments as
errors, even when the result is well defined. However, if you disable BLIS'
internal error checking with (bli-error-checking-level-set
BLIS_NO_ERROR_CHECKING)
BLIS will produce the correct result, as far as
I've been able to verify. (ffi blis)
performs independent shape checks on the
typed and functional bindings, and the array arguments have valid strides by
construction, so the lack of error checking by BLIS itself isn't necessarily
a problem. The test suite includes tests with a variety of overlapping stride
combinations for gemm
and gemv
. Still, BLIS doesn't officially support
these strides. Note that if the destination argument has overlapping strides,
then the result depends on the order in which the operations are carried out and
is pretty much undefined. (ffi blis)
will not check the destination argument
for this error. ↩
⁴ Some distributions of libcblas
do not provide these. guile-ffi-cblas
will still work, just without these bindings. ↩