繁体   English   中英

如何在elisp中制作矩阵? (以及Emacs Cal如何做到这一点?)

[英]How would I make a matrix in elisp? ( and how does Emacs Cal do it?)

我对使用elisp练习实现一些线性代数算法(这里的速度不是目标)感兴趣,但是elisp不支持像通用lisp这样的多维数组

我最终需要做一些事情,例如在索引处获取值,获取子矩阵,获取此列,获取此行等,以编写算法,分解以及诸如此类的东西

我将如何在elisp中重新创建类似内容? 即。 如何从简单的数据结构(如列表)转到矩阵?

我试图看一下Emacs calc

https://github.com/emacs-mirror/emacs/blob/65eee8392ff95f58f7b0bd036e1fe065523658c6/lisp/calc/calc-ext.el

但这有点麻烦,我看不出实际的矩阵是如何定义的

(虽然我对数学很满意,但是当谈到lisps时,我只有一点计划经验。所以也许这并不是一个好的入门项目?哈哈)

在只有一维数组(或向量)的语言中,显而易见的方法是创建向量的向量。

这是elisp中这个技巧的简单实现(非常不适合生产使用!):

(defun make-simple-array (dims &optional init)
  ;; make n-dimensional array, represented as a vector of vectors (of
  ;; vectors ...).
  (if (null (cdr dims))
      (make-vector (car dims) init)
    (let* ((d1 (car dims))
           (dt (cdr dims))
           (v (make-vector d1 nil))
           (i 0))
      (while (< i d1)
        (aset v i (make-simple-array dt init))
        (setq i (1+ i)))
      v)))

(defun simple-array-ref (a indices)
  (if (null (cdr indices))
      (aref a (car indices))
    (simple-array-ref (aref a (car indices)) (cdr indices))))

(defun simple-array-set (a indices newval)
  (if (null (cdr indices))
      (aset a (car indices) newval)
    (simple-array-set (aref a (car indices)) (cdr indices) newval)))

这种方法很简单,但是会导致可怕的局部性:数组的元素可以散布到整个地方。 更好的方法是分配一个大向量,然后计算其中的元素位置。 这就是任何严肃的数组实现都将起作用的方式。

对于hack值,这是一个原始的和部分的实现,该实现将数组保留为大向量并计算位置。 在此实现中,数组存储为(v . factors)的缺点,其中,这些factors是预先计算的索引因子,您需要计算v的索引。 此实现至少有两个问题:

  • 数组不知道它们的维数:您可以根据索引因子和向量的长度进行计算,但是我懒得实现它;
  • 不检查维度,因此,例如,如果您有2x2数组,则可以访问索引为(0 2)的元素,实际上是索引为(1 0)的元素。

无论如何,这是一个实现。

(defun compute-flat-array-total-size (dimensions)
  ;; this is in fact (reduce #'* dimensions), but elisp
  (let ((s 1))
    (mapc (lambda (d) (setq s (* s d))) dimensions)
    s))

(defun compute-flat-array-index-factors (dimensions)
  (cond ((null dimensions)
         '(0))
        ((null (cdr dimensions))
         '(1))
        (t (let ((ftail (compute-flat-array-index-factors (cdr dimensions))))
             (cons (* (car dimensions) (car ftail))
                   ftail)))))

(defun compute-flat-array-index (indices factors)
  ;; Again, elisp sucks: you can't even use mapc here
  (let ((index 0)
        (itail indices)
        (ftail factors))
    (while (not (null itail))
      (when (null ftail)
        (error "too many indices"))
      (setq index (+ index (* (car itail) (car ftail)))
            itail (cdr itail)
            ftail (cdr ftail)))
    (unless (null ftail)
      (error "two few indices"))
    index))

(defun make-flat-array (dimensions &optional init)
  ;; a flat array is a cons of a vector of its contents and a list of
  ;; index factors.
  (cons (make-vector (compute-flat-array-total-size dimensions) init)
        (compute-flat-array-index-factors dimensions)))

(defun flat-array-ref (fa indices)
  (aref (car fa) (compute-flat-array-index indices (cdr fa))))

(defun flat-array-set (fa indices newval)
  (aset (car fa) (compute-flat-array-index indices (cdr fa)) newval))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM