Block Diagonal Matrix in Clojure - clojure

I looked through core.matrix searching for a block diagonal matrix function and searched Google, but have found no such function. Does such a function exist? If it does not could someone point me in the right direction to writing such a function.
Sample inputs would be nested vectors which would output along the diagonals of a larger nested vector.
Symbolic example:
Let a,b,c,d be matrices (nested vectors).
An example output would then look like
[[a 0 0 0] [0 b 0 0] [0 0 c 0] [0 0 0 d]]
where d might be [[0 1] [1 0]].

First of all you need a function to generate vector of size n with element m injected into i th position.
(defn vec-i [m i n]
(-> (repeat n 0)
(vec)
(assoc-in [i] m)))
(vec-i 'a 0 10) => [a 0 0 0 0 0 0 0 0 0]
(vec-i 'b 2 7) => [0 0 b 0 0 0 0]
Then just combine results for every i (assuming matrices are list of your diagonal elements)
(defn block-diag [matrices]
(let [n (count matrices)]
(vec (map-indexed #(vec-i %2 %1 n) matrices))))
(block-diag ['a 'b 'c 'd]) => [[a 0 0 0] [0 b 0 0] [0 0 c 0] [0 0 0 d]]
Of course, symbols abcd can be replaced to matrix.

The library Vectorz (which provides the underlying types for vectorz-clj) includes a BlockDiagonalMatrix class:
https://github.com/mikera/vectorz/blob/develop/src/main/java/mikera/matrixx/impl/BlockDiagonalMatrix.java
You'll have to use Java interop to instantiate it right now, but it offers a couple of advangtages:
Memory efficiency - only the block diagonal components are stored
Optimised operations - various vector operations exploit the fact that large areas of the matrix are guaranteed to be zero in order to perform faster computations
Longer term, it probably makes sense to add a block-diagonal-matrix function to core.matrix itself. In fact, I've just created an issue to do this:
https://github.com/mikera/core.matrix/issues/93

Related

Clojure: Same vector values in a row checker

I'm creating an Clojure Tic Tac Toe game, where I have a board variable with 9 numbers (def moves [0 0 0 0 0 0 0 0 0]) . This variable gets filled with 1's en 2's (no "x" or "o" yet). At the end of the game the variable could look like [2 1 2 1 1 1 2 1 2] where 1 owns the second row. Now I need a function to check if there's three in a row. I wanted to start horizontally. Which means I need a function to check if there's after each 3 numbers 3 of the same number are in a row. any ideas how I can create a function like this?
So this is the function so far:
(def moves [0 0 0 0 0 0 0 0 0])
(defn wongame? [playedmoved]
(
(def counter 0)
;action here....
)
)
(won moves) ;gives true/false
Something like this should work:
(defn end-of-game? [moves]
(->> moves
(partition 3)
(remove #(= [0 0 0] %))
(map (partial apply =))
(some identity)))
With your example input of [2 1 2 1 1 1 2 1 2] (partition 3) gives:
((2 1 2) (1 1 1) (2 1 2))
We need to use = with each list. apply is required because = works with individual arguments rather than a list. partial is required because the parameters to apply = are pending. #(apply = %) could have equivalently been used.
(false true false)
some is all about '(at least) one or none'. Here if one of the list it is passed is truthy then that one will be returned.
If you really need the answer to return true/false then put a call to boolean as the last function to the thread last macro (->>). I've left that out because only rarely do you need to actually return true or false in Clojure - you can rely on nil punning.
This same function will work for vertically as well. Start off with a general transpose function that works for a matrix (e.g. [[0 0 0][0 0 0][0 0 0]]):
(defn transpose [matrix]
(apply mapv vector matrix))
Then fashion your input before, and its output after:
(defn transpose-flat [xs]
(->> xs
(partition 3)
transpose
(mapcat identity)))
(def moves [0 0 1 1 0 1 2 2 2]) #_"the game's state in the middle"
At first, if we encounter like this pattern, we need stop the game,
Otherwise we are possible to misjudge the winner of this game
if the moves reaches the state like [2 2 1 1 1 1 2 2 2]. Which is the winner? We need to call this function each turn of the game.
Second, the name "won?" isn't appropriate because this function doesn't tell the winner, but tells the end of game. "won?" function should be renamed like ["end-of-game?" "game-end?" "end?"].
Third, I try to implement "winner" that returns the winner of the game like this:
(defn winner [moves]
(let [pattern-of-end {[1 1 1]:1 [2 2 2]:2}]
(->> moves #_"I use threading macro to explain"
(partition 3) #_"group by each three symbols.
1 line of 9 elements -> 3 lines of 3 elements"
(keep pattern-of-end) #_"If there is some lines that matches
the pattern-of-end ,that will return [1] or [2]"
first #_"Because the previous expression returns lazy-seq
we can get the scalar by calling first"
)))
This tells us the winner of the game.
It would have been easier if you had proper numbers for x's and o's:
(defn the-winner-is [moves]
(let [x 5
o 7]
(->> moves
(partition 3)
(map (partial apply +))
(some #{15 21}))))
This way it even says who is the winner (15 or 21).
(the-winner-is [5 5 7 7 7 0 7 7 7]) ; 21
(the-winner-is [5 5 5 7 7 5 5 7 7]) ; 15
(the-winner-is [5 7 5 7 7 5 5 7 5]) ; nil

How to perform a map using reduce

Hello I have a simple function like this:
(def state
(memoize
(fn state [t]
(if (<= t 0)
0
1))))
on which I am trying to call (reduce state (range 10)) which the intent of calling the function state on the range 0 1 2 3 4 5 ..., and receiving back 0 1 1 1 1 1 1 1 1 1.
That is not happening, thus I am obviously misunderstanding something, since I am getting:
clojure.lang.ArityException: Wrong number of args (2) passed to: state
The syntax for reduce is (reduce f coll) and my understanding was that it is as simple as doing (reduce + [1 2 3 4 5]).
Obviously one can do this easily enough with map I was just under the impression that reduce would work as well. With map, (map (fn [x] (state x)) (range 10)).
PS. this is just a test case, I genuinely do need memoization for the real thing.
Thanks
Obviously one can do this easily enough with map I was just under the impression that reduce would work as well.
Yes. Any map can also be a reduce. (Except reduce is not lazy, while map is).
The result of a reduce function is going to be the result that is returned in the end after N iterations of your function over your reduction range.
Your function returns a 0 or a 1, therefore, your reduce will ultimately return either a 0 or 1.
If you want to return a list, then your reduction function needs to return a list. Or, use a function other than reduce, such as map.
Also -- all reduction functions take 2 arguments, not 1. So your state function is not a valid function to pass to reduce. Though, it is a valid function to pass to map.
Incidentally, you can do this with reduce, you don't need map -- in fact, many functions can be expressed as reduce, including map, filter and others. But, you'd need to alter your reduction function to make it compatible.
The comments and other answers suggest you must use map, but here is a reduce that will do it:
(def state
(memoize
(fn state [r t]
(if (<= t 0)
(conj r 0)
(conj r 1)))))
(reduce state [] (range 10))
;;-> [0 1 1 1 1 1 1 1 1 1]
This is a great idiom when you have logic for the value of a particular item that depends on knowing about the other items. You do not have such logic here, so map is a better choice. But conceptually you can express many things in functional programming in terms of a fold which is what reduce is.
Here is an alternate method, keeping the original state function from the question, and therefore its memoization intact:
(def state
(memoize
(fn state [t]
(if (<= t 0)
0
1))))
(defn r-fn [r t]
(conj r (state t)))
(reduce r-fn [] (range 10))
;;-> [0 1 1 1 1 1 1 1 1 1]
This is more succinctly written as:
(reduce #(conj %1 (state %2)) [] (range 10))
well, that's because the reduce function should take exactly 2 parameters: accumulator and item from the coll, bur in case the accumulator is not provided during reduce call, the first step of reduction is applied to first 2 values from coll:
(reduce + '(1 2 3 4)) is really (+ (+ (+ 1 2) 3) 4)
but that's not what you need in your case:
user> (map state (range 10))
(0 1 1 1 1 1 1 1 1 1)
as you don't want to reduce a coll to a single value, but rather map each value to another

clojure for sequence comprehnsion adding two elements at a time

The comprehension:
(for [i (range 5])] i)
... yields: (0 1 2 3 4)
Is there an idiomatic way to get (0 0 1 1 2 4 3 9 4 16) (i.e. the numbers and their squares) using mostly the for comprehension?
The only way I've found so far is doing a:
(apply concat (for [i (range 5)] (list i (* i i))))
Actually, using only for is pretty simple if you consider applying each function (identity and square) for each value.
(for [i (range 5), ; for every value
f [identity #(* % %)]] ; for every function
(f i)) ; apply the function to the value
; => (0 0 1 1 2 4 3 9 4 16)
Since for loops x times, it will return a collection of x values. Multiple nested loops (unless limited by while or when) will give x * y * z * ... results. That is why external concatenation will always be necessary.
A similar correlation between input and output exists with map. However, if multiple collections are given in map, the number of values in the returned collection is the size of the smallest collection parameter.
=> (map (juxt identity #(* % %)) (range 5))
([0 0] [1 1] [2 4] [3 9] [4 16])
Concatenating the results of map is so common mapcat was created. Because of that, one might argue mapcat is a more idiomatic way over for loops.
=> (mapcat (juxt identity #(* % %)) (range 5))
(0 0 1 1 2 4 3 9 4 16)
Although this is just shorthand for apply concat (map, and a forcat function or macro could be created just as easily.
However, if an accumulation over a collection is needed, reduce is usually considered the most idiomatic.
=> (reduce (fn [acc i] (conj acc i (* i i))) [] (range 5))
[0 0 1 1 2 4 3 9 4 16]
Both the for and map options would mean traversing a collection twice, once for the range, and once for concatenating the resulting collection. The reduce option only traverses the range.
Care to share why "using mostly the for comprehension" is a requirement ?
I think you are doing it right.
A slightly compressed way maybe achieved using flatten
(flatten (for [i (range 5)] [ i (* i i) ] ))
But I would get rid of the for comprehension and just use interleave
(let [x (range 5)
y (map #(* % %) x)]
(interleave x y))
Disclaimer: I am just an amateur clojurist ;)

How to count the number of ones in a vector, given an upper limit

Given a vector of ones and zeros, I would like to count the number of entries with a value one. However, the vector may be very long and I only care to know if the vector has zero, one, or more entries with a value o f one.
Using the approach given here, I can count the number of ones in the vector.
(count (filter #{1} [1 0 1 0 0 1 1]))
Can I limit filter (or use some other approach) to avoid visiting any more than three elements of the vector, in this case?
Filter is lazy, so will only do as much work as required. Since you only care about having no 1's, one 1's or two or more ones, you only need to examine up to two elements of the filtered sequence of 1's, so just take 2 before you count:
user=> (count (take 2 (filter #{1} [1 0 1 0 0 1 1])))
2
user=> (count (take 2 (filter #{1} [0 0 0 0 0 0 0])))
0
user=> (count (take 2 (filter #{1} [0 0 0 0 0 0 1])))
1
user=> (def rare (repeatedly #(if (< (rand) 0.0001) 1 0)))
#'user/rare
user=> (take 10 rare)
(0 0 0 0 0 0 0 0 0 0)
user=> (count (take 2 (filter #{1} rare)))
2

How can I use Clojure's distinct? function on a collection?

The Clojure distinct? method doesn't take a collection, but rather a list of args
(distinct? x)
(distinct? x y)
(distinct? x y & more)
So (distinct? 0 0 0 0) correctly returns false, while (distinct? [0 0 0 0]) returns true. How can I use distinct? on a collection so that passing it a collection [0 0 0 0] would return false since the collection contains duplicates?
I do realize that the function is performing correctly, but I'm looking for a trick to apply it to the contents of a collection instead of a list of args.
As a workaround, I currently have
(defn coll-distinct? [coll]
(= (distinct coll) coll))
but I feel like I'm missing a more elegant way reusing distinct?
If you want to pass arguments as a seq to a function, use apply.
(apply distinct? [1 2 3 1])
; false
(apply distinct? [1 2 3])
; true