I will show you in this article how to increase performance of an algorithm
by a factor of 10^2086, simply by adding two single lines while not
changing any existing code! Yeah, 10^2086 that's a one with 2086 zeros.
Here is the "un-optimized" algorithm, the well known Fibonacci
function:
def fib(n)
if (0..1).include? n
1
else
fib(n-2) + fib(n-1)
end
end
Okay, it's fast enough for small numbers, but how long would it take to
calculate fib of 10000? Well, it would take so much longer than
the life of the whole universe that I can't even describe how much longer
it would take (billions of billions of billions of ... times longer).
To make the algorithm above run 10^2086 times faster than before, we add
the following two lines:
# paste here the algorithm from above
require 'memoize'
memoize 'fib'
Now let's calculate fib(10_000):
p fib(10_000)
And after approx. 3 seconds, the result is displayed on the screen:
For those who are interested about the performance characteristics, it's a
change from O(Fib(n)) to O(n).
Implementing Memoize
As I couldn't find Robert Feldt's memoize module for Ruby anymore,
I decided to write my own. It took me no more than 10 minutes:
$MEMOIZE_CACHE = Hash.new
def memoize(*methods)
methods.each do |meth|
mc = $MEMOIZE_CACHE[meth] = Hash.new
old = method(meth)
new = proc {|*args|
if mc.has_key? args
mc[args]
else
mc[args] = old.call(*args)
end
}
self.class.send(:define_method, meth, new)
end
end