Способы быстро обновить элемент матрицы в Incanter, Clojure?

Предположим, у меня есть матрица 3x3

(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 

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

($ 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))))

person Kevin Zhu    schedule 15.04.2013    source источник


Ответы (1)


Если вы имеете в виду «быстро» в смысле производительности, то вы, вероятно, можете посмотреть на 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.

person mikera    schedule 15.04.2013