in ,

Blazing fast Fibonacci numbers using Monoids, Hacker News

   fibonacci

This post illustrates a nifty application of Haskell’s standard library to solve a numeric problem.

The

Fibonacci series is a well-known sequence of numbers defined by the following rules:

f ( () = (f) (1) =(1) (1)

f (n) f (n - (1) ) ( (f) n - () (2) )

In fact, that's not only a specification of the Fibonacci numbers: that's also valid Haskell code (with a few gratuitous parentheses to resemble traditional mathematical notation).

However, that solution is inefficient and you can instead use one of two “closed form” solutions for the Fibonacci numbers.

The first solution says that you can compute the Nth fibonacci number using the following formula:

Wikipedia) - Fibonacci number - Closed-form expression

f (n) <a href="#cb1-1">=<span id="cb1-2"> (φ </span>) <span id="cb1-2"> n - <a href="https://en.wikipedia.org/wiki/Fibonacci_number"> ψ </a><a href="#cb1-1"> <span> n) <code> / <span> (φ <code> - <code> ψ) <a href="#cb1-1"> <title><a href="https://en.wikipedia.org/wiki/Fibonacci_number"> (where </a><a href="#cb1-1"> </a> φ <a href="#cb1-1">=</a><a href="#cb1-1"> (</a> 1 (sqrt) ( (5 ) ( / (2) <title><a href="#cb1-1"> </a> ψ <a href="#cb1-1">=</a> ( (1) - sqrt ( 5 )) / (2)

... which is also valid Haskell code.

Unfortunately, the above solution has two issues when translated to a computer algorithm using (IEEE) floating-point numbers

:

These floating point numbers suffer from floating point imprecision:

</p> <p><title><a href="#cb1-1">>>> <span id="cb1-2"> f (<a href="#cb1-1"> </a></span>) </a><a href="#cb1-1"> </a><a href="#cb3-1"> <span id="cb3-2"> </p> <div id="cb1"> <a href="#cb1-1"> </p> <p> () <a href="https://en.wikipedia.org/wiki/Fibonacci_number#Closed-form_expression"> </p> <p> These floating point numbers cannot handle values ​​larger than ~ 1.8 x 22 ³⁰⁸ (the maximum double-precision floating point number) </p> <p> <a href="https://en.wikipedia.org/wiki/Fibonacci_number#Closed-form_expression"> <title> I instead prefer the second closed form solution using matrix arithmetic, which you can find here:

Wikipedia - Fibonacci number - Matrix form I will present a minor variation on that solution which is essentially the same solution. </p> <p> You can compute the Nth Fibonacci number by using the following matrix multiplication expression: </p> <div id="cb1"> <div id="cb1"> - Okay, this is not valid Haskell 😌              ┌ ┐ⁿ ┌ ┐              │0 1│ │0│ f (n)=[1 0] │1 1│ │1│              └ ┘ └ ┘ <a href="#cb1-3"> </p> <p> There are two reasons I prefer this matrix-based closed-form solution: </p> <p> This solution does not require floating point numbers </p> <ul> <p> You can more easily generalize this solution to other arithmetic sequences </p> <li> <title> To expand upon the latter point, if you have an arithmetic sequence of the form: <a href="https://en.wikipedia.org/wiki/Fibonacci_number#Matrix_form"> <code> <span id="cb6-1"> f ( <div id="cb1"> <code> ( a₁ <a href="#cb1-1"> </a><a href="#cb6-1"> (f (1 </a><a href="#cb1-1">) <span>=<a href="#cb1-1"> a₂ <span id="cb1-2"> <a href="#cb6-2"> </p> <p> (f m) <a href="https://en.wikipedia.org/wiki/Fibonacci_number"> (=a) </a><a href="#cb1-1"> f (n) </a><a href="#cb1-1"> </a><a href="#cb1-1"> b₁ x f (n </a></p> <p></a></span> - </a><a href="#cb1-1"> </a><a href="#cb1-2"> 1 </a><a href="#cb1-1">) <span id="cb1-1"> <a href="#cb1-1"> b₂ x f (n </a></span> - </a><a href="#cb1-1"> </a></span> (2) </a><a href="#cb1-1"> (</a><a href="#cb1-1"> ... </a><a href="#cb1-1"> bₘ x f (n - </a><a href="#cb1-1"> m) </a><a href="#cb1-1"> </a><a href="#cb1-3"> </a><a href="#cb1-3"> </p> <p> ... then the closed-form matrix solution is: </p> <p> </a><a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </p> <div id="cb1"> ┌ ┐ⁿ ┌ ┐ <a href="#cb1-1"> </p> <div id="cb7"> <title> │ </p> <div id="cb1"> (0) 1) <code> (0) ... │ │a₁│ <a href="#cb1-1"> </a> │… <code> (0) 1 </p> <div id="cb1"> <a href="#cb1-1"> </p> <div id="cb1"> │ │a₂│ <a href="#cb1-1"> ()) (0) (…) </a><a href="https://en.wikipedia.org/wiki/Fibonacci_number"> (1) │ │… │ </a><a href="#cb1-1"> </a><a href="#cb7-3"> </p> <div id="cb1"> (f (n) <a href="#cb1-1"> [<span>1</span> <span>0</span> … <span>0</span>] │bₘ… b₂ b₁│ │aₘ│ </a><a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </a><a href="#cb7-5"> </a><a href="https://en.wikipedia.org/wiki/Fibonacci_number"> └ ┘ <code> <code> <a href="#cb1-3"> </p> <p> For now, though, we'll stick to Fibonacci numbers, which we can implement efficiently in Haskell in less than 823 lines of code. <a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </p> <p> First, we'll define a quick and dirty 2 × 2 matrix type as a record of four fields: </p> <p> </a><a href="#cb7-5"> </p> <div id="cb1"> <a href="https://en.wikipedia.org/wiki/Fibonacci_number"> (data </a><a href="#cb1-1"> (Matrix2x2) (=(Matrix) </p> <p> { x (:: (Integer) , (x) :: <a href="#cb1-1"> (Integer) </p> <div id="cb1"> <p> (x) (:: (Integer) , (x) :: (Integer) </p> <p> <a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </p> <p> Haskell does have linear algebra packages, but I wanted to keep this solution as dependency-free as possible. </p> <p> Then we'll define matrix multiplication for this type using Haskell's </p> <div id="cb1"> (Semigroup) class, which you can think of as a generic interface for any operator that is associative: <code> <code> <span id="cb7-3"> <a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </a><a href="#cb1-1"> (instance) <code> Semigroup (Matrix2x2) where </p> <p> <a href="#cb1-1"> Matrix </a><a href="#cb1-1"> (l) (l) (l) </a><a href="#cb1-1"> </a></p> <p></code></a></span> Matrix <a href="#cb1-1"> r (r) (r) (r) <code>=</p> <p></code></a> <span> Matrix <span id="cb1-2"> <a href="#cb1-1"> [<span>0</span>,<span>1</span>,<span>1</span>,<span>2</span>,<span>3</span>,<span>5</span>,<span>8</span>,<span>13</span>,<span>21</span>,<span>34</span>,<span>55</span>,<span>89</span>,<span>144</span>,<span>233</span>,<span>377</span>,<span>610</span>,<span>987</span>,<span>1597</span>,<span>2584</span>,<span>4181</span>,<span>6765</span>] </a> {x <a href="https://en.wikipedia.org/wiki/Fibonacci_number"> (l) </a><a href="#cb1-1"> (r) () (l) <code> <a href="#cb1-1"> r 21, x=(l) <span> <a href="#cb1-1"> r (l) (l) <title><a href="#cb1-1"> [<span>0</span>,<span>1</span>,<span>1</span>,<span>2</span>,<span>3</span>,<span>5</span>,<span>8</span>,<span>13</span>,<span>21</span>,<span>34</span>,<span>55</span>,<span>89</span>,<span>144</span>,<span>233</span>,<span>377</span>,<span>610</span>,<span>987</span>,<span>1597</span>,<span>2584</span>,<span>4181</span>,<span>6765</span>] [<span>0</span>,<span>1</span>,<span>1</span>,<span>2</span>,<span>3</span>,<span>5</span>,<span>8</span>,<span>13</span>,<span>21</span>,<span>34</span>,<span>55</span>,<span>89</span>,<span>144</span>,<span>233</span>,<span>377</span>,<span>610</span>,<span>987</span>,<span>1597</span>,<span>2584</span>,<span>4181</span>,<span>6765</span>] , x </a><a href="https://en.wikipedia.org/wiki/Fibonacci_number"> (l) </p> <div id="cb1"> (r) [<span>0</span>,<span>1</span>,<span>1</span>,<span>2</span>,<span>3</span>,<span>5</span>,<span>8</span>,<span>13</span>,<span>21</span>,<span>34</span>,<span>55</span>,<span>89</span>,<span>144</span>,<span>233</span>,<span>377</span>,<span>610</span>,<span>987</span>,<span>1597</span>,<span>2584</span>,<span>4181</span>,<span>6765</span>] (l) (r <a href="#cb1-1"> , x 23 <code>=(l) </p> <p> (r) <a href="#cb1-1"> ( (l) <code> ( <span> () () } <a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </a><a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </p> <p> We'll see why we implement this general interface in (just) a second. <a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </p> <p> The only rule for this </p> <div id="cb1"> Semigroup <meta content="width=device-width, initial-scale=1.0, user-scalable=yes" name="viewport"> interface is that the operator we implement must obey the following associativity law: <a href="#cb9-6"> </p> <div id="cb1"> <div id="cb1"> <title><a href="https://en.wikipedia.org/wiki/Fibonacci_number"> (x </a><a href="#cb1-1"> (y) <code> (z <a href="#cb1-1">=(x) (z) </a><a href="#cb1-1"> </a><a href="#cb1-3"> </p> <p> ... and matrix multiplication is indeed associative. </p> <p> Next, we implement the </p> <div id="cb1"> Monoid <meta content="width=device-width, initial-scale=1.0, user-scalable=yes" name="viewport"> (interface, which is essentially the same as the) (Semigroup) interface except with an additional <code> mempty <a href="#cb1-3"> value. This value is the “identity” of the corresponding <code> Semigroup </p> <div id="cb1"> operation, meaning that the value obeys the following “identity laws”: </p> <div id="cb10"> <code> <a href="#cb10-1"> x </p> <div id="cb1"> <a href="#cb1-1"> </a><a href="#cb1-1"> mempty </a><a href="#cb1-1">=(x) </p> <div id="cb11"> <p> <a href="#cb11-1"> </p> <p> (mempty) </p> <p><title> ( <a href="#cb1-1"> x </p> <p>=<a href="#cb1-1"> x </p> <p> <a href="#cb1-3"> </p> <p> Since our </p> <div id="cb1"> Semigroup operation is matrix multiplication, the corresponding identity value is… the identity matrix (and now you know how it got that name): </p> <p> <a href="#cb9-3"> </a><a href="https://en.wikipedia.org/wiki/Fibonacci_number"> (instance) <title> (Monoid) (Matrix2x2) (where </p> <p> <a href="#cb1-1"> mempty </a><a href="#cb1-1"> <span id="cb1-1">=<a href="#cb1-1"> </a> <span> Matrix <span id="cb1-2"> <a href="#cb1-1"> </a> {x <a href="https://en.wikipedia.org/wiki/Fibonacci_number"> (1) , x (=(0) [<span>0</span>,<span>1</span>,<span>1</span>,<span>2</span>,<span>3</span>,<span>5</span>,<span>8</span>,<span>13</span>,<span>21</span>,<span>34</span>,<span>55</span>,<span>89</span>,<span>144</span>,<span>233</span>,<span>377</span>,<span>610</span>,<span>987</span>,<span>1597</span>,<span>2584</span>,<span>4181</span>,<span>6765</span>] , x </a><a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </a><a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </a><a href="https://en.wikipedia.org/wiki/Fibonacci_number"> , x </a><a href="#cb1-1">=</a><a href="#cb1-1"> (1) <span> () } <a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </a><a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </p> <p> Now, in order to translate this expression to Haskell: <a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </p> <div id="cb1"> <a href="https://en.wikipedia.org/wiki/Fibonacci_number"> ┌ ┐ⁿ ┌ ┐              │0 1│ │0│ f (n)=[1 0] │1 1│ │1│              └ ┘ └ ┘ </a><a href="#cb1-3"> </p> <p> ... we need a fast way to exponentiate our <code> Matrix2x2 <span id="cb1-3"> type. Fortunately, we can do so using the <code> mtimesDefault <span id="cb1-3"> utility from Haskell's standard library, which works for any type that implements <code> (Monoid) : </p> <div id="cb1"> <span id="cb1-2"> - | Repeat a value @ n @ times. <a href="#cb1-1"> <span> </p> <div id="cb14"> <div id="cb1"> - <a href="#cb1-1"> </p> <p> -> mtimesDefault na=a a ... a - using (n-1) times <span> <a href="#cb1-1"> </p> <p> - <a href="#cb1-1"> </p> <p> - Implemented using 'stimes' and 'mempty'. <a href="#cb1-1"> </a><a href="#cb1-1"> </a><a href="https://en.wikipedia.org/wiki/Fibonacci_number"> mtimesDefault :: </a><a href="#cb1-1"> (Monoid) (a)=(Integer) <title> -> a) -> a) </p> <p> This is why I chose to implement the <code> Semigroup and </p><div class="adace-slot-wrapper adace-middle-content adace-align-center adace-slot-wrapper-main" style="text-align:center;"> <div class="adace-disclaimer"> </div> <div class="adace-slot"> <div class="adace_ad_66235e6327205 adace-dont-remove"> </a> </div> </div> </div> <div id="cb1"> (Monoid) interface, because when we do so we can use the above utility for free. The <code> mtimesDefault <a href="#cb1-3"> function works for any type that implements those two interfaces (like our <code> Matrix2x2 (type). This means that in order to exponentiate a matrix, I only need to write <code> mtimesDefault n matrix <span id="cb1-3">, which will multiply our <code> matrix by itself </p> <div id="cb1"> n times. <a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </p> <p> The documentation for this utility fails to note one important detail: </p> <div id="cb1"> mtimesDefault will compute the result in only O (log (n)) operations using the trick known as (exponentiation by squaring) . </p> <p> This leads to the solution for our elegant and efficient fibonacci function, which is: </p> <p> <code> <code> <a href="https://en.wikipedia.org/wiki/Fibonacci_number"> import </a><a href="#cb1-1"> </a><a href="#cb1-1"> qualified </p> <div id="cb1">. Semigroup <a href="#cb1-1"> <code> as <code> Semigroup <a href="#cb1-1"> </a><a href="#cb1-1"> </a> <a href="#cb1-1"> [<span>0</span>,<span>1</span>,<span>1</span>,<span>2</span>,<span>3</span>,<span>5</span>,<span>8</span>,<span>13</span>,<span>21</span>,<span>34</span>,<span>55</span>,<span>89</span>,<span>144</span>,<span>233</span>,<span>377</span>,<span>610</span>,<span>987</span>,<span>1597</span>,<span>2584</span>,<span>4181</span>,<span>6765</span>] </a> <code> f :: <span id="cb1-2"> <a href="#cb1-1"> Integer <span id="cb1-2"> <a href="#cb1-1"> -> </a></span> </a><a href="#cb1-1"> Integer <code> <a href="#cb1-1"> [<span>0</span>,<span>1</span>,<span>1</span>,<span>2</span>,<span>3</span>,<span>5</span>,<span>8</span>,<span>13</span>,<span>21</span>,<span>34</span>,<span>55</span>,<span>89</span>,<span>144</span>,<span>233</span>,<span>377</span>,<span>610</span>,<span>987</span>,<span>1597</span>,<span>2584</span>,<span>4181</span>,<span>6765</span>] fn </p> <div id="cb1"> (x) (Semigroup.mtimesDefault n matrix) <code> () () <a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </p> <p> <a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </a><a href="#cb15-3"> </a> matrix <a href="#cb1-1"> ( </p> <div id="cb1"> <a href="#cb15-4"> </a><a href="#cb15-4"> </a> <a href="#cb1-1"> Matrix <code> <a href="#cb15-5"> </a><a href="#cb15-5"> </a><a href="https://en.wikipedia.org/wiki/Fibonacci_number"> {x </p> <div id="cb1">=<a href="#cb1-1"> (0) , x 18 <code>= 1 </p> <div id="cb1"> <a href="#cb1-1"> </a><a href="#cb15-6"> </p> <p>, x =<a href="#cb1-1"> 1 </a><a href="#cb1-1">, x 22 </a><a href="#cb1-1">=</a><a href="#cb1-1"> (1) </a><a href="#cb15-7"> </p> <p> <a href="#cb1-3"> </p> <p> Here I’ve added one last simplification, which skips the final vector multiplications by instead extracting the value in the top right corner of our 2 × 2 matrix. This simplification works for the fibonacci numbers, but does not necessarily work for the general solution of computing an arbitrary arithmetic sequence. </p> <p> Let’s quickly eyeball that things work: </p> <p> <a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </a><a href="https://en.wikipedia.org/wiki/Fibonacci_number"> (>>> </a><a href="#cb1-1"> (map) (f [<span>0</span><span>..</span><span>20</span>]) </a><a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </a><a href="#cb1-1"> </a><a href="#cb1-3"> </a><a href="#cb1-3"> </p> <p> ... and now we can compute extraordinarily large Fibonacci numbers, even more quickly than the computer can display them: </p> <p> </a><a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </p> <div id="cb1"> <code>>>> (f) <a href="#cb1-1"> <title><a href="#cb1-1"> <span id="cb16-1"> <title><a href="#cb1-1"> <span> <a href="#cb1-1"> </a> <a href="#cb1-1"> <title></p> <p><title></p> <div id="cb1"> <a href="#cb17-1"> </a><a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </a><a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </a><a href="#cb17-3"> </p> <p> 🌺 <a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </a><a href="https://en.wikipedia.org/wiki/Fibonacci_number"> lines </a><a href="#cb1-1"> later 🌺 </a><a href="#cb1-1"> </a><a href="#cb17-4"> </p> <div id="cb1"> </p> <p> <a href="https://en.wikipedia.org/wiki/Fibonacci_number"> </a></p> </div> <p> ... in fact, you can easily compute up to </p> <div id="cb1"> f ( ^ 8) <a href="#cb1-3"> in a couple of seconds using this code (not shown, because the result takes far longer to print than to compute). (Appendix) </p> <p> Here is the complete example in case you want to test this out on your own: </p> <p> <title><code> <a href="#cb17-6"> </p> <div id="cb1"> module Fibonacci <a href="#cb1-1"> </a><a href="#cb1-1"> (</p> <div id="cb1"> <a href="#cb1-1"> <title> (import <a href="https://en.wikipedia.org/wiki/Fibonacci_number"> <span> </span> Data.Semigroup <span> <code> as <a href="#cb1-1"> <span id="cb1-1"> Semigroup <a href="#cb1-1"> <title>

Matrix2x2 = Matrix

      { x 18 ::   Integer ,  x :  (Integer    

,