Creating a graph representing square sum relations - math

I'm trying to solve the square sum problem, more specifically creating a function that can help with the relations.
"the function should, given a set A of integers, produce a relation that includes tuple [a b],
iff a and b are in A and their sum is a square number"
To my aid, I got a help function square?, that tests whether a passed integer is a squared number.
(defn square?
[n]
(= n (sqr (isqrt n)))
)
I took a shot in dark with this, but honestly I'm lost.
(defn sqr-sum-rel
[A]
(reduce (fn [a b] (
if (square? (a + b))
[a b]
)) A )
)
Testing the function should return something like this:
(test? "test" (sqr-sum-rel (set (range 1 11))) #{[5 4] [2 2] [8 8] [4 5] [7 9] [1 3] [3 6] [6 10] [2 7] [1 8] [8 1] [7 2] [10 6] [6 3] [3 1] [9 7]})
I'm really new to Clojure and even functional programming in general, so any pointers in the right direction are appreciated.

To solve this problem, you can first generate all possible pairs of numbers from the set using for and then filter those pair. Assuming square? is properly implemented, we write a helper function that will be the first argument that we pass to filter:
(defn sum-is-square? [coll]
(square? (apply + coll)))
It takes a collection of numbers as argument and test if their sum is square?. Then we can write the complete function like
(defn sqr-sum-rel [A]
(set (filter sum-is-square? (for [a A
b A]
[a b]))))
that takes as argument a set A and first produces all pairs that can be formed by elements from this set, and then only keep those pairs for which sum-is-square? evaluates to true.
We can test it by passing in a set of numbers:
(sqr-sum-rel (set (range 1 11)))
;; => #{[8 8] [2 2] [7 2] [5 4] [6 3] [1 3] [1 8] [8 1] [7 9] [2 7] [3 6] [10 6] [4 5] [9 7] [3 1] [6 10]}
Added: A briefer implementation as suggested by the original poster uses the :when option of for:
(defn sqr-sum-rel [A]
(set (for [a A
b A :when (square? (+ a b))]
[a b]))))

