A couple of weeks ago I ended up on this page about smoothsort, thanks hackernews you faithful time sync. Smoothsort is widely considered to be the greatest of the greats when it comes to both execution time and memory. It manages O ( n l g n ) O(n\ lg\ n) O(n lg n) optimized for O ( n ) O(n) O(n) best case and O ( n ) O(n) O(n) memory.

The short story is that it uses an in-place heap sort to achieve this but instead of a boring old binary heap it uses a mighty Leonardo heap.

I will not go in depth about Leonardo heaps or smoothsort as I want to follow up with a post about implementing all of this in Rust as my hello world, instead I will talk about the math behind this wonderfully quirky data structure.

The lesser known Leonardo numbers

Everybody knows about Fibonacci, but the Leonardo numbers have one up on them… Sorry couldn’t help myself.

L 0 = 1 L 1 = 1 L i = L i − 2 + L i − 1 + 1 \displaystyle L_0 = 1

ewline L_1 = 1

ewline L_i = L_{i-2} + L_{i-1} + 1 L0​=1L1​=1Li​=Li−2​+Li−1​+1

Which means that the first few Leonardo numbers are:

{ 1 , 1 , 3 , 5 , 9 , 15 , 25 , 41 , 67 , 109... } \displaystyle \{ 1, 1, 3, 5, 9, 15, 25, 41, 67, 109... \} {1,1,3,5,9,15,25,41,67,109...}

A Leonardo heap consists of one or more binary trees such that the number of nodes in each tree is a Leonardo number. Now in order for Leonardo heaps to work we must prove that:

Any number n n n can be written as a sum of distinct Leonardo numbers. Thus we can take any set of n n n numbers and arrange them into k k k binary trees each having s i , 0 ≤ i < k {s_i, 0 \le i \lt k} s i ​ , 0 ≤ i < k nodes, such that s i s_i s i ​ is a Leonardo number. For any n n n , the number of binary trees needed to form the heap ( k k k ) is at most l g n lg\ n l g n . Knowing how many binary trees our Leonardo heap contains will help when calculating the asymptotic complexity of the push and pop operations.

I really wanted to prove these two conjectures myself so I stopped reading Keith’s explanation and picked up a pencil. I have to say it was harder than it should have been.

The proof

Caveat: I’m pretty rusty when it comes to math so pretty please let me know if I get stuff wrong. There’s a “Did I get something wrong?” link at the end that points to the GitHub page where you can open an issue or submit a pull-request for this very article.

∀ n ∈ N , ∃ x k such that ∑ 0 ≤ i ≤ k L x i = n and x i < x i + 1 \displaystyle \forall n \in ℕ, \exist x_k \textrm{ such that } \sum_{\mathclap{0\le i\le k}} L_{x_i} = n \textrm{ and } x_i < x_{i+1} ∀n∈N,∃xk​ such that 0≤i≤k​∑​Lxi​​=n and xi​<xi+1​

That’s the gist of what we want to prove. In English, we need to prove that for any natural number n n n there exists a sequence of k k k numbers denoted x k x_k xk​ such that the sum of the x i x_i xi​-th Leonardo numbers ( L x i L_{x_i} Lxi​​) for 0 < i < k 0\lt i\lt k 0<i<k is n n n, also we restrict the sequence to be of distinct monotonically increasing numbers by adding the condition x i < x i + 1 x_i < x_{i+1} xi​<xi+1​.

I stared at these equations for a while. I knew there was some sort of induction proof out there. The Leonardo sequence formula hinted at that especially hard with the plus one in L i = L i − 1 + L i − 2 + 1 L_i = L_{i-1}+L_{i-2} +1 Li​=Li−1​+Li−2​+1. But I couldn’t figure it out. It felt like you transition from n n n to n + 1 n+1 n+1 by collapsing two consecutive Leonardo numbers into the next one, but there was one piece of the puzzle missing.

Finally I started to do what every computer scientist knows best, actually build the sets of numbers manually and look for patterns. I did that on my notebook first but then I thought to myself, you know javascript!

With a little help from React I built this nifty widget that computes the desired sequence x k x_k xk​ for consecutive n n n. The first column is n n n, the next are the members of the set. You can use the toggle at the top to switch between the actual Leonardo numbers or the Leonardo sequence indices.

Showing: Leonardo numbers / indices n = 1 1 2 1 1 3 3 4 1 3 5 5 6 1 5 7 1 1 5 8 3 5 9 9 10 1 9 11 1 1 9 12 3 9 13 1 3 9 14 5 9 15 15 16 1 15 17 1 1 15 18 3 15 19 1 3 15 20 5 15 21 1 5 15 22 1 1 5 15 23 3 5 15 24 9 15 25 25 26 1 25 27 1 1 25 28 3 25 29 1 3 25 30 5 25 31 1 5 25 32 1 1 5 25 33 3 5 25 34 9 25 35 1 9 25 36 1 1 9 25 37 3 9 25 38 1 3 9 25 39 5 9 25 40 15 25 41 41 42 1 41 43 1 1 41 44 3 41 45 1 3 41 46 5 41 47 1 5 41 48 1 1 5 41 49 3 5 41 50 9 41 51 1 9 41 52 1 1 9 41 53 3 9 41 54 1 3 9 41 55 5 9 41 56 15 41 57 1 15 41 58 1 1 15 41 59 3 15 41 60 1 3 15 41 61 5 15 41 62 1 5 15 41 63 1 1 5 15 41 64 3 5 15 41 65 9 15 41 66 25 41 67 67 68 1 67 69 1 1 67 70 3 67 71 1 3 67 72 5 67 73 1 5 67 74 1 1 5 67 75 3 5 67 76 9 67 77 1 9 67 78 1 1 9 67 79 3 9 67 80 1 3 9 67 81 5 9 67 82 15 67 83 1 15 67 84 1 1 15 67 85 3 15 67 86 1 3 15 67 87 5 15 67 88 1 5 15 67 89 1 1 5 15 67 90 3 5 15 67 91 9 15 67 92 25 67 93 1 25 67 94 1 1 25 67 95 3 25 67 96 1 3 25 67 97 5 25 67 98 1 5 25 67 99 1 1 5 25 67 100 3 5 25 67 101 9 25 67 102 1 9 25 67 103 1 1 9 25 67 104 3 9 25 67 105 1 3 9 25 67 106 5 9 25 67 107 15 25 67 108 41 67 109 109 110 1 109 111 1 1 109 112 3 109 113 1 3 109 114 5 109 115 1 5 109 116 1 1 5 109 117 3 5 109 118 9 109 119 1 9 109 120 1 1 9 109 121 3 9 109 122 1 3 9 109 123 5 9 109 124 15 109 125 1 15 109 126 1 1 15 109 127 3 15 109 128 1 3 15 109 129 5 15 109 130 1 5 15 109 131 1 1 5 15 109 132 3 5 15 109 133 9 15 109 134 25 109 135 1 25 109 136 1 1 25 109 137 3 25 109 138 1 3 25 109 139 5 25 109 140 1 5 25 109 141 1 1 5 25 109 142 3 5 25 109 143 9 25 109 144 1 9 25 109 145 1 1 9 25 109 146 3 9 25 109 147 1 3 9 25 109 148 5 9 25 109 149 15 25 109 150 41 109 151 1 41 109 152 1 1 41 109 153 3 41 109 154 1 3 41 109 155 5 41 109 156 1 5 41 109 157 1 1 5 41 109 158 3 5 41 109 159 9 41 109 160 1 9 41 109 161 1 1 9 41 109 162 3 9 41 109 163 1 3 9 41 109 164 5 9 41 109 165 15 41 109 166 1 15 41 109 167 1 1 15 41 109 168 3 15 41 109 169 1 3 15 41 109 170 5 15 41 109 171 1 5 15 41 109 172 1 1 5 15 41 109 173 3 5 15 41 109 174 9 15 41 109 175 25 41 109 176 67 109 177 177 178 1 177 179 1 1 177 180 3 177 181 1 3 177 182 5 177 183 1 5 177 184 1 1 5 177 185 3 5 177 186 9 177 187 1 9 177 188 1 1 9 177 189 3 9 177 190 1 3 9 177 191 5 9 177 192 15 177 193 1 15 177 194 1 1 15 177 195 3 15 177 196 1 3 15 177 197 5 15 177 198 1 5 15 177 199 1 1 5 15 177 200 3 5 15 177 201 9 15 177 202 25 177 203 1 25 177 204 1 1 25 177 205 3 25 177 206 1 3 25 177 207 5 25 177 208 1 5 25 177 209 1 1 5 25 177 210 3 5 25 177 211 9 25 177 212 1 9 25 177 213 1 1 9 25 177 214 3 9 25 177 215 1 3 9 25 177 216 5 9 25 177 217 15 25 177 218 41 177 219 1 41 177 220 1 1 41 177 221 3 41 177 222 1 3 41 177 223 5 41 177 224 1 5 41 177 225 1 1 5 41 177 226 3 5 41 177 227 9 41 177 228 1 9 41 177 229 1 1 9 41 177 230 3 9 41 177 231 1 3 9 41 177 232 5 9 41 177 233 15 41 177 234 1 15 41 177 235 1 1 15 41 177 236 3 15 41 177 237 1 3 15 41 177 238 5 15 41 177 239 1 5 15 41 177 240 1 1 5 15 41 177 241 3 5 15 41 177 242 9 15 41 177 243 25 41 177 244 67 177 245 1 67 177 246 1 1 67 177 247 3 67 177 248 1 3 67 177 249 5 67 177 250 1 5 67 177 251 1 1 5 67 177 252 3 5 67 177 253 9 67 177 254 1 9 67 177 255 1 1 9 67 177 256 3 9 67 177 257 1 3 9 67 177 258 5 9 67 177 259 15 67 177 260 1 15 67 177 261 1 1 15 67 177 262 3 15 67 177 263 1 3 15 67 177 264 5 15 67 177 265 1 5 15 67 177 266 1 1 5 15 67 177 267 3 5 15 67 177 268 9 15 67 177 269 25 67 177 270 1 25 67 177 271 1 1 25 67 177 272 3 25 67 177 273 1 3 25 67 177 274 5 25 67 177 275 1 5 25 67 177 276 1 1 5 25 67 177 277 3 5 25 67 177 278 9 25 67 177 279 1 9 25 67 177 280 1 1 9 25 67 177 281 3 9 25 67 177 282 1 3 9 25 67 177 283 5 9 25 67 177 284 15 25 67 177 285 41 67 177 286 109 177 287 287 288 1 287 289 1 1 287 290 3 287 291 1 3 287 292 5 287 293 1 5 287 294 1 1 5 287 295 3 5 287 296 9 287 297 1 9 287 298 1 1 9 287 299 3 9 287 300 1 3 9 287 301 5 9 287 302 15 287 303 1 15 287 304 1 1 15 287 305 3 15 287 306 1 3 15 287 307 5 15 287 308 1 5 15 287 309 1 1 5 15 287 310 3 5 15 287 311 9 15 287 312 25 287 313 1 25 287 314 1 1 25 287 315 3 25 287 316 1 3 25 287 317 5 25 287 318 1 5 25 287 319 1 1 5 25 287 320 3 5 25 287 321 9 25 287 322 1 9 25 287 323 1 1 9 25 287 324 3 9 25 287 325 1 3 9 25 287 326 5 9 25 287 327 15 25 287 328 41 287 329 1 41 287 330 1 1 41 287 331 3 41 287 332 1 3 41 287 333 5 41 287 334 1 5 41 287 335 1 1 5 41 287 336 3 5 41 287 337 9 41 287 338 1 9 41 287 339 1 1 9 41 287 340 3 9 41 287 341 1 3 9 41 287 342 5 9 41 287 343 15 41 287 344 1 15 41 287 345 1 1 15 41 287 346 3 15 41 287 347 1 3 15 41 287 348 5 15 41 287 349 1 5 15 41 287 350 1 1 5 15 41 287 351 3 5 15 41 287 352 9 15 41 287 353 25 41 287 354 67 287 355 1 67 287 356 1 1 67 287 357 3 67 287 358 1 3 67 287 359 5 67 287 360 1 5 67 287 361 1 1 5 67 287 362 3 5 67 287 363 9 67 287 364 1 9 67 287 365 1 1 9 67 287 366 3 9 67 287 367 1 3 9 67 287 368 5 9 67 287 369 15 67 287 370 1 15 67 287 371 1 1 15 67 287 372 3 15 67 287 373 1 3 15 67 287 374 5 15 67 287 375 1 5 15 67 287 376 1 1 5 15 67 287 377 3 5 15 67 287 378 9 15 67 287 379 25 67 287 380 1 25 67 287 381 1 1 25 67 287 382 3 25 67 287 383 1 3 25 67 287 384 5 25 67 287 385 1 5 25 67 287 386 1 1 5 25 67 287 387 3 5 25 67 287 388 9 25 67 287 389 1 9 25 67 287 390 1 1 9 25 67 287 391 3 9 25 67 287 392 1 3 9 25 67 287 393 5 9 25 67 287 394 15 25 67 287 395 41 67 287 396 109 287 397 1 109 287 398 1 1 109 287 399 3 109 287 400 1 3 109 287 401 5 109 287 402 1 5 109 287 403 1 1 5 109 287 404 3 5 109 287 405 9 109 287 406 1 9 109 287 407 1 1 9 109 287 408 3 9 109 287 409 1 3 9 109 287 410 5 9 109 287 411 15 109 287 412 1 15 109 287 413 1 1 15 109 287 414 3 15 109 287 415 1 3 15 109 287 416 5 15 109 287 417 1 5 15 109 287 418 1 1 5 15 109 287 419 3 5 15 109 287 420 9 15 109 287 421 25 109 287 422 1 25 109 287 423 1 1 25 109 287 424 3 25 109 287 425 1 3 25 109 287 426 5 25 109 287 427 1 5 25 109 287 428 1 1 5 25 109 287 429 3 5 25 109 287 430 9 25 109 287 431 1 9 25 109 287 432 1 1 9 25 109 287 433 3 9 25 109 287 434 1 3 9 25 109 287 435 5 9 25 109 287 436 15 25 109 287 437 41 109 287 438 1 41 109 287 439 1 1 41 109 287 440 3 41 109 287 441 1 3 41 109 287 442 5 41 109 287 443 1 5 41 109 287 444 1 1 5 41 109 287 445 3 5 41 109 287 446 9 41 109 287 447 1 9 41 109 287 448 1 1 9 41 109 287 449 3 9 41 109 287 450 1 3 9 41 109 287 451 5 9 41 109 287 452 15 41 109 287 453 1 15 41 109 287 454 1 1 15 41 109 287 455 3 15 41 109 287 456 1 3 15 41 109 287 457 5 15 41 109 287 458 1 5 15 41 109 287 459 1 1 5 15 41 109 287 460 3 5 15 41 109 287 461 9 15 41 109 287 462 25 41 109 287 463 67 109 287 464 177 287 465 465 466 1 465 467 1 1 465 468 3 465 469 1 3 465 470 5 465 471 1 5 465 472 1 1 5 465 473 3 5 465 474 9 465 475 1 9 465 476 1 1 9 465 477 3 9 465 478 1 3 9 465 479 5 9 465 480 15 465 481 1 15 465 482 1 1 15 465 483 3 15 465 484 1 3 15 465 485 5 15 465 486 1 5 15 465 487 1 1 5 15 465 488 3 5 15 465 489 9 15 465 490 25 465 491 1 25 465 492 1 1 25 465 493 3 25 465 494 1 3 25 465 495 5 25 465 496 1 5 25 465 497 1 1 5 25 465 498 3 5 25 465 499 9 25 465 500 1 9 25 465

Source on github.

You might have noticed that for the n = 1 n=1 n=1 I actually use L 1 L_1 L1​ instead of L 0 L_0 L0​ this is intentional and actually part of the nifty solution. You can already start to see some pretty clear patterns and recursion emerge. If you look closely at the numbers you’ll see that between any two consecutive n n n only one of two things happens:

x 1 x_1 x1​ = x 0 + 1 x_0 + 1 x0​+1, aka the first to indices are consecutive and they collapse into the next Leonardo number, because if we have two consecutive indices there L x 0 + L x 1 + 1 = L x 1 + 1 L_{x_0} + L_{x_1} + 1 = L_{x_1+1} Lx0​​+Lx1​​+1=Lx1​+1​ We add L 0 L_0 L0​ or L 1 L_1 L1​ at the front of the sequence, if both were already there that would fall into (1).

The first situation isn’t intuitively true because, when trying to transition from n n n to n + 1 n+1 n+1, collapsing two consecutive Leonardo numbers might give you another number that’s already in the sequence. But that’s actually the missing piece. If you look at all the numbers in the box you’ll notice that we only ever get consecutive Leonardo numbers in the first two positions of the sequence, check it out. Thus we can prove the conjecture by further restricting its conditions:

∀ n ∈ N , ∃ x k such that (1) ∑ 0 ≤ i ≤ k L x i = n (2) x 0 < x 1 (3) x i + 1 < x i + 1 , for i > 0 (4) x 0 = 0 ⟺ x 1 = 1 \displaystyle \forall n \in ℕ, \exist x_k \textrm{ such that }

ewline \textrm{(1) } \sum_{\mathclap{0\le i\le k}} L_{x_i} = n

ewline \textrm{(2) } x_0 < x_1

ewline \textrm{(3) } x_i + 1 < x_{i+1}, \textrm{for } i > 0

ewline \textrm{(4) } x_0 = 0 \iff x_1 = 1 ∀n∈N,∃xk​ such that (1) 0≤i≤k​∑​Lxi​​=n(2) x0​<x1​(3) xi​+1<xi+1​,for i>0(4) x0​=0⟺x1​=1

Let’s break it down. The first condition stays the same as before. The 2nd and 3rd ensure not only that the sequence is monotonically increasing but that two consecutive indices will only occur at the beginning of the sequence. The 4th is a little helper condition that enforces 0 0 0 to be part of the sequence only if 1 1 1 already is. It helps us have a single valid transition when neither 0 , L 0 = 1 0, L_0 = 1 0,L0​=1 or 1 , L 1 = 1 1, L_1 = 1 1,L1​=1 are part of the sequence for n n n and we’re transitioning to n + 1 n+1 n+1.

For the induction part we say that for n = 0 n=0 n=0, the empty sequence fulfils all conditions. Now we need to prove that for any n n n with a sequence x k x_k xk​, fulfilling the conditions, there’s a sequence y l y_l yl​ fulfilling the same conditions for n + 1 n+1 n+1. This becomes trivial after the observations I made above, when looking at the changes in structure between consecutive values of n n n. We have these cases:

