jon.com.org.net Badass, like REO Speedwagon or somethin'.

2Aug/100

99 Clojure Problems (50)

Fortunately for those of you following along at home, Wikipedia has a great article on Huffman Coding. The theory is simple, just keep taking the bottom two smallest frequency numbers and smoosh them into a new node with their frequency summed together until you're left with only two elements. Then split each node of the tree into 0 and 1, and just keep appending on down the tree.

; P50 (***) Huffman code.
(comment "First of all, consult a good book on discrete mathematics or algorithms for a detailed description of Huffman codes!")

(comment "We suppose a set of symbols with their frequencies, given as a list of fr(S,F) terms. Example: [fr(a,45),fr(b,13),fr(c,12),fr(d,16),fr(e,9),fr(f,5)]. Our objective is to construct a list hc(S,C) terms, where C is the Huffman code word for the symbol S. In our example, the result could be Hs = [hc(a,'0'), hc(b,'101'), hc(c,'100'), hc(d,'111'), hc(e,'1101'), hc(f,'1100')] [hc(a,'01'),...etc.]. The task shall be performed by the predicate huffman/2 defined as follows:")  

(defn huffman-tree [fs]
  (let [fs-sorted (sort-by #(nth % 1) fs)]
    (loop [[a b & tail] fs-sorted]
        (if (not (empty? tail))
          (recur (sort-by #(nth % 1) (conj tail (list (concat (list (nth a 0)) (list (nth b 0))) (+ (nth a 1) (nth b 1))))))
          (concat (list (nth a 0)) (list (nth b 0)))))))
(defn digit-map [a b c]
  (if (seq? a)
    (map digit-map a (list "0" "1") (list (str c b) (str c b)))
    (list a (str c b))))

(defn dft [ls]
  (mapcat (fn [e]
            (if (list? e)
              e
              (dft e)
              )) ls))
(defn process [ls]
  (loop [[a b & tail] ls
         out '()]
    (if (empty? tail)
      (sort-by (fn [[a b]] a) (conj out (list a b)))
      (recur tail (conj out (list a b))))))

(defn huffman [fs]
  (let [tree (huffman-tree fs)]
    (process (dft (map
      digit-map
      tree
      (list "0" "1")
      (list "" ""))))))

There's probably a lot of room to optimize and shortcut a lot of what I did. This was a three star problem, though, so I'm sure that most of the optimization is going to be in the flattening code.

Tagged as: clojure, programming No Comments
30Jul/101

99 Clojure Problems (48)

Yesterday I was moping that I wasn't able to do problem 48. Luckily for me, commenter Mark was able to show me that apply can be used to take each item of a list as separate parameters to that function. (Instead of taking the whole list.)

This gives me the following:

; P48 (**) Truth tables for logical expressions (3).
(comment "Generalize problem P47 in such a way that the logical expression may contain any number of logical variables. Define table/2 in a way that table(List,Expr) prints the truth table for the expression Expr, which contains the logical variables enumerated in List.")
(defn truth-table [n]
  (loop [nleft n
         combos (list (list ))]
    (if (zero? nleft)
      combos
      (recur (dec nleft) (concat (map #(conj % true) combos) (map #(conj % false) combos))))))

(defn table2 [nparams func]
  (let [tfls (truth-table nparams)]
    (doseq [ls tfls]
      (do
        (doseq [t ls] (print t "\t"))
        (println (apply func ls))))))

So, while it still doesn't use the operator syntax, it does take any number of arguments as long as you tell it how many arguments there are. I'm happy with this solution, because I learned something doing it.

Tagged as: clojure, programming 1 Comment
29Jul/104

99 Clojure Problems (46, 49)

I had some difficulty with the "Logic and Codes" section, since neither Prolog or Scala are really all that lisp like.

Here's my answer for 46. Many thanks to Brian Carper for responding to my StackOverflow question. It really helped me to reformulate this question with more of a clojure style than a Scala or Prolog style.

; P46 (**) Truth tables for logical expressions.
(comment "Define predicates and/2, or/2, nand/2, nor/2, xor/2, impl/2 and equ/2 (for logical equivalence) which succeed or fail according to the result of their respective operations; e.g. and(A,B) will succeed, if and only if both A and B succeed. Note that A and B can be Prolog goals (not only the constants true and fail).")
(comment "A logical expression in two variables can then be written in prefix notation, as in the following example: and(or(A,B),nand(A,B)).")

(defn not_ [a] (if a false true))
(defn and_ [a b] (if a (if b true false) false))
(defn or_ [a b] (if a true (if b true false)))
(defn nand_ [a b] (not_ (and_ a b)))
(defn nor_ [a b] (not_ (or_ a b)))
(defn xor_ [a b] (or_ (and_ a (not_ b)) (and_ (not_ a) b)))
(defn impl_ [a b] (or_ (not_ a) (and_ a b)))
(defn equ_ [a b] (not_ (xor_ a b)))

(comment "Now, write a predicate table/3 which prints the truth table of a given logical expression in two variables.")
(defn table [f]
  (doseq [a '(true false)
        b '(true false)]
     (println a "\t" b "\t" (f a b))
    ))

I skipped number 47 (turning the functions into operators) because clojure doesn't really deal with infix notation at all. It seems really foreign to me to try to write (a and b). I can see doing this in ruby

a.and(b)

or f#

a |> and b

but not clojure.

I skipped number 48, because I couldn't figure out how to count the parameter "arity" of the function being passed in. Even with the number of parameters being passed in, I wasn't able to figure out how to pass a list as the parameters to a function. (Basically converting (func '(a b c)) to (func a b c) with a simple bit of code.

Here's my answer to number 49, which was mercifully easy after messing with 48 for a little while.

; P49 (**) Gray code.
(comment "An n-bit Gray code is a sequence of n-bit strings constructed according to certain rules. For example,")
(comment "n = 1: C(1) = ['0','1']. ")
(comment "n = 2: C(2) = ['00','01','11','10'].")
(comment "n = 3: C(3) = ['000','001','011','010','110','111','101','100'].")

(defn gray [n]
  (loop [nleft n
         combos (list (list ))]
    (if (zero? nleft)
      (map #(apply str %) combos)
      (recur (dec nleft) (concat (map #(conj %1 1) combos) (map #(conj %1 0) combos)) ))))

I did not do result caching. I couldn't figure out where to start with it, and this code is so devilishly simple that I can't figure out where I would store anything for future use.

Tagged as: clojure, programming 4 Comments
28Jul/101

Follow These Instructions Exactly as they Are Written

My wife found this on ONTD, and I think I tracked it down to Creepy Pasta or a Tumblr.

Somewhere in West Philadelphia, you will find an old basketball court with a single ball lying in the middle. Pick it up and start shooting hoops. After a while, a small group of hooligans will approach you and challenge you to a fight, which you must accept.

After the fight, you must go home and relay the events to your mother. She will then inform you that you have an aunt and uncle living in one of the districts of Los Angeles, and out of fear, she will send you to live there for an indefinite period of time.

With your bags packed, go to the street corner, and whistle for a cab. The cab that will pull up will bear the word FRESH on the license plate, and upon closer inspection, novelty fuzzy dice will hang in the mirror. Although you will suddenly realize that cabs like these are extremely hard to find, do not bear any thought to it. At this point you MUST point out in front of the car and say ‘Yo homes to Bel Air’. You will stop in front of a mansion, and it will be sometime between 7 and 8 o’clock, even though it will feel like you’ve been traveling mere seconds. Get your luggage out and say ‘Yo homes, smell ya later!’, but do NOT turn back to face the cabby. Walk up to the door, look over your shoulder once, and then knock on the door three times.

If you follow these instructions, your life will get flip-turned upside-down.

Spooky stuff, eh?

Tagged as: silly 1 Comment
19Jul/100

99 Clojure Problems (39-41)

Only three problems this update, since we're coming to the end of the arithmetic section of the problems. The Goldbach Conjecture is fun to say, and fairly easy to solve. Unfortunately, I think I misunderstood the "secondary" problem of P41. I returned all even numbers that can be expressed as the sum of two primes that are over 50. The solution in the scala version of the problems seems to find the first possible pair of primes that equal a prime, and then find which "initial" pair of primes is over 50.

(defn prime? [n prime-cache]
  (= 0 (count (filter zero? (map (fn [e] (mod n e)) prime-cache)))))

(defn primes-upto [n]
  (loop [possible 3
         primes '()]
	  (cond
	    (< n 2) primes
	    (= n 2) '(2)
	    (>= possible n) (reverse primes)
	    (prime? possible primes) (recur (+ 2 possible) (conj primes possible))
	    :else (recur (+ 2 possible) primes))))

; P39 (*) A list of prime numbers.
(comment "Given a range of integers by its lower and upper limit, construct a list of all prime numbers in that range.")
(defn prime-list [start end]
  (drop-while (fn [e] (< e start)) (primes-upto end)))

; P40 (**) Goldbach's conjecture.
(comment "Goldbach's conjecture says that every positive even number greater than 2 is the sum of two prime numbers. Example: 28 = 5 + 23. It is one of the most famous facts in number theory that has not been proved to be correct in the general case. It has been numerically confirmed up to very large numbers (much larger than we can go with our Prolog system). Write a predicate to find the two prime numbers that sum up to a given even integer.")
(defn goldbach [n]
  (let [primes (primes-upto n)]
    (loop [[head & tail] primes]
    (let [match (first (filter #(= % (- n head)) primes))]
      (cond
        (nil? head) nil
        (nil? match) (recur tail)
        :else (list head match)
      )))))

(defn limited-goldbach [n limit]
  (let [primes (primes-upto n)]
    (loop [[head & tail] primes]
    (let [match (first (filter #(= % (- n head)) primes))]
      (cond
        (nil? head) nil
        (> head (/ n 2)) nil
        (nil? match) (recur tail)
        (< head limit) (recur tail)
        :else (list head match)
      )))))

(comment "In most cases, if an even number is written as the sum of two prime numbers, one of them is very small. Very rarely, the primes are both bigger than say 50. Try to find out how many such cases there are in the range 2..3000.")
(defn print-goldbach-list-limited [a end limit]
  (loop [start a]
    (cond
      (> start end) nil
      (< start limit) (recur (inc start))
      (zero? (rem start 2)) (do
                              (let [gbp (limited-goldbach start limit)]
                                (if (nil? gbp) nil
                                    (let [[a b] gbp] (println start "=" a "+" b ))))
                              (recur (inc start)))
      :else (recur (inc start)))))

; P41 (**) A list of Goldbach compositions.
(comment "Given a range of integers by its lower and upper limit, print a list of all even numbers and their Goldbach composition.")
(defn print-goldbach-list [a end]
  (print-goldbach-list-limited a end 0))

So yeah, some extra work... oh well! I learned about the "do" function today, which allows me to do something in addition to "recur".

Tagged as: clojure, programming No Comments
15Jul/101

99 Clojure Problems (35-38)

Once again, a lot of the familiar faces from Project Euler show up to give us a hand. And then, in problem 36, we actually go back and use that list encoding work we did earlier in problem 10. Most of my learning moments this set were in problem 38, where I struggled a little to abstract the timing harness enough. Defining my own operator was cool too, but not as fancy looking as scala, ruby, or python.

; P35 (**) Determine the prime factors of a given positive integer.
(comment "Construct a flat list containing the prime factors in ascending order.")
(defn prime-factors [n]
  (loop [number n
         curr 2
         output '()]
    (cond
      (= 1 number) (reverse output)
      (evenly-divisible number curr) (recur (/ number curr) curr (conj output curr))
      :else (recur number (inc curr) output))))

; P36 (**) Determine the prime factors of a given positive integer (2).
(comment "Construct a list containing the prime factors and their multiplicity.")
(defn prime-factors-mult [n] (encode (prime-factors n)))

; stolen from rosettacode.org/wiki/Exponentiation_operator#Clojure
(defn ** [x n] (if (zero? n) 1 (reduce * (repeat n x))))

; P37 (**) Calculate Euler's totient function phi(m) (improved).
(comment "See problem P34 for the definition of Euler's totient function. If the list of the prime factors of a number m is known in the form of problem P36 then the function phi(m>) can be efficiently calculated as follows: Let [[p1, m1], [p2, m2], [p3, m3], ...] be the list of prime factors (and their multiplicities) of a given number m. Then phi(m) can be calculated with the following formula:")
(defn totient2 [n]
  (let [pfs (prime-factors-mult n)]
    (reduce * (map (fn [[m p]] (* (dec p) (** p (dec m)))) pfs))))

; P38 (*) Compare the two methods of calculating Euler's totient function.
(comment "Use the solutions of problems P34 and P37 to compare the algorithms. Try to calculate phi(10090) as an example.")
(defn timer [which function n]
  (let [start (System/currentTimeMillis)
        answer (function n)
        end (- (System/currentTimeMillis) start)]
  (println which "{" answer "} takes" end "ms")))

(defn benchmark [n]
  (doseq [i (range 1 11)]
	  (println "Run" i)
	  (timer "p34" totient n)
	  (timer "p37" totient2 n)
	  (println "------\n")))

(benchmark 10090)
Tagged as: clojure, programming 1 Comment
13Jul/104

99 Clojure Problems (31-34)

I wanted to complete problems 27 and 28, but it just wasn't working out. I'll come back to them later, but for now, here's numbers 31 through 34.

Since I'm working through Project Euler as a sort of algorithmic kata to stretch my legs in new languages, these prime based problems were a snap.

; A utility method that helps keep things readable.
(defn evenly-divisible [n d] (zero? (mod n d)))

; P31 (**) Determine whether a given integer number is prime.
(defn prime? [n]
  (loop 1
    (if (> (* c c) n)
      true
      (if (evenly-divisible n c)
        false
        (recur (inc c))))))

; P32 (**) Determine the greatest common divisor of two positive integer numbers.
(comment "Use Euclid's algorithm.")
; my first attempt...
(defn gcd_a [n k]
  (loop [a (if (< n k) n k)
         b (if (< n k) k n)
         c 2
         o 1]
    (cond
      (< a c) o
      (and (evenly-divisible a c) (evenly-divisible b c)) (recur (/ a c) (/ b c) c (* o c))
      :else (recur a b (inc c) o))))

(comment "using euclid's algorithm, which I thought I knew, but I was apparently misremembering")
(defn gcd [m n]
  (if (zero? n)
    m
    (recur n (mod m n))))

; P33 (*) Determine whether two positive integer numbers are coprime.
(comment "Two numbers are coprime if their greatest common divisor equals 1.")
(defn coprime? [n k] (= 1 (gcd n k)))

; P34 (**) Calculate Euler's totient function phi(m).
(comment "Euler's so-called totient function phi(m) is defined as the number of positive integers r (1 <= r <= m) that are coprime to m.")
(defn totient [n]
  (count
    (filter
      (fn [e] (coprime? e n))
      (range 1 n))))

Not only was Project Euler helpful, the fact that these solutions so nicely build upon each other helped speed these through. I think I made the right choice skipping 27-28. The forward momentum has rekindled my interest in learning more about clojure.

Tagged as: clojure, programming 4 Comments
12Jul/101

Ruby Koans

Ben sent me a link to Ruby Koans today. These "Koans" are a kind of learn-by-doing approach to learning ruby.

Each problem is set up as part of a test-driven framework that requires you to make the tests pass by filling in the answers.

An example:

def test_combining_hashes
  hash = { "jim" => 53, "amy" => 20, "dan" => 23 }
  new_hash = hash.merge({ "jim" => 54, "jenny" => 26 })

  assert_not_equal hash, new_hash

  expected = { "jim" => __, "amy" => 20, "dan" => 23, "jenny" => __ }
  assert_equal expected, new_hash
end

This was a great way to spend a couple of hours and learn some of the deeper secrets of the ruby language.

Oh, and if you have a problem running the problems in 1.9.1, specifically the following:

C:\ruby_koans>rake
(in C:/ruby_koans)
cd koans
C:/Ruby19/bin/ruby.exe path_to_enlightenment.rb
C:/ruby_koans/koans/edgecase.rb:33:in `<class:Sensei>': uninitialized constant T
est::Unit::AssertionFailedError (NameError)
        from C:/ruby_koans/koans/edgecase.rb:30:in `<module:EdgeCase>'
        from C:/ruby_koans/koans/edgecase.rb:29:in `<top (required)>'
        from C:/ruby_koans/koans/about_asserts.rb:4:in `require'
        from C:/ruby_koans/koans/about_asserts.rb:4:in `<top (required)>'
        from path_to_enlightenment.rb:3:in `require'
        from path_to_enlightenment.rb:3:in `<main>'
rake aborted!
Command failed with status (1): [C:/Ruby19/bin/ruby.exe path_to_enlightenme...]

(See full trace by running task with --trace)

You need to run:

gem install test-unit

The test-unit gem is no longer included in the Ruby installer.

Tagged as: koans, programming, ruby 1 Comment
9Jul/101

Euler Problem 17 in Ruby

After hearing about Ben's motivation trouble with problem 17, I realized that I only had fun on that problem because I saw a rather fun algorithm. Since I'm rather proud of it, I'm going to show off the code here.

ones = ["", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"]
tens = ["", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]
hundred = "hundred"
and_ = "and"
thousand = "thousand"

sum = ""
1.upto(1000) do |i|
  curr = i
  out = ""
  if (curr > 999) then
    out += ones[curr/1000] + thousand
    curr = curr%1000
  end
  if (curr > 99) then
    out += ones[curr/100] + hundred
    curr = curr%100
    out += and_ if curr != 0
  end
  if (curr >= 20) then
    out += tens[curr/10]
    curr = curr%10
    out += ones[curr]
  else
    out += ones[curr]
  end
  sum += out
end
puts sum.length

# Over 50 trials:
# Mean:	17.3689 ms
# Median: 16.5885 ms

I'm particularly proud of this code because I don't have to convert the numbers into an array, and it's blazing fast, even in ruby.

Tagged as: programming, projecteuler 1 Comment
6Jul/101

99 Clojure Problems (23-26)

This is the first set that I'm not a 100% proud of. After being stuck on P26 for days, I just stole the code from clojure.contrib.combinatorics. At least I learned a few things! (defn-) creates a generator! Now I can create infinite sequences! Also, there is a better example of the #(%) syntax. The (cond ...) syntax also looks useful, as now I can replicate JSP's choose/when/otherwise.

; P23 (**) Extract a given number of randomly selected elements from a list.
(defn rnd_select [n input]
  (if (> n 0)
    (loop 1 (remove_at (rand-int (count input)) input)]
      (if (> c 0)
        (recur (dec c) (cons x output) (remove_at (rand-int (count r)) r))
        output)) nil)
  )

; P24 (*) Lotto: Draw N different random numbers from the set 1..M.
; The selected numbers shall be put into a result list.
(defn lotto [n m] (rnd_select n (s99_range 1 m)))

; P25 (*) Generate a random permutation of the elements of a list.
(defn randomPermute [input]
  (loop 1 (remove_at (rand-int (count input)) input)]
      (if (> c 1)
        (recur (dec c) (cons x output) (remove_at (rand-int (count r)) r))
        (cons x output))))

; P26 (**) Generate the combinations of K distinct objects chosen from the N elements of a list.
(comment "In how many ways can a committee of 3 be chosen from a group of 12 people? We all know that there are C(12,3) = 220 possibilities (C(N,K) denotes the well-known binomial coefficient). For pure mathematicians, this result may be great. But we want to really generate all the possibilities.")
(defn- index-combinations
  [n cnt]
  (lazy-seq
   (let 1 (+ j cnt (- (inc n)))))),
   iter-comb
   (fn iter-comb 1
     (if (> j n) nil
         (let 1
     (if (< (c j) j) 1
         (loop 1
           (if (= j 1) 1
         (recur (assoc c (dec j) (dec (c j))) (dec j)))))))),
   step
   (fn step 1
     (cons (rseq (subvec c 1 (inc n)))
     (lazy-seq (let [next-step (iter-comb c j)]
           (when next-step (step (next-step 0) (next-step 1)))))))]
     (step c 1))))

(defn combinations
  "All the unique ways of taking n different elements from items"
  [n items]
  (let [v-items (vec (reverse items))]
    (if (zero? n) (list ())
      (let [cnt (count items)]
       (cond
         (> n cnt) nil
         (= n cnt) (list (seq items))
         :else (map #(map v-items %) (index-combinations n cnt)))))))
Tagged as: clojure, programming 1 Comment
   Older Entries »

Blogroll

  • JohnnyCoder
  • Mostly Blather
  • Piggington's Econo-Almanac
  • The Jackie Bristow Memorial 5k Run
  • [tone·milazzo]

Cool Sites

  • Ruby Koans
  • Ruby Quiz
  • S-99: Ninety-Nine Scala Problems

Recent Posts

  • 99 Clojure Problems (50)
  • 99 Clojure Problems (48)
  • 99 Clojure Problems (46, 49)
  • Follow These Instructions Exactly as they Are Written
  • 99 Clojure Problems (39-41)

Categories

  • clojure (13)
  • programming (16)
  • rpg (3)
  • ruby (3)
  • Uncategorized (2)

Archives

  • August 2010 (1)
  • July 2010 (9)
  • June 2010 (7)
  • April 2010 (1)
  • January 2010 (2)

jon.com.org.net is using WP-Gravatar

gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.