2013-04-15 2 views
1

Предположим, у меня есть матрица 3х3Способы быстрого обновления элемента матрицы в Incanter, Clojure?

(def myMatrix (matrix (range 9) 3)) 
; A 3x3 matrix 
; ------------- 
; 0.00e+00 1.00e+00 2.00e+00 
; 3.00e+00 4.00e+00 5.00e+00 
; 6.00e+00 7.00e+00 8.00e+00 

я могу использовать $, чтобы получить элемент, скажем, второй строке первого столбца

($ 1 0 myMatrix) ; --> 3 

Есть ли метод API для быстрого обновления элемента, а затем возвращают матрица? например

(update-matrix-by-element 2 1 myMatrix 4) 
; A 3x3 matrix 
; ------------- 
; 0.00e+00 1.00e+00 2.00e+00 
; 4.00e+00 4.00e+00 5.00e+00 
; 6.00e+00 7.00e+00 8.00e+00 

Ближайшие методы API я могу найти в bind-rows и bind-columns, и моя текущая версия функции с помощью этих двух методов является

;note i j starts from 1 rather than 0 
(defn update-matrix-by-element [i j myMatrix value] 
    (if (or (> i (count (trans myMatrix))) (> j (count myMatrix)) (< i 1) (< j 1) (not (integer? i)) (not (integer? j))) 
     myMatrix 
     (let [n (count myMatrix) 
     m (count (trans myMatrix)) 
     rangeFn #(if (== %1 %2) %1 (range %1 %2)) 
     m1 (if (== (dec i) 0) [] 
      ($ (rangeFn 0 (dec i)) :all myMatrix)) 
     m2 (if (== i m) [] 
       ($ (rangeFn i m) :all myMatrix)) 
     matrixFn #(if (matrix? %) % [ %]) 
     newRow (if (== (dec j) 0) 
        (bind-columns [value] (matrixFn ($ (dec i) (rangeFn j n) myMatrix))) 
        (if (== j n) 
        (bind-columns (matrixFn ($ (dec i) (rangeFn 0 (dec j)) myMatrix)) [value] ) 
        (bind-columns (matrixFn ($ (dec i) (rangeFn 0 (dec j)) myMatrix)) [value] (matrixFn ($ (dec i) (rangeFn j n) myMatrix)))) 
       ) 
    ] 

    ; (prn " m1 " m1) (prn " m2 " m2) (prn " newrow " newRow) 

    (bind-rows m1 newRow m2)))) 

ответ

2

Если вы имеете в виду «быстро» в смысле производительности, то вы, вероятно, можете посмотреть на core.matrix, который предназначен для поддержки быстро изменяемых матричных операций.

Пример использования vectorz-clj реализации для core.matrix:

(def M (matrix [[1 2] [3 4]])) 
=> #<Matrix22 [[1.0,2.0][3.0,4.0]]> 

(mset! M 0 0 10) 
=> #<Matrix22 [[10.0,2.0][3.0,4.0]]> 

(time (dotimes [i 1000000] (mset! M 0 0 i))) 
"Elapsed time: 28.895842 msecs" ;; i.e. < 30ns per mset! operation 

Это будет гораздо быстрее всего, что требует строительства новой изменчивой матрицы, тем более, что матрицы становятся больше/имеют более высокую размерность.

Я работаю над тем, чтобы сделать core.matrix аккуратно интегрироваться с Incanter, поэтому вы должны иметь возможность использовать матрицы core.matrix прозрачно внутри Incanter слишком долго.