How to build a lazy sequence of perfect number in Clojure? - clojure

I tried to find a list of perfect number in this way:
(defn classify [num]
(let [factors (->> (range 1 (inc num))
(filter #(zero? (rem num %))))
sum (reduce + factors)
aliquot-sum (- sum num)]
(cond
(= aliquot-sum num) :perfect
(> aliquot-sum num) :abundant
(< aliquot-sum num) :deficient)))
(defn is-p [n]
(= :perfect (classify n)))
(defn list-perfect [n]
(filter is-p (range 1 (inc n))))
Question:
How to build a lazy sequence of perfect numbers, so that I can use (take n ...) to easily get a list.
Is this code idiomatic and efficient? Any improvement?
Thanks in advance.

Your algorithm is very inefficient, it's O(n).
For a quick win, you can immediately reduce the range by a half, as you won't ever have factors that are greater than the number you're testing divided by 2.
So change it to:
(defn classify [num]
(let [factors (->> (range 1 (max 2 (inc (quot num 2))))
;; ...
However... you can change it to O(sqrt n) which is magnitudes faster. See my timings below.
The real efficiency is noticing that factors are in pairs of [x (quot num x)] and then only check the first (sqrt num) (or slightly over):
(defn perfect? [n]
(let [r (range 2 (+ 2 (int (Math/sqrt n))))
s (set (mapcat #(if (zero? (rem n %))
[% (quot n %)])
r))
t (reduce + 1 s)]
(= n t)))
I've split it into separate calculations so you can verify each stage.
The range can be reduced from 2..((sqrt n) + 2), and initialise the reduction with 1 (which is always a factor).
This changes the problem from an O(n) to O(sqrt n), so if you're checking large numbers, makes a vast difference.
As an illustration here are some times on larger values for n on my MBP:
n "n/2" "sqrt n"
33550336 1,172.5ms 2.85ms
8589869056 274,346.6ms 16.76ms
137438691328 didn't time 44.27ms
so using root version was 16,369 times faster for the 6th perfect number. See http://en.wikipedia.org/wiki/List_of_perfect_numbers for more details.
EDIT:
Why (int (root n)) + 2? And why `[x (quot n x)]?
When you work out the factors of a number n, then if you find one (say, a), then n/a is also a factor (call it b) because n = a * b
e.g. looking at 28, the first relevant factor is 2, and clearly 28/2 = 14 is also a factor. So you don't need to check 14, you already know it's a factor from the fact that 2 is.
as we're incrementally checking numbers from 2 upwards, we're incidentally finding the higher numbers coming down:
2 is a factor, 28 / 2 = 14 -> [a, b] = [2, 14]
4 is a factor, 28 / 4 = 7 -> [a, b] = [4, 7]
7 is a factor, 28 / 7 = 4 -> [a, b] = [7, 4] - wait a minute...
The [a,b] pairs here are the [% (quot n %)] in the mapcat function, e.g. when the range is currently iterating the value 2, then % is 2 inside the fuction, and so (quot n %) is (quot 28 2) which is 14, thus [% (quot n %)] is simply the vector [2 14], which then gets added to the set after being flattened to 2 and 14 as values. Later, when the range value is 4, then [% (quot n %)] is [4 (quot 28 4)] which is [4 7], and again is flattened by mapcat as the numbers 4 and 7.
So we add each pair of numbers (flattened via mapcat) to our set, include the number 1, and end up with #{1 2 14 4 7}, which are the factors of 28. (Actually, I don't put 1 in the set as I don't need to, instead I start the summing reduction at 1, which is same effect).
But at what point do they turn around? i.e. when do we know that [7,4] will already have been included in the set as [4,7]?
clearly it's when a > b, because in finding the lowest numbers we always find the highest number with it, so we can finish checking at this point.
but what is this point? it's simple, if a perfect number were a square number, then a and b would be equal, i.e. a*a = n, so a = sqrt(n).
Thus the highest value of a we need to check is the whole number that is larger than the root of n.
e.g. for 28, sqrt(28) = 5.292, so we have to check 6 to be sure that we've included the lowest number possible that could be a factor that has a paired factor.
so we need (int (sqrt n)) + 1.
I always do this in case the root calculation is 1.9999999999... and rounds wrong way, so adding 1 more ensures you eliminate any rounding errors.
but in a range, if you want to include that number you have to add 1 more to it (range drops the high number, (range 6) = (0 1 2 3 4 5)), hence why it adds 2 to the value: 1 for the range, 1 to ensure it's above the rounded down root.
Although, after saying this, I've tested perfect numbers up to 2305843008139952128 and it works with +1 instead of +2, not that it's a massive saving. Probably because non of the perfect numbers are close to perfect squares in ones I checked, so there's no rounding error in (int (sqrt n)).
If you're interested in perfect numbers, I'd recommend reading http://britton.disted.camosun.bc.ca/perfect_number/lesson1.html

list-perfect is already lazy due to your usage of filter:
(filter pred coll)
Returns a lazy sequence of the items in coll for which
(pred item) returns true. pred must be free of side-effects.
Whether code is idiomatic or not might be a matter of opinion (and hence off-topic), but it looks good enough from my perspective.

Related

How to properly bind greater and lesser values in the loop in Clojure?

I need to bind properly the greater and lesser value in the initial binding in the loop. The values are provided in ad-hoc order, so I need to distinguish them first. The loop itself is used inside an anonymous function.
So, I need to do something like:
(#(loop [divident %1 divisor %2] (some-recursion)) greater lesser)
or, this in case of swapped arguments:
(#(loop [divident %2 divisor %1] (some-recursion)) lesser greater)
If you need values to be in order from greater to lesser or lesser to greater then you could use the functions sort and sort-by. For instance:
(sort [1 7 4 6])
;;=> (1 4 6 7)
(sort-by - [1 7 4 6])
;;=> (7 6 4 1)
So for two numbers you can easily destructure the sort result:
(let [[lesser greater] (sort [7 1])]
(println lesser greater))
;;=> 1 7
Applying that to the loop:
(defn x-1 []
(#(let [[lesser greater] (sort [%1 %2])]
(loop [bigger greater
smaller lesser]
(println smaller bigger))) 7 1))
;;=> 1 7
For two numbers, the simplest approach is just to use max and min in the loop binding:
(#(loop [dividend (max %2 %1)
divisor (min %2 %1)]
(println (format "larger: %d smaller: %d" dividend divisor)))
2 1)
Not sure that this is a proper solution, but: we can do any initial binding and than do the appropriate binding switch in the first recursion loop.
Here is an example of implementation of the Euclidean algorithm as an anonymous function:
(#(loop [dd %1 dr %2]
(if (zero? (rem dd dr))
dr
(recur dr (rem dd dr))))
858 1023)
;; -> 33
(#(loop [dd %1 dr %2]
(if (zero? (rem dd dr))
dr
(recur dr (rem dd dr))))
1023 858)
;; -> 33

ArityException Wrong number of args (0) passed to: core/max

If I run this code, I will get an error "ArityException Wrong number of args (0) passed to: core/max"
(apply max (filter #(zero? (mod % 7)) (range 1 3)))
However, if I run this code
(apply max (filter #(zero? (mod % 7)) (range 1 10)))
then I get the result 7.
Is there anyone who can help me to figure out this problem?
(filter #(zero? (mod % 7)) (range 1 3))
this, produces an empty sequence.
However, max must be called with at least one argument. When you apply an empty sequence to it, it's called with zero arguments, and this produces the arity exception.
You could do something like this:
(defn my [a b]
(let [result (filter #(zero? (mod % 7)) (range a b))]
(if (zero? (count result))
nil ; or 0 or.. whatever
(apply max result))))
apply and reduce
Because the question came up, here's a short explanation of the difference between apply and reduce.
They are two totally different concepts, however, in the following case both do the same job when combined with max.
let xs be any collection of numbers.
(apply max xs) equals (reduce max xs)
apply
Usually functions are called with a number of arguments, so one can call max like so: (max 3), or (max 5 9), or (max 4 1 3) ... As noticed before: just (max) would be an arity exception.
Apply however, lets someone call a function passing the arguments in the form of a collection. So in correspondence to the last example, the following is possible: (apply max [3]), or (apply max [5 9]), or (apply max [4 1 3]) ... Just (apply max []) or even (apply max) would lead to the same arity exception as above. This is useful in many cases.
reduce
Reduce in contrast is a bit trickier. Along with map and filter it's absolutely essential for functional programming languages like Clojure.
The main idea of reduce is to walk through a collection, in each step desired information from the current item is processed and added to a memo or accumulator.
Say, one wants to find out the sum of all numbers in a collection.
Let xs be [3 4 5 23 9 4].
(reduce + xs) would do the job.
more explicitly one could write: (reduce (fn [memo value] (+ memo value)) xs)
The function which is passed as the first argument to reduce expects two parameters: The first one is the memo, the second one the value of the current item in the collection. The function is now called for each item in the collection. The return value of the function is saved as the memo.
Note: that the first value of the collection is used as an initial value of the memo, hence the iteration starts with the second value of the collection. Here's what it is doing:
(+ 3 4) ; memo is 7 now
(+ 7 5) ; memo is 12 now
(+ 12 23) ; memo is 35 now
(+ 35 9) ; memo is 44 now
(+ 44 4) ; memo is 48 now
(There's also a way to specify the start value of the memo, see clojuredocs.org for more details)
This works equally with max. In each iteration the value of the current item is compared with the memo. Each time the highest value is saved to the memo: Hence the memo in this case represents the "maximum value until now".
So (reduce max [4 1 3 5 2]) is calculated like this:
(max 4 1) ; memo is 4
(max 4 3) ; memo is 4
(max 4 5) ; memo is 5
(max 5 2) ; memo is 5
so?
Which one to use now? It showed that there's not really a notable difference in the time that (reduce max (range 100000000)) and (apply max (range 100000000)) take. Anyways, the apply solution looks easier to me, but that's just my opinion.
There are no numbers divisible by 7 between 1 and 3, the result of filter in your first example returns an empty sequence, which means that the first example if calling (apply max []) which is the same as calling (max). max requires at least one parameter, hence the ArityException.
A couple of options to fix it:
(last (filter #(zero? (mod % 7)) (range 1 3))
or
(if-let [by-7 (seq (filter #(zero? (mod % 7)) (range 1 3)))]
(apply max by-7)
nil ;; or whatever value in case the collection is empty
)
According to the error message, the number of arguments that are passed to max is 0, and that is wrong. I guess it makes sense because it's impossible to compute the maximum for an empty list.
The reason why max gets no arguments is that there are no numbers divisible by 7 between 1 and 3.

my Modulo Inverse in clojure Seems to give wrong answer

Hi I am programming in clojure and though the problem of modulo inverse has nothing to do with language i am stuck at this code -
(defn EulerDiv [x p]
(let [ToMod (+ p 2)]
(loop [num 1 toPow (int p) numDouble x]
(if (= 0 toPow)
num
(let [numDouble2 (rem (* numDouble numDouble) ToMod)
halfToPow (int (/ toPow 2))]
(if (odd? toPow)
(recur (rem (* num numDouble) ToMod)
halfToPow
numDouble2)
(recur num halfToPow numDouble2))
))))
)
It seems to give me right answers for small Primes but when i am using it in a problem with Bigger primes i am getting answers other than result like :
(= 2 (mod (* 4 (EulerDiv 2 (- 3 2))) 3))
This prints true
(def ToMod (+ 10e8 7))
( = 1 (int (mod (* 2 (EulerDiv 2 (- ToMod 2))) ToMod)) )
This prints false.
Also there is rem and mod in clojure.
mod makes the output positive and hence i can not use it in between the calculations.
It is a programming contest but this is just part of solution and this info of modulo inverse was also provided in the problem page.
The problem is that of programming calculator grammar for evaluating evpressions like 4/-2/(2 + 8)
You are straying from integer arithmetic.
Given integers, the / function can produce rationals: (/ 1 2) is 1/2, not 0.
And 1e9 is 1.0E9, a double, not an integer.
There are appropriate substitutes available. Look at the arithmetic section here for an integer division function, and at the cast section for something to convert a number to an integer.
All the best!

find all subsets of an integer collection that sums to n

i'm trying to find a function that, given S a set of integer and I an integer, return all the subsets of S that sum to I
is there such a function somewhere in clojure-contrib or in another library ?
if no, could anyone please give me some hints to write it the clojure way?
Isn't this the subset sum problem, a classic NP-complete problem?
In which case, I'd just generate every possible distinct subset of S, and see which subsets sums to I.
I think it is the subset sum problem, as #MrBones suggests. Here's a brute force attempt using https://github.com/clojure/math.combinatorics (lein: [org.clojure/math.combinatorics "0.0.7"]):
(require '[clojure.math.combinatorics :as c])
(defn subset-sum [s n]
"Return all the subsets of s that sum to n."
(->> (c/subsets s)
(filter #(pos? (count %))) ; ignore empty set since (+) == 0
(filter #(= n (apply + %)))))
(def s #{1 2 45 -3 0 14 25 3 7 15})
(subset-sum s 13)
; ((1 -3 15) (2 -3 14) (0 1 -3 15) (0 2 -3 14) (1 2 3 7) (0 1 2 3 7))
(subset-sum s 0)
; ((0) (-3 3) (0 -3 3) (1 2 -3) (0 1 2 -3))
These "subsets" are just lists. Could convert back to sets, but I didn't bother.
You can generate the subsets of a set like this:
(defn subsets [s]
(if (seq s)
(let [f (first s), srs (subsets (disj s f))]
(concat srs (map #(conj % f) srs)))
(list #{})))
The idea is to choose an element from the set s: the first, f, will do. Then we recursively find the subsets of everything else, srs. srs comprises all the subsets without f. By adding f to each of them, we get all the subsets with f. And together, that's the lot. Finally, if we can't choose an element because there aren't any, the only subset is the empty one.
All that remains to do is to filter out from all the subsets the ones that sum to n. A function to test this is
(fn [s] (= n (reduce + s)))
It is not worth naming.
Putting this together, the function we want is
(defn subsets-summing-to [s n]
(filter
(fn [xs] (= n (reduce + xs)))
(subsets s)))
Notes
Since the answer is a sequence of sets, we can make it lazier by changing concat into lazy-cat. map is lazy anyway.
We may appear to be generating a lot of sets, but remember that they share storage: the space cost of keeping another set differing by a single element is (almost) constant.
The empty set sums to zero in Clojure arithmetic.

Solving Project Euler 1

I am trying to solve Project Euler problem in Clojure using recursion. The following is the problem statement:
If we list all the natural numbers below 10 that are multiples of 3 or
5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
Find the sum of all the multiples of 3 or 5 below 1000.
However, the code below seems to give the wrong answer. What am I doing wrong?
(defn m?
[x]
(or (= (rem x 3)) (= (rem x 5))))
(defn sum-m
[limit sum]
(if (= limit 0)
sum
(recur (dec limit)
(if (m? limit)
(+ sum limit)
sum))))
(sum-m (dec 1000) 0)
You didn't say what erroneous answer it was giving, but I believe the problem is in m?:
(or (= 0 (rem x 3)) (= 0 (rem x 5)))
m? change to
(defn m? [x]
(or (zero? (rem x 3))(zero? (rem x 5))))
I think you wanted the function m? to check if a number is multiple of 3 or 5. But it does not do that. You should check if any of (rem x 3) or (rem x 5) are zero.
It's an interesting exercise to solve this for very large numbers. For example, find the sum of all the natural numbers below 1 billion that are multiples of 3 or 5. Your solution is linear in time, but you can try for a solution that is faster. This is not part of your original question; just an interesting addition to it.