开发者

Lisp: multidimensional array elementwise operations

开发者 https://www.devze.com 2023-01-24 08:08 出处:网络
What is the \"correct\" construct in Common Lisp to apply elementwise operations to multidimensional arrays?

What is the "correct" construct in Common Lisp to apply elementwise operations to multidimensional arrays?

The following examples should help illustrate what I'm trying to do:

A) Suppose I want to increase every element of an array by one:

0 1 2    1 2 3
3 4 5 -> 4 5 6
6 7 8    7 8 9

B) Suppose I want to add 2 arrays:

1 2   -1 -1    0 1
3 4 + -2 -2 -> 1 2
5 6   -3 -3    2 3

C) Suppose I want to find the largest elements of several arrays, elementwise:

max( 0 1 , 开发者_如何学运维4 -1 , 0 0 ) -> 4 1
     2 3   0  0   8 1      8 3

Basically I think I'm looking for some sort of "arraymap" function which would be used in like so: (arraymap f A1 A2 ... An), where f takes n arguments as input, and the Ai are arrays of the same size.

In the above examples it would be used like so:

A)

(setq M #2A((0 1 2) (3 4 5) (6 7 8)))
(arraymap #'incf M)

B)

(setq M #2A((1 2) (3 4) (5 6)))
(setq N #2A((-1 -1) (-2 -2) (-3 -3)))
(arraymap #'+ M N)

C)

(setq M #2A((0 1) (2 3)))
(setq N #2A((4 -1) (0 0)))
(setq O #2A((0 0) (8 1)))
(arraymap #'max M N O)

I have tried some constructs with map and loop, but it seems to not work since multidimensional arrays are not a sequence type.


There are four ways to do that:

  • Write an ARRAY-MAP function based on the array dimensions and iterate over those.

  • Use ROW-MAJOR-AREF, which views the array like a vector.

  • Use displaced one-dimensional arrays for the operations.

Example for a use of displaced arrays:

(defun array-map (function &rest arrays)
  "maps the function over the arrays.
   Assumes that all arrays are of the same dimensions.
   Returns a new result array of the same dimension."
  (flet ((make-displaced-array (array)
           (make-array (reduce #'* (array-dimensions array))
                       :displaced-to array)))
    (let* ((displaced-arrays (mapcar #'make-displaced-array arrays))
           (result-array (make-array (array-dimensions (first arrays))))
           (displaced-result-array (make-displaced-array result-array)))
      (declare (dynamic-extent displaced-arrays displaced-result-array))
      (apply #'map-into displaced-result-array function displaced-arrays)
      result-array)))

Using it:

CL-USER 3 > (array-map #'1+ #2A((0 1 2) (3 4 5) (6 7 8)))

#2A((1 2 3) (4 5 6) (7 8 9))

CL-USER 4 > (array-map #'+ #2A((1 2) (3 4) (5 6)) #2A((-1 -1) (-2 -2) (-3 -3)) )

#2A((0 1) (1 2) (2 3))
  • Use internal, implementation specific, operations for efficient array operations.


For anyone coming here looking for an up-to-date answer to this question: https://github.com/bendudson/array-operations defines aops:each (and aops:each*) that does exactly what the OP asks for.

0

精彩评论

暂无评论...
验证码 换一张
取 消