2D Head with a clock as an eyeball.
 Monday, April 28, 2008

...Other Project Euler posts...

Today, my mission is to solve Project Euler Question #2:

Find the sum of all the even-valued terms in the fibonacci sequence which do not exceed four million.

The obvious solution is to use a brute force approach:

public static int Problem2() {
  var fib = 0;
  var sum = 0;

  for (var n = 0; fib < 4000000; n++)
  {
    fib = Fibonacci(n);
    if (fib % 2 == 0)
      sum += fib;
  }

  return sum;
}

private static int Fibonacci(int n) {
  return n < 2 ? 1 : Fibonacci(n - 2) + Fibonacci(n - 1);
}

Lazy evaluation

Slightly more elegant solutions do exist. For starters, F# allows us to use lazy evaluation to create sequences of values. This has the advantage of sequence values only being evaluated when necessary. Robert Pickering's "Foundations of F#" gives us the following example for generating fibonacci numbers using lazy evaluation. In fact, the example here is one of an infinite list.

#light
let fibs = (1, 1) |> Seq.unfold(fun (n0, n1) -> Some(n0, (n1, n0 + n1)))

Initially, a pair of values (named a tuple) 1 and 1 is piped through to the Seq.unfold function. The unfold function allows us to define how we want our list to be generated. It returns a disciminated union type called Option which in this case is called with a tuple, the first value in the tuple being the value applied to the list, the second value is the accumulator.  The accumulator basically allows you to pass some state into next round of calculations. Option types are there own blog post, as they are a totally awesome example of applied discriminated unions.

To put the fibs function into english: fibs takes a tuple of integers (n0, n1), and always returns the first member in the tuple, however when we evaluate the next item in the sequence, the first member of the tuple will be n1 and the second will be n0 + n1. This will go on and on even once we hit the 32bit limit and starting looking at negative integers.

Pattern matching

So how does this help us to solve question two? Using a similar approach as the C# version we could alter the way the list is generated before we summate:

#light

let summate x = x |> Seq.sumByInt (fun n -> n)
let Question2 =
  (1, 1)
  |> Seq.unfold(fun (n0, n1) ->
    match n0 with
      | n0 when n0 % 2 = 0 -> Some(n0, (n1, n0 + n1))
      | n0 when n0 > 4000000 -> None
      | _ -> Some(0, (n1, n0 + n1)))
      |> summate

Here, I'm using simple pattern matching to do two things, make sure any numbers that arent even are mapped to 0, and also to ensure that once n0 exceeeds 4 million, we stop generating values in the list. This is the power of the unfold function at play: the ability to lazily evaluate the members of the list and also to define the condition to terminate the list.

A Mathematical approachFibonacci green - by Mark Strozier

However, this is still a brute force approach, although dressed up a little. Since the fibonacci set is full of patterns and properties surely we can take advantage of one or three? Of course, each 3rd term in the fibonacci set happens to be even. We also have an approximate ratio between two consequetive terms: Phi. Therefore, the ratio between even terms is approximately Phi to the power of 3. Using these properties we should be able to come up with the same answer as our brute force approach: 

#light
let summate x = x |> Seq.sumByFloat (fun n -> n)
let PhiCubed = ((sqrt(5.0) + 1.0) / 2.0) ** 3.0
let Question2 =
  2.0
  |> Seq.unfold (fun x -> match x with
    | x when x < 4000000.0 -> Some(x, Math.Round(x * PhiCubed))
    | _ -> None)
    |> summate

So with a starting point of 2.0 I simply round the result of x * (Phi ^ 3) to yield each value in my list which is then summed. The C# interpretation as follows:

public static double Problem2() {
  return EvenFibsBelowFourMillion().Sum();
}
private static IEnumerable<double> EvenFibsBelowFourMillion() {
  var phiCubed = Math.Pow(((Math.Sqrt(5D) + 1D) / 2D), 3);
  var fib = 2D;
  do {
    yield return fib;
    fib = Math.Round(fib * phiCubed);
  } while (fib < 4000000);
}

In Summary 

C# still outperforms F# ever so slightly on my machine, C# taking an average 0.002 milliseconds, F# taking an average 0.003 milliseconds. So far I feel that F# lives up to the promise of a 'similar performance profile as C#'. I'm starting to appreciate the 'point and shoot' nature of F# syntax. Having said that, the C# solution is equally nice and easy to read. I cant wait to get into some of the meatier questions.


Filed under:  |  |  |  | 
 Sunday, April 06, 2008

One of the languages I have decided to learn this year is F Sharp. F# is a multi paradigm programming language; it is capable of expressing ideas in an imperative, functional and object oriented fashion. It is the result of some very hard work by Microsoft Research and integrates into VS2005 and 2008. F# rounds out the MS language ecosystem quite nicely i think, as it provides a solid platform for mathematical solutions, as well as maintaining the ability to be used to create windows applications of all types.

I decided to get my head around using it by reading Foundations in F# and by undertaking Project Euler, a series of mathematical puzzles. I'm certainly not alone, and to set myself apart from those who have trod before me, I've decided to compare the solutions in F# to possible solutions in to my favourite language: C# 3.0. Since I am no maths expert, this could be a real trainwreck...

Question 1: Find the sum of all the multiples of 3 or 5 below 1000.

Sounds simple enough. We can use mod 3 and mod 5 to filter a list of positive numbers below 1000 and sum the result. One approach might be:

static int Problem1()
{
  return MultiplesOfThreeAndFiveBelow(1000).Sum();
}

static IEnumerable<int> MultiplesOfThreeAndFiveBelow(int n)
{
  for (var i = 0; i < n; i++)
  {
    if (i % 3 == 0 || i % 5 == 0)
    yield return i;
  }
}

OK, so thats a little expensive, I've used a generic list instead of an array, but hey it works. Its main strength is that its readable. So how about a functional approach? 

let solution = Array.init 1000 (fun x -> if x % 3 = 0 || x % 5 = 0 then x else 0 )
               |> Array.fold_left (+) 0

Array.fold_left is a higher order function, since it accepts a function as a parameter. I am passing it the addition operator (a function in its own right) and an accumulator initialized to 0. The first iteration of the fold function will take the value of first element of the sequence and add it to zero. The result is then added to the value of the next element in the sequence to produce a new result and so on. Essentially, it provides the summation required to complete this problem. The downside with this approach is that it naively overestimates the size of the array required, and folding left doesnt immediately lead the reader to think of summation.

I can do better though, F# provides us some constructs for more efficient array initialisations; a comprehension syntax:

let solution = Array.fold1_left (+) [|
                                       for x in 1 .. 999 
                                       when x % 3 = 0 || x % 5 = 0 -> x
                                    |]

While this is readable, some might complain that Array.fold1_left is a cryptic way to summate, and is therefore hard to maintain, so without much effort we can curry it to look like this:

let summate a = Array.fold1_left (+) a
let solution = summate [|
                           for x in 1 .. 999 
                           when x % 3 = 0 || x % 5 = 0 -> x
                       |]

I've split the array initialization over 4 lines for extra readability but in essence its only 1-2 lines of readable code to solve Project Euler Problem 1 using F#.

So, for those of you interested in speed, using the time honored technique of taking the average execution time over 1 million executions, the C# implementation came in at around 10 times faster than the final F# one. The first F# implementation was faster but was still two times slower than C#. The main bottleneck seemed to be the array initialization; using the comprehension syntax is a little pricey. But, who cares about optimization anyway? It was only the difference between fractions of a millisecond anyhow :)


Filed under:  |  |  |  | 
© Copyright 2008 Jim Burger