A high performance numerical computing library for Common Lisp (focus: basic math operations)
THIS PROJECT IS UNSTABLE YET. THINGS ARE SUBJECT TO CHANGE.
See digikar99.github.io/numericals/ for documentation.
The project intends to offer a numpy-like (not exactly numpy!) API and equivalent performance for high performance number crunching. This is enabled by the use of SIMD using libraries like BMAS backed by SLEEF as well as BLAS. This is further coupled with multithreading using lparallel.
It provides mainly two ASDF systems:
numericals for use with
dense-numericals for use with dense-arrays:array, that is to say, wherever possible functionality in
numericals attempts to output
cl:array, while wherever possible,
dense-numericals attempts to output
At the moment, work is primarily happening under
dense-numericals, so it might be slightly better than
numericals; raise an issue if you'd like to shift the focus to
Usage and Features
Native CL arrays
As of this writing,
- The only libraries that offer broadcasted operations on arrays are this and numcl
numcldoes not yet have a focus on high performance - though, it should be possible to implement the current einsum based backend using BLAS and BMAS; instead the focus there is on functionality; by contrast, the focus here is on performance first, and functionality second. Users do not have to choose.
uiop:define-packagecan be useful for mixing the two libraries as per user preferences
- Other minor differences wrt numcl include:
(ones 2 3 :type 'single-float)and
(ones '(2 3) :type 'single-float)are legal in numericals; while only the latter is legal in numcl/numpy
swank:*readtable-alist*to provide a package local way of specifying the default element-type for arrays. This can be further overriden by binding
*array-element-type*. This does impose performance penalties however.
numclrelies on JIT backed by specialized-function, while
numericalsrelies on AOT backed by polymorphic-functions and cl-form-types. Again, these are not either-or, high level user functions can (in theory) utilize specialized-function, while the innards can use static-dispatch either by polymorphic-functions or static-dispatch or fast-generic-functions.
- In addition to these two, another performant library operating on CL arrays includes lla. Again,
:mixcan be used suitably.
The author of
numericals did not find other libraries operating on native CL arrays.
Non-native CL arrays
There are quite a few libraries in Common Lisp in this domain. I have only managed to take a peak at femlisp-matlisp.
That said, the goal of
numericals is not to replace python ecosystems, at least not in the short run, but instead to overcome the limitations of libraries like py4cl/2 of sub-10,000 instructions per second.
For the time being, preferably, fetch from this dist of ultralisp. Once
(ql:quickload "numericals") or
(ql:quickload "dense-numericals") is successful; use inside your own package using
:mix option of
uiop:define-package (see above discussion), or package-local-nicknames.
Run tests using
(asdf:test-system "numericals") or
(asdf:test-system "dense-numericals"); these are scattered throughout the system.
Not doing so would mean an additional configuration option. That implies an usage overhead on the part of the user, besides employing a decision factor into the return type of the functions. Separate packages, functions, symbols simply by-passes this issue. If a user is interfacing with the lisp ecosystem at large, they can choose
numericals without a second thought.
The project renaming reflects an attempt to separate the ANSI standard parts of the codebase from the SBCL-specific part, so that a portability attempt may be made in the future.
Curiosity got the better of me one day, and I set out to explore the limits of numerical computing with Common Lisp. I mean - what does speed require? Just memory-locality and SIMD? SBCL has memory-locality. What about SIMD? Well, the functionality hasn't been "standardized" yet, and there are several attempts. Indeed, SBCL needs more documentation - think Emacs! But knowledge exists in people's heads. People are willing to share it. So, this was possible.
PS: This library began as a reddit post, that, in turn, was triggered by this reddit post.
You should probably use the latest SBCL (get from git), at least SBCL-2.0.4. The build is fairly easy:
sh make.sh && sh run-sbcl.sh # or install.sh.
- Everyone who has contributed to SBCL.
- u/love5an and u/neil-lindquist for the required hand-holding and the gist.
- Paul Khuong for some blog posts.
- guicho271828 for SBCL Wiki as well as numcl.
- All the SLEEF contributors
- All the contributors of c2ffi and cl-autowrap
- It's possible that I could have forgotten to mention somebody - so... yeah... happy number crunching!