core.matrix icon indicating copy to clipboard operation
core.matrix copied to clipboard

Add API functions for setting rows / columns / sub-matrices

Open mikera opened this issue 12 years ago • 10 comments
trafficstars

Ideas:

  • (set-row m i v)
  • (set-column m i j)
  • (set-submatrix-at m i j small-matrix)

mikera avatar Apr 20 '13 03:04 mikera

If I understand the suggestion correctly, I would expand and suggest to add the elementary row operations. (switching, multiplication, and row addition; see http://en.wikipedia.org/wiki/Elementary_matrix).

Not sure what the semantics of the last function (set-submatrix-at) is supposed to be.

kasterma avatar Apr 20 '13 07:04 kasterma

@kasterma: good suggestion, though I think that is worth a separate issue. I'll create one.

mikera avatar Apr 20 '13 09:04 mikera

https://github.com/mikera/matrix-api/issues/40

mikera avatar Apr 20 '13 11:04 mikera

If I'm right it can be done using mutable "views" into original array (or at least can pretend to be done this way if underlying matrix representation doesn't support mutation).

si14 avatar Jun 14 '13 13:06 si14

Well we probably ultimately want two versions (immutable and mutable) of each: set-row and set-row! for example.

The mutable versions could certainly be implemented with an mutable view.

The immutable version would need to construct a new matrix. However structural sharing is possible, so parts of the new matrix could be shared with the original matrix - possibly via a view.

mikera avatar Jun 15 '13 10:06 mikera

I've also thought already about implementing 2 APIs for Incanter - mutable & immutable.

alexott avatar Jun 15 '13 13:06 alexott

We'll get mutable + immutable versions of most operations for free if we complete the Incanter / core.matrix integration.

Most core.matrix functions already have immutable and mutable versions where it makes sense, e.g. add and add!, where the ! versions generally mutate their first argument.

mikera avatar Jun 15 '13 14:06 mikera

I'm sorry for not being clear enough.

I meant something like this MATLAB/Octave code:

octave:1> a = eye(3)
a =

Diagonal Matrix

   1   0   0
   0   1   0
   0   0   1

octave:2> a(2,1:2) = [2,2]
a =

   1   0   0
   2   2   0
   0   0   1

The thing here is that we already need a powerful tool to take slices of array. Why don't reuse it to assign values as well, as it is done in MATLAB/Octave? From the point of API, I can imagine "slicing schemes" as first-class objects:

(def s (slicing-scheme [2 1 :to 2]))
(sub (eye 3) s) ; returns a slice
(set (eye 3) s) ; returns new matrix
(set! (eye 3) s) ; mutates in place

DSL for slicing is another issue, of course.

si14 avatar Jun 16 '13 13:06 si14

slicing schemes as first class objects is an interesting idea, I'd be interested to see an implementation that demonstrates that it can be done efficiently and in a general way.

But do note that core.matrix already includes an NDWrapper type that can wrap an arbitrary subset of a matrix. See clojure.core.matrix.impl.wrappers namespace and the submatrix function.

Use example:

(def A (array :ndarray [[1 2 3] [4 5 6] [7 8 9]]))
(def S (submatrix A [[1 1] [0 2]]))
S
=> #<NDWrapper [[4 5]]>

Currently NDWrapper doesn't support mutation, but it could easily be upgraded to do so. In which case, we would be able to do stuff that alters the original matrix like:

(assign! S 0)
S
=> #<NDWrapper [[0 0]]>
A
=> #<NDArray [[1 2 3] [0 0 6] [7 8 9]]>

Overall the NDWrapper is quite flexible and good for simple use cases. The problem is that it adds quite a lot of index lookup overhead for each element (Dmitry: we wouldn't need your shiny new NDArray if the NDWrapper was ultra-fast!)

mikera avatar Jun 16 '13 17:06 mikera

Row setting implemented in this commit: https://github.com/mikera/core.matrix/commit/95993eaf9c4b77a866e538cd2784d8e4f13dadeb

Still not sure of how to handle the more general strategy....

mikera avatar Oct 28 '13 01:10 mikera