2017-05-14 22 views
0

我有兴趣使用elisp来实践一些线性代数算法(速度在这里不是一个目标) - 但是elisp不支持多维数组,像普通的lisp如何在elisp中创建矩阵? (以及Emacs Cal如何做?)

我需要最终做一些事情,比如在索引处获取值,获取子矩阵,获取此列,获取此行等,以编写算法,分解和其他东西

我该如何去重新创建类似于elisp的? 即。我如何从简单的数据结构,如列表,并建立矩阵?

我想看看Emacs的钙

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

,但它是一个有点超过我的头,我没有看到实际的矩阵是如何定义的

(虽然我很舒服数学,当谈到说什么我只有一点点的计划经验..所以也许这不是一个很好的入门项目?哈哈)

回答

0

在一种语言只有一维数组(或向量)是创建载体向量。

这里是一个简单的实现这一招(非常不适合生产使用!)中的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))