How can I quickly generate matrix by row from range?
For example, given
my_example_matrix = [[1 2 3]
[4 5 6]
[7 8 9]]
How can I generate the matrix fastly by using range 1:9?
Best.
This is quick in a way because no part of it allocates memory, so the length of the range won't matter.
julia> transpose(reshape(1:9, (3, 3)))
3×3 LinearAlgebra.Transpose{Int64,Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}}:
1 2 3
4 5 6
7 8 9
Related
I am using Julia 1.6.1.
B is a matrix. For example,
B =
[ 2 4 4 4 5 ;
1 2 2 3 5 ;
1 2 3 3 3 ;
1 2 2 5 6 ;
1 3 4 4 4 ; ]
I wanted to sort it forcsing on each row.
sortedB = sortslices( B, dims=1, rev=true)
Then, we get sorted B
sortedB =
[ 2 4 4 4 5 ; # 1st row of the original matrix B
1 3 4 4 4 ; # 5th row of the original matrix B
1 2 3 3 3 ; # 3rd row of the original matrix B
1 2 2 5 6 ; # 4th row of the original matrix B
1 2 2 3 5 ;] # 2nd row of the original matrix B
I would like to get the array [1 5 3 4 2].
How can I do that ?
It seems that sortperm does not work.
sortperm( sortslices( B, dims=1, rev=true) )
# ERROR: MethodError; no method matching sortperm(::Matrix{Int64})
If performance is an issue use a non-allocating version.
julia> sortperm(view.(Ref(B), 1:size(B,1), :), rev=true)
5-element Vector{Int64}:
1
5
3
4
2
Here are some benchmarks using BenchmarkTools:
julia> #btime sortperm(view.(Ref($B), 1:size($B,1), :),rev=true);
376.471 ns (3 allocations: 432 bytes)
julia> #btime sortperm(collect(eachslice($B,dims=1)),rev=true)
642.683 ns (6 allocations: 496 bytes);
you can use eachrow or eachslice:
julia> C = collect(eachslice(B,dims=1))
5-element Vector{SubArray{Int64, 1, Matrix{Int64}, Tuple{Int64, Base.Slice{Base.OneTo{Int64}}}, true}}:
[2, 4, 4, 4, 5]
[1, 2, 2, 3, 5]
[1, 2, 3, 3, 3]
[1, 2, 2, 5, 6]
[1, 3, 4, 4, 4]
julia> sortperm(C,rev=true)
5-element Vector{Int64}:
1
5
3
4
2
although this will allocate more than necessary (collect is needed apparently)
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]]
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.
I'd like to be able to generate a set of tournament match-ups such that each player faces each other player at least once, each player plays the same number of games. Think of it as an abstraction of round-robin matchups to Mario Kart.
In my case, I have 17 contestants, and would like them to play in rounds of 3 or 4 players. I'd like to have a way to generate S, a set of subsets of P (players) such that each element of P occurs in at least one element of S with each other element of P.
At first I thought a Balanced Tournament Design would answer, but it doesn't seem to have any way to match multiple contestants per round, just multiple additional face-offs for each pair.
It also smacks of an exact cover problem, but not quite.
This would be applicable to games such as four-player chess, icehouse, various card and dice games, and the like as well.
I've just created an algorithm for this, but it does have its shortcomings. If P is the number of players, and C the number of contestants in each game, my algorithm simply creates an array the size of C in which I keep the indices of each player in the current game.
I start by filling the array with the lowest possible indices where each index is still larger than the previous one ([1, 2, 3]). In each round I start from the back of the array and try to increment the player index. When I reach out of bounds I move one step to the left, incrementing that player index and setting all the following players to their lowest possible value while still keeping each index larger than the previous one.
So for 5 players and 3 contenstants in each round I get
[1, 2, 3]
[1, 2, 4]
[1, 2, 5]
[1, 3, 4] <- could not increase 3rd position, increase 2nd position
[1, 3, 5]
[1, 4, 5] <- could not increase 3rd position, increase 2nd position
[2, 3, 4] <- could not increase 3rd or 2nd position, increase 1st position
[2, 3, 5]
[2, 4, 5] <- could not increase 3rd position, increase 2nd position
[3, 4, 5] <- could not increase 3rd or 2nd position, increase 1st position
---------
could not increase any position -> done
The problem with this is obvious; players are not distributed fairly across games, but rather, many players have to play an unnecessary number of consecutive games (in particular, player 1 plays all his/her games in succession and then has to wait for the remainder of the tournament).
While this should solve your problem as it's currently defined, I too would be interested in a better approach with increased fairness (less consecutive games for each player).
I was trying to do something similar for 12 players/4 per game where each player has to play all other players over 5 rounds. Unfortunately, my solution only worked for 7 rounds. I'm interested in solving this myself for N players and M per game.
https://gist.github.com/anonymous/e3372d1e61b01cf453dc26a488c9e345
(ns tournament-gen.core)
(defn rotate [n ps]
(concat (drop n ps) (take n ps)))
(defn round [size ps]
(apply mapcat vector (partition (Math/floorDiv (count ps) size) ps)))
(defn rounds [size n ps]
(take n (iterate #(rotate 2 (round size %)) ps)))
(defn set->map [gset]
(into {}
(for [k gset]
[k gset])))
(defn verify [size gs]
(apply merge-with
clojure.set/union
(for [game (mapcat (partial partition size) gs)]
(set->map (set game)))))
; I got it to work in 7 rounds for 12, but it seems like 5 should be possible
(map (partial partition 4) (rounds 4 7 (range 0 12)))
;result
(((0 1 2 3) (4 5 6 7) (8 9 10 11))
((6 9 1 4) (7 10 2 5) (8 11 0 3))
((2 11 9 7) (5 0 1 10) (8 3 6 4))
((1 3 11 5) (10 6 9 0) (8 4 2 7))
((9 4 3 10) (0 2 11 6) (8 7 1 5))
((11 7 4 0) (6 1 3 2) (8 5 9 10))
((3 5 7 6) (2 9 4 1) (8 10 11 0)))
(sort-by first (into {} (for [[k v] (verify 4 (rounds 4 5 (range 0 12)))]
[(str "Player " k) (count v)])))
=>
(["Player 0" 10]
["Player 1" 12]
["Player 10" 12]
["Player 11" 11]
["Player 2" 12]
["Player 3" 11]
["Player 4" 10]
["Player 5" 11]
["Player 6" 12]
["Player 7" 10]
["Player 8" 12]
["Player 9" 11])
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]]