numericals

2023-02-15

A high performance numerical computing library for Common Lisp (focus: basic math operations)

Upstream URL

github.com/digikar99/numericals

Author

Shubhamkar B. Ayare (shubhamayare@yahoo.co.in)

License

MIT
README

numericals

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 cl:array and 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 dense-arrays:array.

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 numericals.

Usage and Features

Native CL arrays

As of this writing,

  • The only libraries that offer broadcasted operations on arrays are this and numcl
  • numcl does 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. :mix option of uiop:define-package can be useful for mixing the two libraries as per user preferences
  • Other minor differences wrt numcl include:
    • Both (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
    • numericals provides a *array-element-type-alist* equivalent to 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.
    • numcl relies on JIT backed by specialized-function, while numericals relies 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, uiop:define-package with :mix can 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.

Usage

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.

Why separate numericals and dense-numericals packages?

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.

Project Predecessors

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.

Background

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.

Acknowledgements

Dependencies (26)

Dependents (0)

    • GitHub
    • Quicklisp