Update matrix in-place in Clojure - matrix

Suppose I have a Clojure matrix A as such (formatted for clarity)
[[1 4 3]
[1 7 3]
[1 8 3]]
Now suppose I want to update the first column in place, by e.g. multiplying it by a factor of two, so that the new matrix becomes
[[2 4 3]
[2 2 3]
[2 8 3]]
How would one do this in clojure? I have tried things like assoc and stuff like
(join-along 1 (* (slice A 1 0) 2) (select A [0 1 2] [2 3]))
Naturally that did not work. It would be great if there was something like assoc for matrices e.g.
(massoc A [rows] [columns] replacement-vector)
or something simple like numpy in Python:
A[:,0]*2 = [[2 4 3]
[2 2 3]
[2 8 3]]
Thanks

You should look into clojure.core/matrix and see if it supports operations like this.
Here is something that may be what you're looking for. It should be trivial to change this to assoc a new value rather than updating after applying a function.
(defn mupdate-in
"Update all `coll' rows at `column' with `f'"
[coll column f & args]
(reduce #(apply update-in %1 [%2 column] f args)
coll
(range (count coll))))
An example:
(def m [[1 4 3]
[1 7 3]
[1 8 3]])
(mupdate-in m 0 * 2)
;; [[2 4 3]
;; [2 7 3]
;; [2 8 3]]
(mupdate-in m 2 + 10)
;; [[1 4 13]
;; [1 7 13]
;; [1 8 13]]

Related

How do I implement a nested for loop that converts every element in a 2D array into zeros in Clojure

