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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With