Double Dobble - slight improvement

TL;DR

Chipping away some more time in the search for [Double Dobble][] arrangements!

After writing Double Dobble - easy optimization, my brain remained thinking if there was any further low-hanging fruit to gather. I mean, I know that I haven’t exploited the symmetry in the solutions… but it’s mainly because my gut feeling is that it would take a lot of time and I’m not sure how much this might improve the situation.

On the other hand… low hanging fruits are so sweet! 🙄

And there it is!

Just like any valid arrangement MUST contain two indexes that are adjacent, then it MUST also contain two indexes that are two-spaced apart, thanks to the double-dobble-ness nature of the problem.

Confused? Let’s see…

The difference of 2 must occur twice, just like any other difference. Fact is, anyway, that it’s a difference of any index with respect to any other index. So, for example, the following arrangement contains one delta of 2 even if there are no two-spaced indexes:

(0,1,2,...)

You see? Index 2 is spaced from index 0 by… 2 spaces.

But.

We’re looking for [Double Dobble][]s, right? This means that the difference of 2 MUST occur somewhere else. Now there are two cases:

  • there are indeed two indexes that are spaced by two, like $(…, x, x
    • 2, …)$ - yay!
  • we have a new triplet like (,x,x+1,x+2). This cannot happen in a valid arrangement for [Double Dobble][], because it would imply that the distance-by-1 occurs four times:
10=121=1(x+1)x=1(x+2)(x+1)=1

So… the spacing-by-2 MUST indeed occur! New iterator definition for us:

my $it = NestedLoops(
   [
      [0], [2],
      map {
         my $end = $N - 1 - ($k - 1) + $_;
         sub { [($_ + 1) .. $end] },
      } (2 .. $k - 1)
   ]
);

Not only this brings us down to (N3k2) for exhaustive searches:

$ time perl old-code.pl 8

real	0m4.126s
user	0m4.088s
sys	0m0.008s

$ time perl new-code 8

real	0m3.379s
user	0m3.368s
sys	0m0.004s

but it might also help finding valid arrangements when they are possible:

$ time perl old-code.pl 9
(0 1 3 7 17 24 25 29 35)

real	0m28.675s
user	0m28.544s
sys	0m0.068s

$ time perl new-code 9
(0 2 3 5 9 19 26 27 31)

real	0m4.260s
user	0m4.220s
sys	0m0.016s

Not bad!

Last, I tried to actually implement a sieve to pre-cache the result for all possible variants of a specific sequence. Well… either I didn’t code it well, or the amount of work required to do this generate-then-cache is comparable with the work to do a straight check on a new sequence, because the times I got (up to generating all possible arrangements with k=9) were slightly worse than the results above.

Stay safe!


Comments? Octodon, , GitHub, Reddit, or drop me a line!