This post of mine discusses Thomson's paradox, and simulates it in Clojure.
The state function returns the state of the lamp at time = t.
(defn thomsons-lamp []
(iterate (fn [[onoff dur]]
[(not onoff) (/ dur 2)])
[true 1]))
(defn state [t]
(let [t-vals (map second (thomsons-lamp))]
(loop [i 1]
(if (<= t (apply + (take i t-vals)))
((comp first last) (take i (thomsons-lamp)))
(recur (inc i))))))
How do I define a cleaner state function (preferably without loop/recur)?
The only sins here are
Unnecessary quadratic complexity in state
Evidence of floating point usage and error in your blog post. The code as written should be using ratios -- (state 2) should not terminate...
Reduce/reduced would be a good candidate for your state function.
(defn thomsons-lamp []
(map vector (iterate not true) (iterate #(* 1/2 %) 1)))
(defn state [t]
(reduce (fn [[s1 t1] [s2 t2]]
(if (>= t1 t) (reduced s1) [s2 (+ t1 t2)]))
(thomsons-lamp)))
A one-line solution in Clojure
In Clojure, though not in ClojureScript, we can express the state function as a series of pure function applications:
(defn state [t]
(-> t rationalize / biginteger .bitLength odd?))
or, without using the threading macro
(defn state [t]
(odd? (.bitLength (biginteger (/ (rationalize t))))))
Let's test it:
(map (juxt identity state) [1 0.7 0.5 0.4 0.3 0.2])
; ([1 true] [0.7 true] [0.5 false] [0.4 false] [0.3 false] [0.2 true])
Taking it step by step:
(defn state [t]
(-> t
rationalize ; convert to a ratio to avoid losing precision using floating point
/ ; take the reciprocal
biginteger ; round down (if need be) to a java.math.BigInteger
.bitLength ; take its length in bits (a method, not a Clojure function)
odd? ; ask whether odd
))
How does it work?
Instead of testing where the given number t fits in the series of toggle-points
1 1/2 1/4 1/8 ...
we test where 1/t (that's (/ t) in Clojure) fits in the series of inverted toggle-points
1 2 4 8 ...
which, in binary, is
1 10 100 1000 ...
which are the smallest numbers with
1 2 3 4 ...
binary digits.
Applying BigInteger/bitLength tells us how many binary digits 1/t has - rounding down has no effect. This is the number of terms of series 1 2 4 8 ... that 1/t reaches. So the answer is whether this number is odd.
Related
I'm trying to estimate the mean distance of all pairs of points in a unit square.
This transducer returns a vector of the distances of x randomly selected pairs of points, but the final step would be to take the mean of all values in that vector. Is there a way to use mean as the final reducing function (or to include it in the composition)?
(defn square [x] (* x x))
(defn mean [x] (/ (reduce + x) (count x)))
(defn xform [iterations]
(comp
(partition-all 4)
(map #(Math/sqrt (+ (square (- (first %) (nth % 1)))
(square (- (nth % 2) (nth % 3))))))
(take iterations)))
(transduce (xform 5) conj (repeatedly #(rand)))
[0.5544757422041136
0.4170515673848907
0.7457675423415904
0.5560901974277822
0.6053573945754688]
(transduce (xform 5) mean (repeatedly #(rand)))
Execution error (ArityException) at test.core/eval19667 (form-init9118116578029918666.clj:562).
Wrong number of args (0) passed to: test.core/mean
If you implement your mean function differently, you won't have to collect all the values before computing the mean. Here is how you can implement it, based on this Java code:
(defn mean
([] [0 1]) ;; <-- Construct an empty accumulator
([[mu n]] mu) ;; <-- Get the mean (final step)
([[mu n] x] ;; <-- Accumulate a value to the mean
[(+ mu (/ (- x mu) n)) (inc n)]))
And you use it like this:
(transduce identity mean [1 2 3 4])
;; => 5/2
or like this:
(transduce (xform 5) mean (repeatedly #(rand)))
;; => 0.582883812837961
From the docs of transduce:
If init is not supplied, (f) will be called to produce it. f should be
a reducing step function that accepts both 1 and 2 arguments, if it
accepts only 2 you can add the arity-1 with 'completing'.
To disect this:
Your function needs 0-arity to produce an initial value -- so conj
is fine (it produces an empty vector).
You need to provide a 2-arity function to do the actual redudcing
-- again conj is fine here
You need to provide a 1-arity function to finalize - here you want
your mean.
So as the docs suggest, you can use completing to just provide that:
(transduce (xform 5) (completing conj mean) (repeatedly #(rand)))
; → 0.4723186070904141
If you look at the source of completing you will see how it produces
all of this:
(defn completing
"Takes a reducing function f of 2 args and returns a fn suitable for
transduce by adding an arity-1 signature that calls cf (default -
identity) on the result argument."
{:added "1.7"}
([f] (completing f identity))
([f cf]
(fn
([] (f))
([x] (cf x))
([x y] (f x y)))))
I have a little programming issue that I'm trying to resolve in Clojure.
Say, I have a list with Integer values (they also include zeros). These values have a sum, which I want to decrease by a certain value. To get to this lower sum, I want to decrease the values in the list by ratio.
Say, I have the following list: [0, 10, 30, 40, 20, 0]. The sum is 100, and I want to decrease the sum to 90. I want to decrease the values by ratio, so the new list will be [0, 9, 27, 36, 18, 0].
However, this gets problematic when the numbers turn into fractions. When you round numbers (either with round, floor or ceil), you can end up with a sum that's off by 1 or 2. I can't seem to find an elegant solution. Everything I get consists of going through all the values once, and then going back to repair the offset. Any ideas?
Edit
To clarify the behaviour I want to see, the way it rounds doesn't really matter to me, as long as the sum is correct and the ratios of the numbers are approximately the same. I don't care care whether the total error is the smallest or that most are rounded down.
Additional requirements are that numbers are only allowed to stay equal or get lower, numbers should be >= 0, and the resulting list of numbers should be integers.
We can specify the function's requirements with clojure.spec. If we want the function to support integers w/arbitrary precision, sequences that sum to zero, empty sequences, etc., we could write this function spec:
(s/def ::natural-integer (s/and integer? (comp not neg?)))
(s/fdef dec-sum-int
:args (s/and (s/cat :new-sum ::natural-integer
:nums (s/coll-of ::natural-integer))
#(<= (:new-sum %) (apply +' (:nums %))))
:ret (s/coll-of ::natural-integer)
:fn (fn [{:keys [args ret]}]
(and (= (count (:nums args)) (count ret))
;; each output <= corresponding input
(every? true? (map <= ret (:nums args)))
(or (empty? ret)
(= (:new-sum args) (apply + ret))))))
Then st/check the original answer below to see failing examples, or see example invocations with s/exercise-fn.
Here's a version that satisfies the spec for your updated requirements. Most of the complexity is to ensure each output <= input when adjusting for rounding error:
(defn dec-sum-int [new-sum nums]
(let [sum (apply +' nums)
ratio (if (zero? sum) 1 (/ new-sum sum))
nums' (map #(bigint (*' % ratio)) nums)
err (- new-sum (apply + nums'))]
(loop [nums nums
nums' nums'
out []
err err]
(cond
(zero? err)
(into out nums')
(seq nums')
(let [[num & more] nums
[num' & more'] nums']
(if (pos? num)
(let [num'' (min num (+ num' err))]
(recur more more'
(conj out num'')
(- err (- num'' num'))))
(recur more more' (conj out num') err)))
:else out))))
(st/summarize-results (st/check `dec-sum-int))
{:sym playground.so/dec-sum-int}
=> {:total 1, :check-passed 1}
Original Answer
Here's a function to multiply each number in a collection by a ratio to reach some desired sum:
(defn adjust-sum [new-sum nums]
(let [sum (apply + nums)]
(map #(* % (/ new-sum sum))
nums)))
(adjust-sum 90 [0 10 30 40 20 0])
=> (0N 9N 27N 36N 18N 0N)
(map int *1)
=> (0 9 27 36 18 0)
For your example the results naturally come out as big integers. This is the only given example, but this problem lends itself well to property-based, generative testing. We can define properties that should hold for all examples and use test.check to test the function against many random examples we may not have imagined:
(tc/quick-check 10000
(prop/for-all [new-sum gen/int
nums (->> (gen/vector gen/int)
;; current approach fails for inputs that sum to zero
(gen/such-that #(not (zero? (apply + %)))))]
(= new-sum (apply + (adjust-sum new-sum nums)))))
=> {:result true, :num-tests 10000, :seed 1552170880184}
See updates above for handling examples with rounding error, or prior edits for handling negative numbers.
I don't think there is way to solve it without going through the list a second time to fix the rounding. Here is one solution using Largest Remainder Method:
(defn adj-seq
[input ratio rounding]
(let [;;
;; function to apply ratio to a number
;;
mul-ratio (partial * ratio)
;;
;; function to apply ratio and rounding to a number
;;
mul-ratio-r (comp rounding mul-ratio)
;;
;; sort oirignal input with largest remainder first
;; then applies ratio and rounding to each number
;;
rounded-list (->> input
(sort-by #(- (mul-ratio-r %)
(mul-ratio %)))
(map mul-ratio-r))
;;
;; sum of original numbers
;;
sum-input (reduce + input)
;;
;; calculate the delta between the expected sum and sum of all rounded numbers
;;
delta (- (mul-ratio-r sum-input) (reduce + rounded-list))]
;;
;; distribute delta to the rounded numbers in largest remainder order
;;
(->> rounded-list
(reductions (fn [[remain _] e]
;; increment number by 1 if remaining delta is >1
(if (pos? remain)
[(dec remain) (inc e)]
;; otherwise returns the rounded number as is
[0 e]))
;; delta is the initial value to feed to the reducing function
[delta])
;;
;; ignore the first output from the reducing function - which is the original delta
;;
rest
;;
;; get the adjusted number: ratio + rounding + delta-adj
;;
(map last))))
And a sample run:
(def input [0 10 30 40 20 0])
(def ratio 0.83)
(def rounding int)
(reduce + input)
;; => 100
(* ratio *1)
;; => 83.0
(adj-seq input ratio rounding)
;; => (25 17 8 33 0 0)
(reduce + *1)
;; => 83
Is this what you need?
(defn scale-vector
"Given `s`, a sequence of numbers, and `t`, a target value for the sum of
the sequence, return a sequence like `s` but with each number scaled
appropriately."
[s t]
(let [ratio (/ (reduce + (filter number? s)) t)]
(map #(if (number? %) (/ % ratio) %) s)))
(scale-vector [10 20 :foo 30 45.3 0 27/3] 21)
=> (1.837270341207349 3.674540682414698 :foo 5.511811023622047 8.32283464566929 0.0 1.6535433070866141)
(reduce + (filter number? (scale-vector [10 20 :foo 30 45.3 0 27/3] 21)))
=> 21.0
What's going on here:
We're assuming that s is a sequence of numbers; but it isn't necessarily an error if some element is not a number. Filtering for numbers allows us to cope gracefully is some elements are non-numeric; I've chosen to preserve non-numeric elements, but you could equally drop them.
I've done nothing special to exclude rational numbers from the output, and I can't see why you'd need to; but if you wanted to do that you could use (map double [1 1/2 22/7]) => (1.0 0.5 3.142857142857143).
But idiomatically, in Clojure, a number is just a number. Any function that accepts numbers should accept numbers. Rational numbers - what you are referring to as 'fractions' - are just numbers like any other numbers. Don't worry about them.
(defn multiply-xf
[]
(fn [xf]
(let [product (volatile! 1)]
(fn
([] (xf))
([result]
(xf result #product)
(xf result))
([result input]
(let [new-product (* input #product)]
(vreset! product new-product)
(if (zero? new-product)
(do
(println "reduced")
(reduced ...)) <----- ???
result)))))))
This is a simple transducer which multiples numbers. I am wondering what would be the reduced value to allow early termination?
I've tried (transient []) but that means the transducer only works with vectors.
I'm assuming you want this transducer to produce a running product sequence and terminate early if the product reaches zero. Although in the example the reducing function xf is never called in the 2-arity step function, and it's called twice in the completion arity.
(defn multiply-xf
[]
(fn [rf]
(let [product (volatile! 1)]
(fn
([] (rf))
([result] (rf result))
([result input]
(let [new-product (vswap! product * input)]
(if (zero? new-product)
(reduced result)
(rf result new-product))))))))
Notice for early termination, we don't care what result is. That's the responsibility of the reducing function rf a.k.a xf in your example. I also consolidated vreset!/#product with vswap!.
(sequence (multiply-xf) [2 2 2 2 2])
=> (2 4 8 16 32)
It will terminate if the running product reaches zero:
(sequence (multiply-xf) [2 2 0 2 2])
=> (2 4)
We can use transduce to sum the output. Here the reducing function is +, but your transducer doesn't need to know anything about that:
(transduce (multiply-xf) + [2 2 2 2])
=> 30
I've tried (transient []) but that means the transducer only works with vectors.
This transducer also doesn't need to concern itself the type of sequence/collection it's given.
(eduction (multiply-xf) (range 1 10))
=> (1 2 6 24 120 720 5040 40320 362880)
(sequence (multiply-xf) '(2.0 2.0 0.5 2 1/2 2 0.5))
=> (2.0 4.0 2.0 4.0 2.0 4.0 2.0)
(into #{} (multiply-xf) [2.0 2.0 0.5 2 1/2 2 0.5])
=> #{2.0 4.0}
This can be done without transducers as well:
(take-while (complement zero?) (reductions * [2 2 0 2 2]))
=> (2 4)
Consider a query function q that returns, with a delay, some (let say ten) results.
Delay function:
(defn dlay [x]
(do
(Thread/sleep 1500)
x))
Query function:
(defn q [pg]
(lazy-seq
(let [a [0 1 2 3 4 5 6 7 8 9 ]]
(println "q")
(map #(+ (* pg 10) %) (dlay a)))))
Wanted behaviour:
I would like to produce an infinite lazy sequence such that when I take a value only needed computations are evaluated
Wrong but explicative example:
(drop 29 (take 30 (mapcat q (range))))
If I'm not wrong, it needs to evaluate every sequence because it really doesn't now how long the sequences will be.
How would you obtain the correct behaviour?
My attempt to correct this behaviour:
(defn getq [coll n]
(nth
(nth coll (quot n 10))
(mod n 10)))
(defn results-seq []
(let [a (map q (range))]
(map (partial getq a)
(iterate inc 0)))) ; using iterate instead of range, this way i don't have a chunked sequence
But
(drop 43 (take 44 (results-seq)))
still realizes the "unneeded" q sequences.
Now, I verified that a is lazy, iterate and map should produce lazy sequences, so the problem must be with getq. But I can't understand really how it breaks my laziness...perhaps does nth realize things while walking through a sequence? If this would be true, is there a viable alternative in this case or my solution suffers from bad design?
Look at the function below. I want to pass a vector of factors and test if any of the elements in the vector is a factor of x. How do I do that?
(defn multiple?
"Takes a seq of factors, and returns true if x is multiple of any factor."
([x & factors] (for [e m] ))
([x factor] (= 0 (rem x factor))))
You could try using some and map:
(defn multiple? [x & factors]
(some zero? (map #(rem x %) factors)))
Also some returns nil if all tests fail, if you need it to actually return false, you could put a true? in there:
(defn multiple? [x & factors]
(true? (some zero? (map #(rem x %) factors))))
Note that some short-circuits and map is lazy, so multiple? stops as soon as a match is found. e.g. the following code tests against the sequence 1,2,3,4,....
=> (apply multiple? 10 (map inc (range)))
true
Obviously this computation can only terminate if multiple? doesn't test against every number in the sequence.
You can solve it only using some.
=> (defn multiple? [x factors]
(some #(zero? (rem x %)) factors))
#'user/multiple?
=> (= true (multiple? 10 [3 4]))
false
=> (= true (multiple? 10 [3 4 5 6]))
true
some will stop at the first factor.
Try this, using explicit tail recursion:
(defn multiple? [x factors]
"if any of the elements in the vector is a factor of x"
(loop [factors factors]
(cond (empty? factors) false
(zero? (rem x (first factors))) true
:else (recur (rest factors)))))
The advantages of the above solution include: it will stop as soon as it finds if any of the elements in the vector is a factor of x, without iterating over the whole vector; it's efficient and runs in constant space thanks to the use of tail recursion; and it returns directly a boolean result, no need to consider the case of returning nil. Use it like this:
(multiple? 10 [3 4])
=> false
(multiple? 10 [3 4 5 6])
=> true
If you want to obviate the need to explicitly pass a vector (for calling the procedure like this: (multiple? 10 3 4 5 6))) then simply add a & to the parameter list, just like it was in the question.
A more Clojurian way is to write a more general-purpose function: instead of answering true/false question it would return all factors of x. And because sequences are lazy it is almost as efficient if you want to find out if it's empty or not.
(defn factors [x & fs]
(for [f fs :when (zero? (rem x f))] f))
(factors 5 2 3 4)
=> ()
(factors 6 2 3 4)
=> (2 3)
then you can answer your original question by simply using empty?:
(empty? (factors 5 2 3 4))
=> true
(empty? (factors 6 2 3 4))
=> false