【问题标题】:Displaced multidimensional arrays in common lisp常见lisp中的移位多维数组
【发布时间】:2016-11-25 18:39:39
【问题描述】:

所以我有一些代码需要多维数组的一个子集,它的工作方式更像是获取矩阵的一个子部分,理想情况下它会像一个置换数组一样工作。

假设我有一些看起来像这样的东西

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

我希望它可以通过数组*b* 访问

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

这样*b* 将指向

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

而不是

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

我已经为自己编写了一个多维切片函数,它可以复制我想要的数组部分,但是不需要手动来回复制是理想的,在 vanilla common lisp 中有没有像这样工作的解决方案?

我了解置换多维数组的工作方式与(array-major-row-index) 直接相一致(即#2a((1 2 3) (2 3 4)) 具有行索引(0 1 2 3 4 5),因此维度'(2 2) 的置换数组'(1 0) 将指向#2a((2 3) (2 3)),所以我需要包装新数组,使其引用旧数组中的特定位置,但到目前为止我不知道如何捕获这样的引用。

我不完全确定是否有可能获得指向数组中位置的指针,所以如果可以清除它,我将不胜感激。

【问题讨论】:

  • 你不能使用内置数组来做到这一点,而且置换数组在大多数实现(即 SBCL)中往往表现不佳。一个解决方案是将所有数据保存在一个大向量中,并简单地保存包含维度和步幅的小对象(即足够的信息来表示您想要的子集类型,以便您可以轻松地将(多维)索引转换为正确的索引进入向量)这是可能的,但您需要编写自己的函数来获取子集(或转置或其他)以及您自己的函数和 setf-expander 进行访问。
  • @DanRobertson 谢谢,这是另一个很好的理由来复制进出数组。

标签: multidimensional-array common-lisp


【解决方案1】:

您不能直接执行此操作,但仅供参考,Symbolic Lisp Machines 曾经支持此操作。

来自Kent Pitman

LispM 有哪些新功能,哪些没有包含在 CL 中(也许 因为缺乏微码辅助速度)是保形的 移位数组(我想你说的是:displaced-conformally t,或者一些 这样)在这种情况下,您会得到原始正方形的移位区域 (立方体等)而不是线性化存储的区域。这是 对于转移到屏幕内存很有用,特别是因为 LispM 使用来自光栅阵列的 DMA(直接内存访问)显示, 我想,屏幕上特地知道的意思是“这个数组的记忆是 屏幕”并在制作的特殊数组中执行 AREF 的 SETF 屏幕上出现了一些东西。所有窗户都已保形移位 代表屏幕部分的间接数组。

正如 Rainer Joswig 所指出的,来自 Kalman Reti 的 a video on Youtube 展示了保形位移阵列。实现可能对此提供支持,但我不知道当前是否有任何提供这种移位数组。但其他答案也可以提出替代方案。

【讨论】:

  • Symbolic Lisp Machine 的保形位移数组实际上由 Kalman Reti 在youtube.com/watch?v=o4-YnLpLgtk 中从 10:20 开始演示。
  • @RainerJoswig 谢谢。万一您不知道,您可以使用&t=__m__s(或使用youtubetime.com)在Youtube 视频中指定偏移量。
【解决方案2】:

多维数组以行优先顺序作为一维数组存储在内存中。即#2a((1 2 3) (2 3 1) (3 1 2))实际上与#(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)

置换数组是实际数组的连续子集(与其共享内存)。您想要的 *B* 不会是连续的,因为它必须任意跳过数组中的最后一个 3

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

您必须将跳过的3 包含在置换数组中,或者使用两个单独的置换数组。

【讨论】:

  • 谢谢,我怀疑我会写一个函数或其他东西来将更改后的数组切片复制回原来的位置。
【解决方案3】:

正如 jkiiski 的回答中所解释的,你不能直接获得你想要的,但你可以通过使用数组数组而不是多维数组来“近似”这样的结果。

例如:

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

然后*b* 可以定义为一个数组,其元素是在*a* 的适当数组上置换的数组:

(defvar *b* 
  (make-array 2 :initial-contents
    (loop for row from 1 to 2
       collect (make-array 2 :displaced-to (aref *a1* row) :displaced-index-offset 1))))

与多维数组的主要区别在于,它不是使用:

(aref *b* 1 1)

你应该使用:

(aref (aref *b* 1) 1)  ; => produces 2 for the example above

当然,您可以定义宏或阅读器宏来简化这种表示法。

【讨论】:

  • 您也可以保留*A* 二维并将收集更改为(make-array 2 :displaced-to *a* :displaced-index-offset (1+ (* row 3))) 之类的东西
  • 我考虑过这一点,但我真的不想进行嵌套的 aref 调用,它也不允许我使用任何为多维数组提供支持的数组函数,这意味着我的矩阵代码必须被重写,而且或多或少,我宁愿不这样做。
猜你喜欢
  • 2018-08-28
  • 2012-12-10
  • 2013-09-21
  • 2011-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-30
  • 1970-01-01
相关资源
最近更新 更多