I wish to implement (in Clojure) a nested for loop that converts every element in a 2D array into zero. Like the C code written below.
void set_to_zero(int n, int m[v][v]) {
int i, j;
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
m[i][j] = 0;
}
This is what I was able to do
(defn trial [n m]
(loop [i 0
j 0]
(if (= i (count (range n)))
(println m)
(if (= j (count (range n)))
(recur i j)
(assoc-in m[i j] 0)
)
)
)
)
This is what I get: i.e only one element changes and the rest stays same.
(trial 4 [[9 8 2 3][8 4 5 6][6 1 8 9][3 1 8 9]])
=> [[0 8 2 3] [8 4 5 6] [6 1 8 9] [3 1 8 9]]
Update
(defn trial [n m]
(for [i (range n)
j (range n)]
(if (> i n)
m
(if-not (> j n)
;(recur (inc i) j)
(assoc-in m[i j] 0)
;(println i j)
)
)
)
)
New result
(trial 4 [[9 8 2 3][8 4 5 6][6 1 8 9][3 1 8 9]])
=>
([[0 8 2 3] [8 4 5 6] [6 1 8 9] [3 1 8 9]]
[[9 0 2 3] [8 4 5 6] [6 1 8 9] [3 1 8 9]]
[[9 8 0 3] [8 4 5 6] [6 1 8 9] [3 1 8 9]]
[[9 8 2 0] [8 4 5 6] [6 1 8 9] [3 1 8 9]]
[[9 8 2 3] [0 4 5 6] [6 1 8 9] [3 1 8 9]]
[[9 8 2 3] [8 0 5 6] [6 1 8 9] [3 1 8 9]]
[[9 8 2 3] [8 4 0 6] [6 1 8 9] [3 1 8 9]]
[[9 8 2 3] [8 4 5 0] [6 1 8 9] [3 1 8 9]]
[[9 8 2 3] [8 4 5 6] [0 1 8 9] [3 1 8 9]]
[[9 8 2 3] [8 4 5 6] [6 0 8 9] [3 1 8 9]]
[[9 8 2 3] [8 4 5 6] [6 1 0 9] [3 1 8 9]]
[[9 8 2 3] [8 4 5 6] [6 1 8 0] [3 1 8 9]]
[[9 8 2 3] [8 4 5 6] [6 1 8 9] [0 1 8 9]]
[[9 8 2 3] [8 4 5 6] [6 1 8 9] [3 0 8 9]]
[[9 8 2 3] [8 4 5 6] [6 1 8 9] [3 1 0 9]]
[[9 8 2 3] [8 4 5 6] [6 1 8 9] [3 1 8 0]])
At the moment, it changes all the elements into 0 but does it separately would like it to return as one array with all the elements equal to zero.
P.S I am sure there are more efficient ways to achieve all zeros in a 2D vector but I'm particularly interested in the for loop method since it's popular in other languages and can help one more easily translate codes from other languages to Clojure (in some cases).
Thanks.
Since you already have the sizes of the structure (its a vector of
vectors) I think there is no need to pass in any sizes. So the one
thing to make sure is to keep the vectors (many tools in the clojure
belt use (lazy) sequences).
Using mapv does that. The function to map with can be (constantly
0). Then map that again over the outer vector. E.g.
Plain clojure:
(mapv (partial mapv (constantly 0)) [[9 8 2 3][8 4 5 6][6 1 8 9][3 1 8 9]])
; → [[0 0 0 0] [0 0 0 0] [0 0 0 0] [0 0 0 0]]
Alternative:
Using specter:
(setval [ALL ALL] 0 [[9 8 2 3][8 4 5 6][6 1 8 9][3 1 8 9]])
; → [[0 0 0 0] [0 0 0 0] [0 0 0 0] [0 0 0 0]]
First, you're never increasing the values of i and j. So, they never change. Thus, you never get to the recur call.
They way you phrase your question gives the impression that you think, you edit the vector in-place. You don't. With every assoc-in you're creating a new vector. (A new associative data-structure to be more precise, but regardless.) A lot of copying will happen under the hoods.
My take on this is that you'd best create a fresh data-structure from the sizes of the existing one. If the nested vectors can be of differing sizes, the code #cfrick wrote (map ... constantly) is good. If all of the nested vectors have the same size, there's a simpler alternative. Try to find it and tell us how it goes. :-)
Clojure arrays are immutable, so if you want to operate in an imperative/mutable fashion you need to use an atom. Consider the following code:
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(defn new-array
[M N]
(vec (for [i (range M)]
(vec (for [j (range N)]
(* i j))))))
(defn set-array-elem
[arr i j val]
(assoc-in arr [i j] val))
(defn change-array
[arr]
(let [work (atom arr)]
(doseq [i (range (count #work))]
(doseq [j (range (count (get #work i)))]
(swap! work set-array-elem i j
(* (inc i) (+ 3 j))))) ; set it to an "interesting" value
#work))
(dotest
(let [arr1 (new-array 3 5)]
(is= arr1
[[0 0 0 0 0]
[0 1 2 3 4]
[0 2 4 6 8]])
(is= (change-array arr1)
[[3 4 5 6 7]
[6 8 10 12 14]
[9 12 15 18 21]])))
Function set-array-elem returns a modified copy of the input array. The swap! in change-array calls this function and keeps the output in the atom work, replacing the previous immutable value. Thus we slowly transition from the original array to the final result, one element at at time.
I understand this is a learning exercise. If you ever need to manipulate arrays (nested vectors), please consider using either tupelo.array or tupelo.array.mutable and save a lot of writing (& debugging!)
Clojure template project to get you started. Includes many documentation links.
Tupelo Clojure library on Github
Tupelo Array
Tupelo Array Mutable
You can build a list of 0 with repeat:
(repeat 3 0)
; (0 0 0)
You can convert that into a vector with vec:
(vec (repeat 3 0))
; [0 0 0]
You just need to replace 3 with the length of each sub vectors:
(mapv #(-> (count %) (repeat 0) vec) [[1] [2 3] [4 5 6]])
; [[0] [0 0] [0 0 0]]
So if you know what the dimensions of your array are, create a new one.
(defn make-ary [m n]
(vec (repeat m (vec (repeat n 0)))))
I guess i was using assoc-in the wrong way. Was meant to use recur to implement assoc-in. I assume that was why I got several instances of the 2D vector returned instead of one. Using recur helped do that.
Thanks #cfrick #Stefan Kamphausen #Alan Thompson for pointing me to the right direction.
(defn trial [n m]
(loop [i 0
j 0
m m
]
(if (= i n)
m
(if (= j (dec n))
(recur (inc i) 0 (assoc-in m[i j] 0))
(recur i (inc j) (assoc-in m[i j] 0))
)
)
)
)
(trial 8 [[6 1 8 8 6 1 8 8][8 4 5 6 6 1 8 8][6 1 8 8 6 1 8 8][3 1 8 9 6 1 8 8][6 1 8 8 6 1 8 8][6 1 8 8 6 1 8 8][6 1 8 8 6 1 8 8][6 1 8 8 6 1 8 8]])
[[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]]

In place matrix operations in Clojure

I asked a related question before:
Update matrix in-place in Clojure
And unfortunately, being new to Clojure, I am even more confused now.
Essentially what I would like to do, in Python syntax, is simply, with matrix A:
[[1 4 3]
[1 7 3]
[1 8 3]]
take the determinant of A, call it D, and then do
A[:,0] = A[:,0]*(D /abs(D))
upon which I would like to do
A = A*(D**(-1./A.shape[0]))
But even while perusing the functionality of core.matrix it is proving very difficult to figure out how something quite as simple is done in Clojure, even with the help of the previous question.
I have got this far [in clojure syntax]:
(join-along 1 (* (slice A 1 0) (/ (det A) (abs (det A)))) (select A [0 1 2] [1 2]))
but then then how to update in-place, without storing in variable? Currently getting error message:
Unidentified exception when trying to call procedure join-along with arguments (1 [1.0 4.0 7.0] #<NDWrapper [[2 3] [5 6] [8 9]]>)
Yet this works:
>(def t1 [[1 1] [2 2] [3 3]])
>(def t2 [[9] [9] [9]])
>(join-along 1 t2 t1)
[[9 1 1] [9 2 2] [9 3 3]]
If that could be figured out then it should simply be an issue of doing:
(* "A-updated-matrix" (pow (det A) (/ -1 (dimension-count A 0)))
Also I can imagine that the above is probably not the most efficient way of performing these matrix operations.
UPDATE:
So it appears to be a problem with the clojure accesses matrices, and outputting column vectors as row vectors.
E.g.
>(def a [[1 2 3] [4 5 6] [7 8 9]])
>(def t2 (get-column a 0)) ; Gets first column
>(join-along 1 t2 a)
Unidentified exception when trying to call procedure join-along with arguments (1 [1 4 7] [[1 2 3] [4 5 6] [7 8 9]])
However if we do
>(def i [[2] [3] [4]])
>(join-along 1 i a)
[[2 1 2 3] [3 4 5 6] [4 7 8 9]]
it works fine.

Adding rows / columns to existing matrices in core.matrix (Clojure)

How does one add a row or a column to an existing matrix? I'm trying to add a bias-term, a column of ones, as the first row of a matrix. In Octave I can do this with:
M = [ones(size(M, 1), 1), M];
You can use the join function to append arrays along the major dimension.
And you can combine this with broadcast to get a matrix of ones in whatever size you like, e.g.:
e.g.
(join (broadcast 1 [1 3])
[[1 2 3]
[4 5 6]
[7 8 9]])
=> [[1 1 1]
[1 2 3]
[4 5 6]
[7 8 9]]

Implementing a counter in for

I would like to iterate over a collection and at the same time also maintain a counter ex
(for [x (range 10) y (inc 0)] [x y] )
I would like 'y' to represent the counter, so for every element the output is ( [0 0] [ 1 1] [2 2]...). How do I do that?
You can use indexed from clojure.contrib.seq. Example:
(indexed '(a b c d)) => ([0 a] [1 b] [2 c] [3 d])
You can also use map-indexed. Example:
(map-indexed vector "foobar") => ([0 \f] [1 \o] [2 \o] [3 \b] [4 \a] [5 \r])
Use map-indexed, as Simeon advices. In the for context it's convenient to use destructuring to get easy access to both the counter and the collection elements:
(for [ [y x] (map-indexed vector (range 10) ) ] [x y] )
> ([0 0] [1 1] [2 2] [3 3] [4 4] [5 5] [6 6] [7 7] [8 8] [9 9])
I figure if this question still had not been marked as "answered", there may be something else you are looking for, and perhaps it is the flexibility to define your own counter.
I agree with others that for the specific problem you outline, map-indexed is the way to go. However, if you insist on using for, I would recommend something like this:
(for [[x y] (map vector (range 10) (iterate inc 0))]
[x y])
Rafal has a very similar answer, except that the counter will always start from zero and increment by 1. In my version you could define your counter as you see fit. For example, by changing the above (iterate inc 0) to (iterate #(+ 2 %) 10), you could instead have a counter that starts at 10 and increments by 2.
(keep-indexed (fn [i el][el i]) (range 10))
or
(keep-indexed #(vec [%2 %1]) (range 10))
(keep-indexed #(identity [%2 %1]) (range 10))
;([0 0] [1 1] [2 2] [3 3] [4 4] [5 5] [6 6] [7 7] [8 8] [9 9])
Also, remember that using indexes in Clojure is generally a code smell.

How to generate one lazy sequence from a nested for loop in Clojure

This is a question about how to properly collect the results from a nested for loop in Clojure. Suppose you want to create a sequence of all vectors [i j] where 0<=j<i<4
The following code
(for [i (range 1 4)]
(for [j (range i)]
[i j]
)
)
produces
(([1 0]) ([2 0] [2 1]) ([3 0] [3 1] [3 2]))
but what I really want to get is
([1 0] [2 0] [2 1] [3 0] [3 1] [3 2])
What is the right way to do this?
Notice that I'm not interested in this specific sequence. My purpose here is to learn how to collect results from a nested for loop, which I need for a more complex problem.
Don't nest two loops, rather use one loop with two iterators:
(for [i (range 1 4)
j (range i)]
[i j])
Assuming you have to use nested for loops, apply concat is the preferred way to flatten a sequence by one level
=> (apply concat
(for [i (range 1 4)]
(for [j (range i)]
[i j])))
([1 0] [2 0] [2 1] [3 0] [3 1] [3 2])
#Oin's solution is always preferable, unless the inner loop depends on the outer loop.

Resources