Reputation: 1019
I am using a matrix as follows
(require '[clojure.core.matrix :as ccm])
(def M (ccm/matrix [[1 2] [3 4]]))
(ccm/mset! M 0 0 10)
However this throws an error
IllegalArgumentException No implementation of method: :set-2d! of protocol: #'clojure.core.matrix.protocols/PIndexedSettingMutable found for class: clojure.lang.PersistentVector clojure.core/-cache-protocol-fn (core_deftype.clj:568)
However this should work according to the wiki https://mikera.github.io/core.matrix/doc/clojure.core.matrix.html#var-mset.21
Upvotes: 4
Views: 662
Reputation: 8854
core.matrix can use different underlying matrix implementations. By default it uses the persistent-vector
implementation, which means that matrices are simply Clojure vectors containing Clojure vectors. However, Clojure vectors are immutable, so mset!
won't work on them. This is the expected behavior.
To use mset!
, you need to use one of the core.matrix implementations that can make mutable matrices. ndarray
is the matrix implementation that's always available by default in core.matrix, but you have to tell core.matrix that you want to use it.
user=> (use 'clojure.core.matrix)
nil
user=> (matrix [[1 2] [3 4]])
[[1 2] [3 4]]
That's what a persistent-vector matrix looks like.
You can create an ndarray matrix by passing an extra keyword to the matrix
function:
user=> (def M (matrix :ndarray [[1 2] [3 4]]))
#'user/M
user=> M
#object[clojure.core.matrix.impl.ndarray_object.NDArray 0x561ddbde "[[1 2] [3 4]]"]
Now mset!
will work:
user=> (mset! M 0 0 10)
10
user=> M
#object[clojure.core.matrix.impl.ndarray_object.NDArray 0x561ddbde "[[10 2] [3 4]]"]
Notice the elements over on the right. You can also use pm
to create a nicer representation:
user=> (pm M)
[[10 2]
[ 3 4]]
To make ndarray the default, use set-current-implementation
:
user=> (set-current-implementation :ndarray)
:ndarray
user=> (def M (matrix [[1 2] [3 4]]))
#'user/M
user=> M
#object[clojure.core.matrix.impl.ndarray_object.NDArray 0x5cd44e57 "[[1 2] [3 4]]"]
user=> (mset! M 0 0 10)
10
user=> M
#object[clojure.core.matrix.impl.ndarray_object.NDArray 0x5cd44e57 "[[10 2] [3 4]]"]
There are several other implementations available if you set them up as dependencies (e.g. in your Leiningen project.clj). Some of them support both mutable and immutable matrices.
By the way, as amalloy suggested, you can get a mutable matrix from an immutable matrix by passing the immutable matrix to mutable
. If you do this with a persistent-vector matrix, the returned matrix will not be a persistent-vector matrix, since there are no mutable persistent-vector matrices. The new matrix will be a matrix from a different implementation. Which implementation is used depends on your current environment, but if you haven't done anything special, an ndarray matrix should be what is returned.
Upvotes: 2
Reputation: 91887
However this should work according to the wiki
No, the link you provided clearly states that it will throw an exception if the matrix is not mutable. The documentation for matrix
isn't clear about whether it produces a mutable matrix or not, but evidently it does not. However, it is not hard to find a way to produce a mutable matrix: the function mutable
is right there on the same page.
Upvotes: 1