i would also guess that the the number in set can't form the pair with itself, and also there is no need to compare pair members in reverse order, since we already know they form the relation needed. I would update it like this:
(defn sq-rel [a-set]
(seq (for [[x & t] (take-while seq (iterate rest a-set))
y t
:when (square? (+ x y))]
[x y])))
this one is more or less like an imperative
for (i = 0; i < len; i++) {
for (j = i + 1; j < len; j++)
if (isSquare(a[i] + a[j])) {
res.push([a[i], a[j]])
}
}
}
in repl:
user> (sq-rel #{1 2 3 4 5 6})
;;=> ([1 3] [4 5] [6 3])

Related

Find lists from multiple collections in clojure

I am a newbie to clojure. One question I am facing is to find special lists from multiple collections.
list one: (1 2 3 4 5)
list two: (a b c d e f)
Source list: (1 c 2 b 4 e a f)
Lists to find in the source list: (a 1), (1 a), (4 c), (f 2)
How to resolve it?
Thanks
Have a look at https://github.com/clojure/math.combinatorics
=> (combo/cartesian-product [1 2] [3 4])
((1 3) (1 4) (2 3) (2 4))
If my understanding of the problem is correct and you don't mind brute-force, you can use this solution.
(let [list1 '#{1 2 3 4 5}
list2 '#{a b c d e f}
source '(1 c 2 b 4 e a f)]
(for [x source
y source
:when (or (and (list1 x) (list2 y))
(and (list1 y) (list2 x)))]
[x y]))
=>
([1 c] [1 b] [1 e] [1 a] [1 f] [c 1] [c 2] [c 4] [2 c] [2 b] [2 e] [2 a] [2 f] [b 1] [b 2] [b 4] [4 c] [4 b] [4 e] [4 a] [4 f] [e 1] [e 2] [e 4] [a 1] [a 2] [a 4] [f 1] [f 2] [f 4])
You can also use shuffle to introduce some randomness and use take n to acquire the samples you need.
Or to make it even simpler, just remove items from list1 and list2 not in source and loop through these filtered lists.

Clojure, sum a list of vectors, recording positions along the way

Say I have a list of vectors
([0 0] [1 0] [1 0] [1 0])
I want to be able to add the list of vectors together and record each unique position along the way.
[0 0]
[0 0] + [1 0] = [1 0]
[1 0] + [1 0] = [2 0]
[2 0] + [1 0] = [3 0]
Giving 4 unique positions.
([0 0] [1 0] [2 0] [3 0])
Any idea how I could achieve this in Clojure?
I've tried the following code, but it overflows for large number of vectors :(
(defn add-vectors [vectors]
(let [[a b] vectors]
(vec(map + a b))))
(defn get-positions [dirs positions]
(if (empty? (rest dirs))
(set positions)
(do
(let [next-pos (add-vectors (take 2 dirs))]
(get-directions (conj (rest (rest dirs)) next-pos) (conj positions next-pos))))))
the (conj (rest (rest dirs)) replaces the first element in the next recursive call with the sum of the first two vectors from the last call.
To add two numbers together, you can use the + function, as you know:
(+ 2 1)
;;=> 3
To add two vectors together, you can use the mapv function to zip together the two vectors using +:
(mapv + [1 0] [1 0])
;;=> [2 0]
To perform a left fold of this vector addition across a sequence of vectors, you can use reduce:
(reduce #(mapv + %1 %2) [[0 0] [1 0] [1 0] [1 0]])
;;=> [3 0]
Or, replacing that function literal with a usage of partial:
(reduce (partial mapv +) [[0 0] [1 0] [1 0] [1 0]])
;;=> [3 0]
To obtain all the intermediate steps of this left fold, you can use reductions:
(reductions (partial mapv +) [[0 0] [1 0] [1 0] [1 0]])
;;=> ([0 0] [1 0] [2 0] [3 0])
Finally, to return only the unique elements from this sequence, you can use set:
(set (reductions (partial mapv +) [[0 0] [1 0] [1 0] [1 0]]))
;;=> #{[0 0] [1 0] [3 0] [2 0]}

Find cartesian product of 2 collections

I am trying to write a function in clojure returns cartesian product
(my-compute-fn [1 2 3] [4 5 6])
will return
[[1 4] [1 5] [1 6] [2 4] [2 5] ....]
My attempt resulted in this
(defn compute [col1 col2]
(let [totcol2 (count col2)
totcol1 (count col2)]
(map #(vector %1 %2)
(mapcat #(repeat totcol1 %1) col1)
(take (* totcol1 totcol2) (cycle col2)))))
Which does the job, but looks a bit clunky.
What would be a better and more concise implementation, involving more readily available functions from clojure.core?
Thanks!
edit:
Found clojure combinatorics, and it doesn't seem there's a magic functional way of doing this.
for is the prime candidate for this task:
(for [a [1 2 3]
b [4 5 6]]
[a b])
;; => ([1 4] [1 5] [1 6] [2 4] [2 5] [2 6] [3 4] [3 5] [3 6])
You can supply for with any number of seqs and it will bind the given symbols to each element of the seq associated with them. There is even cooler stuff like :when that lets you e.g. find all those products whose sum is 7:
(for [a [1 2 3]
b [4 5 6]
:when (= (+ a b) 7)]
[a b])
;; => ([1 6] [2 5] [3 4])

Updating a nested vector

Let's say i have the following vector
(def x [[1 2 3] [4 5 6] [7 8]])
and I want to append the number 9 to the last vector (I don't know the index of the vector)
(conj (vec (butlast x)) (conj (last x) 9))
#=> [[1 2 3] [4 5 6] [7 8 9]]
Is there a better/clearer way to do this?
Use the efficient tail access functions
(conj (pop x) (conj (peek x) 9))
But you could also
(update-in x [(dec (count x))] conj 9)

Clojure swap! not working inside a map function in let bindings

I have two sequences for comparison and I need to keep comparison results in a map, with data in the first sequence serving as keys and second as vals. Here comes sample code that works
(def myAtom (atom {}))
(map #(if (== %1 %2) (swap! myAtom assoc %1 %2 ))
[1 2 3] [4 5 3])
(prn #myAtom) ; ==> {3 3}
However after putting "same" thing above into one let bindings, it doesn't work anymore
(let [ myAtom (atom {})]
(map #(if (== %1 %2) (swap! myAtom assoc %1 %2 ))
[1 2 3] [4 5 3])
(prn #myAtom)) ;;==> {} empty???
So the question is, what happens to myAtom inside let binding? How come is it missing?
map is to generate lazy sequence out of a sequence whereas what you need is to do certain operation (i.e swap) for each item in a sequence, hence you need to use doseq
EDIT: (updated as par #mobyte suggestion)
(let [myAtom (atom {})
a [1 2 3]
b [4 5 3]]
(doseq [[x y] (map vector a b)]
(if (== x y) (swap! myAtom assoc x y )))
(prn #myAtom))
Your first example works because you executed each expression in REPL which made the map operation to execute its lazy operations.
I have seen many people try to use map to do certain operations like this, map should only be used for one purpose i.e mapping a sequence to another sequence without any side-effect operations.
As Ankur mentioned it's better to use doseq for imperative operations:
(let [myAtom (atom {})]
(doseq [[a b] (map vector
[1 2 3]
[4 5 3])]
(when (== a b) (swap! myAtom assoc a b )))
(prn #myAtom))
But you can force evaluation of the map result by using dorun in your original version:
(let [ myAtom (atom {})]
(dorun (map #(when (== %1 %2) (swap! myAtom assoc %1 %2 ))
[1 2 3] [4 5 3]))
(prn #myAtom))
P.S. Ankur's version is not equivalent to original one
doseq:
(doseq [a [1 2 3]
b [4 5 3]]
(println [a b]))
=> [1 4]
[1 5]
[1 3]
[2 4]
[2 5]
[2 3]
[3 4]
[3 5]
[3 3]
map:
(dorun (map #(println [%1 %2])
[1 2 3]
[4 5 3]))
=> [1 4]
[2 5]
[3 3]

Resources