Solving Project Euler Problems With Ioke

For those of you that have been following Ola Bini’s work on Ioke, the dynamic language for the JVM, I am happy to report that the current release 0.1.1 is usable enough to solve Project Euler problems with. I wanted to learn more about Ioke and the best way to learn a new language is to use it on your own. So, here is some example Ioke code for some of the simpler Project Euler problems.

Problem 1

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.

Brute force version below.

n = 1
sum = 0
while(n < 1000,
      if(n % 3 == 0 or n % 5 == 0, sum += n)
      n++
)
sum println

Or, as a one-liner after a suggestion from Ola:

(1..999) select(n, n % 3 == 0 or n % 5 == 0) fold(+) println

Problem 2

Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be: 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, … Find the sum of all the even-valued terms in the sequence which do not exceed four million.

sum = 0
fibs = [0, 1]
current_fib = 0
while(current_fib < 4000000,
    current_fib = fibs[0] + fibs[1]
    if(current_fib % 2 == 0, sum += current_fib)
    fibs[0] = fibs[1]
    fibs[1] = current_fib
)
sum println

Problem 3

The prime factors of 13195 are 5, 7, 13 and 29. What is the largest prime factor of the number 600851475143?

Using brute force for this one. Faster and more elegant would have been the Rho algorithm.

start = 600851475143
num = start
factor = 2

while(factor * factor <= num,
    if(num % factor == 0,
        factor println
        num = num / factor,
        factor++
    )
)

if(num != 1, num println)

Problem 5

2520 is the smallest number that can be divided by each of the numbers  from 1 to 10 without any remainder. What is the smallest number that is evenly divisible by all of the numbers from 1 to 20?

First, as the numbers 1 to 10 are factors in the numbers 11 to 20 we only need to check divisibility for the the latter. Starting of by setting up methods for greatest common divisor and least common multiple. Brute forcing this by looping over an incremented number will not work in the current version of Ioke (takes a couple of hours). Brute forcing it in Ruby took a couple of seconds.

gcd = method(a, b,
    if(b == 0, a,
        gcd(b, a % b)
    )
)

lcm = method(a, b,
    (a / gcd(a, b)) * b
)

(11..20) inject(number, n, lcm(number, n)) println

Problem 18

Find the maximum total from top to bottom of the triangle below. This solution also works for problem 67 (a much bigger triangle).

By moving from bottom to top, calculating each cell’s maximum sum and replacing the value with it we’ll end up with the total in the first cell in the triangle.

triangle = [
[75],
[95, 64],
[17, 47, 82],
[18, 35, 87, 10],
[20, 04, 82, 47, 65],
[19, 01, 23, 75, 03, 34],
[88, 02, 77, 73, 07, 63, 67],
[99, 65, 04, 28, 06, 16, 70, 92],
[41, 41, 26, 56, 83, 40, 80, 70, 33],
[41, 48, 72, 33, 47, 32, 37, 16, 94, 29],
[53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14],
[70, 11, 33, 28, 77, 73, 17, 78, 39, 68, 17, 57],
[91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27, 29, 48],
[63, 66, 04, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31],
[04, 62, 98, 27, 23, 09, 70, 98, 73, 93, 38, 53, 60, 04, 23],
]

;; We replace cells from the bottom up by finding the max sum for each
;; position in the triangle.

current_row = triangle length - 2

while(current_row > -1,
    pos = 0
    while(pos < triangle[current_row] length,
        triangle[current_row][pos] = triangle[current_row][pos] + \
        ([triangle[current_row + 1][pos], triangle[current_row + 1][pos + 1]] sort)[1]
        pos++
    )

    current_row = current_row - 1
)

triangle[0][0] println

Related Posts:

  • http://olabini.com/blog Ola Bini

    Cool,

    Could you post the brute force version of 5 too? I would be interested in seeing what takes so much time, since the looping is pretty fast. Although – I don’t look too much at performance. =)

  • http://www.peterkrantz.com Pete

    The brute force version of #5:

    DQpuID0gMjANCg0KdW50aWwobiAlIDIwID09IDAgYW5kIA0KICBuICUgMTkgPT0gMCBhbmQgDQogIG4gJSAxOCA9PSAwIGFuZA0KICBuICUgMTcgPT0gMCBhbmQNCiAgbiAlIDE2ID09IDAgYW5kDQogIG4gJSAxNSA9PSAwIGFuZA0KICBuICUgMTQgPT0gMCBhbmQNCiAgbiAlIDEzID09IDAgYW5kDQogIG4gJSAxMiA9PSAwIGFuZA0KICBuICUgMTEgPT0gMCwNCg0KICBuID0gbiArIDIwDQopDQoNCm4gcHJpbnRsbg0K
  • http://www.peterkrantz.com Pete

    Brute force of #5 in Ruby:

    DQpuID0gMjANCg0KZGVmIGlzX2RpdmlzaWJsZShuKQ0KCShuICUgMjAgPT0gMCBhbmQgDQoJbiAlIDE5ID09IDAgYW5kIA0KCW4gJSAxOCA9PSAwIGFuZA0KCW4gJSAxNyA9PSAwIGFuZA0KCW4gJSAxNiA9PSAwIGFuZA0KCW4gJSAxNSA9PSAwIGFuZA0KCW4gJSAxNCA9PSAwIGFuZA0KCW4gJSAxMyA9PSAwIGFuZA0KCW4gJSAxMiA9PSAwIGFuZA0KCW4gJSAxMSA9PSAwKQ0KZW5kDQoNCndoaWxlICFpc19kaXZpc2libGUobikgZG8NCiAgICBuID0gbiArIDIwDQplbmQNCg0KcHJpbnQgbg0K
  • http://olabini.com/blog Ola Bini

    Hey,

    So, I’ve made one change on trunk so that the cost of creating all those numbers aren’t as high. The reason being that originally, every time a number is in code, that will be translated into a internal:createNumber message. This message will run every time a number is encountered, and will as such create all those 11 to 20 numbers every time in the loop. It will also create quite a few copies of 0. This has been changed on trunk. Since numbers and texts are immutable in themselves, the first time it will be cached.

    The large difference I got was when running with –server, though. For long running processes, that is definitely recommend.

    Without my number-fixes, I got:
    232792560
    ruby p5.rb 8,28s user 0,07s system 95% cpu 8,786 total
    232792560
    ioke p5.ik 3224,51s user 54,80s system 96% cpu 56:46,65 total
    232792560
    ioke –server p5.ik 1076,38s user 23,17s system 99% cpu 18:20,49 total

    So as you can see, running with –server cuts the time down to a third. It’s still 20 minutes running time, but much better than without it.

    I’m going to do a new run with the number caching and see what happens.

  • Ka3bzq

    on #3, it might be that i don’t understand the semantics.   If you were to start with 128, wouldn’t the loop divide to 64, then increment factor, missing the other instances of factor 2?