Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Displaced multidimensional arrays in common lisp

So I have some code that needs a subset of a multidimensional array in such a way that it works a bit more like taking a subsection of a matrix, ideally it would work like a displaced array.

So let's say I have something that looks like this

(defvar *a* (make-array '(3 3) :initial-contents 
   '((1 2 3) (2 3 1) (3 1 2))

And I want it to be accessible with an array *b*

(defvar *b* (make-array '(2 2) :displaced-to *a* :displaced-index-offset 
    (array-major-row-index *a* '(1 1)))

Such that *b* will point to

 #2a((3 1) (1 2))

instead of

 #2a((3 1) (3 1))

I've already written myself a multidimensional slice function that copies the parts of the array I want, but it would be ideal to not need to copy back and forth manually, is there any solution that works like this in vanilla common lisp?

I understand that the way that displaced multidimensional arrays work in a way that coheres directly with (array-major-row-index) (namely that #2a((1 2 3) (2 3 4)) has row indices (0 1 2 3 4 5) and therefore the displaced array at '(1 0) of dimensions '(2 2) will point to #2a((2 3) (2 3)), so I need to wrap the new array such that it refers to specific places in the old one, but so far I don't know how to capture such a reference.

I'm not entirely sure that it is possible to get pointers to places in the array, so I would appreciate if that could be cleared up.

like image 421
violet_white Avatar asked Dec 05 '25 19:12

violet_white


2 Answers

You can't directly do it, but FYI there used to be support for this in Symbolics Lisp Machines.

From Kent Pitman:

What was new with the LispM, and which did not carry into CL (perhaps because of the lack of microcode assist for speed) was conformally displaced arrays (I think you said :displaced-conformally t, or some such) in which case you got a displaced region of the original square (cube, etc) rather than a region of the linearized storage. This was useful for displacing to screen memory, especially since the LispM used DMA (direct memory access) display from a raster array that was, I think, specially known by the screen to mean "this array's memor IS the screen" and doing a SETF of AREF into that special array made something appear on the screen. All windows had conformally displaced indirect arrays that represented their part of the screen.

As pointed out by Rainer Joswig, there is a video on Youtube, from Kalman Reti, demonstrating conformally displaced arrays. It might be possible for implementations to provide support for this, but I don't know if any current one provides such displaced arrays. But other answers are fine suggesting alternatives.

like image 173
coredump Avatar answered Dec 09 '25 19:12

coredump


Multidimensional arrays are stored in memory as a one-dimensional array in row-major order. That is, #2a((1 2 3) (2 3 1) (3 1 2)) is actually the same as #(1 2 3 2 3 1 3 1 2).

CL-USER> (let ((a (make-array '(3 3) :initial-contents 
                              '((1 2 3) (2 3 1) (3 1 2)))))
           (make-array 9 :displaced-to a))
#(1 2 3 2 3 1 3 1 2)

A displaced array is a contiguous subset of the actual array (sharing memory with it). Your desired *B* would not be contiguous, since it would have to arbitrarily jump over the last 3 in the array.

           *B*
          /   \
        ---   ---
1 2 3 2 3 1 3 1 2

You would have to either include the skipped over 3 in the displaced array, or use two separate displaced arrays.

like image 45
jkiiski Avatar answered Dec 09 '25 18:12

jkiiski



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!