x 1 x_1 x 1 ​ = x 0 x_0 x 0 ​ + 1, the first two elements of x x x are consecutive

If that’s the case we can defined a sequence y y y with k − 1 k-1 k−1 elements. y 0 = x 1 + 1 y_0 = x_1 + 1 y0​=x1​+1 and y i = x i + 1 , i > 0 y_i = x_i+1, i > 0 yi​=xi​+1,i>0. It follows that:

∑ 0 ≤ i ≤ k − 1 L y i = L x 1 + 1 + ∑ 2 ≤ i ≤ k L x i = L x 1 + L x 1 − 1 + 1 + ∑ 2 ≤ i ≤ k L x i = ∑ 0 ≤ i ≤ k L x i + 1 = n + 1 \displaystyle \sum_{\mathclap{0\le i\le k-1}} L_{y_i} = L_{x_1 + 1} + \sum_{\mathclap{2\le i\le k}} L_{x_i}= L_{x_1} +L_{x_1-1} + 1 + \sum_{\mathclap{2\le i\le k}} L_{x_i} = \sum_{\mathclap{0\le i\le k}} L_{x_i} + 1 = n + 1 0≤i≤k−1​∑​Lyi​​=Lx1​+1​+2≤i≤k​∑​Lxi​​=Lx1​​+Lx1​−1​+1+2≤i≤k​∑​Lxi​​=0≤i≤k​∑​Lxi​​+1=n+1

x 0 x_0 x 0 ​ = 1 and case (1) does not apply, which means that we can define y y y with k + 1 k+1 k + 1 elements such that y 0 = 0 y_0 = 0 y 0 ​ = 0 and y i = x i − 1 , i > 0 y_i = x_{i-1}, i > 0 y i ​ = x i − 1 ​ , i > 0 , it follows that:

∑ 0 ≤ i ≤ k − 1 L y i = L 0 + ∑ 0 ≤ i ≤ k = 1 + ∑ 0 ≤ i ≤ k L x i = n + 1 \displaystyle \sum_{\mathclap{0\le i\le k-1}} L_{y_i} = L_{0} + \sum_{\mathclap{0\le i\le k}} = 1 + \sum_{\mathclap{0\le i\le k}} L_{x_i}= n + 1 0≤i≤k−1​∑​Lyi​​=L0​+0≤i≤k​∑​=1+0≤i≤k​∑​Lxi​​=n+1

x 0 x_0 x 0 ​ ≠ 1 1 1 , from that follows that x 0 x_0 x 0 ​ ≠ 0 0 0 otherwise the 4th condition would imply x 1 = 1 x_1 = 1 x 1 ​ = 1 and case (1) would apply. So let there be a sequence y y y with k + 1 k+1 k + 1 elements such that y 0 = 1 y_0 = 1 y 0 ​ = 1 and y i = x i − 1 , i > 0 y_i = x_{i-1}, i > 0 y i ​ = x i − 1 ​ , i > 0 , it follows that:

∑ 0 ≤ i ≤ k − 1 L y i = L 1 + ∑ 0 ≤ i ≤ k = 1 + ∑ 0 ≤ i ≤ k L x i = n + 1 \displaystyle \sum_{\mathclap{0\le i\le k-1}} L_{y_i} = L_{1} + \sum_{\mathclap{0\le i\le k}} = 1 + \sum_{\mathclap{0\le i\le k}} L_{x_i}= n + 1 0≤i≤k−1​∑​Lyi​​=L1​+0≤i≤k​∑​=1+0≤i≤k​∑​Lxi​​=n+1

Which wraps up our proof nicely. All that’s left now is to figure out if for the series x k , k < = l g n x_k, k <= lg\ n xk​,k<=lg n, but I’ll leave this as an exercise to the reader.

Tune in next time when I take all this further and talk about the Leonardo heap and how that’s used in implementing the elusive smoothsort.