2017-05-14 57 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))