Lispy dialects with good multi-dimensional array programming support
Asked Answered
O

3

8

Are there any Lisp or scheme dialects that have good support for Array and linear algebraic manipulations. By good support I do not mean interfaces to BLAS/LAPACk, but efficient array primitives in the language itself. I would consider it efficient if it can hold its own against Numpy, say. I have heard Stalin to be very fast but I am very new to lisp and not familiar with syntactically convenient manipulation and efficient representation of multi-d arrays in such languages. Pointers (no pun intended) will be deeply appreciated especially if supported with personal experiences.

Ostler answered 15/7, 2011 at 2:54 Comment(0)
D
12

Arrays in standard Common Lisp can be multi-dimensional.

The Array Dictionary describes the available operations.

CL-USER 12 > (defparameter *a* (make-array '(3 2 4) :initial-element 'foo))
*A*

CL-USER 13 > *a*
#3A(((FOO FOO FOO FOO) (FOO FOO FOO FOO))
    ((FOO FOO FOO FOO) (FOO FOO FOO FOO))
    ((FOO FOO FOO FOO) (FOO FOO FOO FOO)))

CL-USER 14 > (setf (aref *a* 1 1 2) 'bar)
BAR

CL-USER 15 > *a*
#3A(((FOO FOO FOO FOO) (FOO FOO FOO FOO))
    ((FOO FOO FOO FOO) (FOO FOO BAR FOO))
    ((FOO FOO FOO FOO) (FOO FOO FOO FOO)))

CL-USER 16 > (array-dimensions *a*)
(3 2 4)

When working with arrays, it may be useful to use another feature of Common Lisp: type declarations and compiler optimizations. Common Lisp allows to write generic code without declaring types. But in critical sections one can declare types for variables, parameters, return values and so on. One then can instruct the compiler to get rid of some checks or to use type specific operations. The amount of support depends on the compiler. There are more sophisticated compilers like SBCL, LispWorks and Allegro CL which support a wide variety of optimizations. Some compilers also give large amounts of compilation information.

A last resort is to use a Foreign Function Interface (FFI) to call C code or to use inline assembler (which is supported by some compilers).

Common Lisp has by default the LOOP macro in the standard. It allows to express the typical imperative looping constructs. There is also an alternative, the ITERATE macro - it may have some advantages for multi-dimensional arrays.

Also note that Lisp arrays have some unusual features like displaced arrays. These use the storage of some other array, but can have a different dimensional layout.

It is also sometimes useful to write special macros, which hide the boilerplate of using arrays. Without that Lisp code with type declarations, multi-dimensional arrays and LOOP can be a bit large. An example for a typical code not using special linguistic abstractions is here: fft.lisp.

Special use of SIMD instructions or other forms of data parallelism are usually not provided out of the box by Common Lisp compilers. Exceptions may exist.

Dar answered 15/7, 2011 at 9:45 Comment(0)
B
4

Have you considered Clojure with the Incanter library? It has good support for matrices and has very high quality code for other things like graphing, mathematical functions, statistics and more. It also has good support for parallelism built right in.

Banlieue answered 15/7, 2011 at 14:16 Comment(0)
A
3

Racket (formerly PLT Scheme) has recently got nice multi-dimensional arrays (math/array). They seem to be inspired by Python NumPy and Data Parallel Haskell. Some key features you may like:

  • true N-dimensional hyperrectangular shape
  • broadcasting (pointwise operation on one or more arrays, like UFuncs in NumPy, but more flexible)
  • slicing, transforming and reshaping (on par with NumPy)
  • array comprehensions
  • partial and complete reductions (folds)
  • optional mutability (mutable arrays allow for explicit array-set!)
  • optional laziness (arrays are strict by default)
  • optional typing (required for fast code)

That's for array primitives. They happen to play well with math/matrix too.

> (require math/array math/matrix)
> (define arr3d (array-reshape (list->array (range 1 19)) #[2 3 3]))
> arr3d
(array #[#[#[1 2 3] #[4 5 6] #[7 8 9]] #[#[10 11 12] #[13 14 15] #[16 17 18]]])
> (array-map * arr3d arr3d)
(array
 #[#[#[1 4 9]
     #[16 25 36]
     #[49 64 81]]
   #[#[100 121 144]
     #[169 196 225]
     #[256 289 324]]])
> (define m (array-slice-ref arr3d (list 1 ::...)))
> m
(array #[#[10 11 12] #[13 14 15] #[16 17 18]])
> (array-shape m)
'#(3 3)
> (matrix-trace m)
42

math/array seems like a good reason to reconsider Scheme Racket for practical tasks.

Antislavery answered 11/4, 2013 at 10:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.