SICP Exercise 2.43 slow queens

Exercise 2.43.  Louis Reasoner is having a terrible time doing exercise 2.42. His queens procedure seems to work, but it runs extremely slowly. (Louis never does manage to wait long enough for it to solve even the 6× 6 case.) When Louis asks Eva Lu Ator for help, she points out that he has interchanged the order of the nested mappings in the flatmap, writing it as

(flatmap
 (lambda (new-row)
   (map (lambda (rest-of-queens)
          (adjoin-position new-row k rest-of-queens))
        (queen-cols (- k 1))))
 (enumerate-interval 1 board-size))


Explain why this interchange makes the program run slowly. Estimate how long it will take Louis's program to solve the eight-queens puzzle, assuming that the program in exercise 2.42 solves the puzzle in time T.

SOLUTION

The code and tests are here.

Explanation
===========
In this procedure, the 'lambda (new-row)' function is applied to every element in the sequence produced by (enumerate-interval 1 board-size). But note that in the implementation of this lambda function (queen-cols (- k 1)) is evaluated. Therefore, for a given 'k' queen-cols is evaluated 'board-size' times. Now, since k itself ranges from 0 to board-size, queen-cols is evaluated a total of 'board-size raised to the power (board-size + 1)'.

For a 2x2 board, it will be 8 evaluations
For a 3x3 board, it will be 81 evaluations
For a 4x4 board, it will be 1024 evaluations
For a 5x5 board, it will be 15625 evaluations
For a 6x6 board, it will be 279936 evaluations
For a 7x7 board, it will be 5764801 evaluations
For a 8x8 board, it will be 134217728 evaluations

That is why the program runs more slowly than the version in the previous exercise. 

For the eight-queen puzzle, the implementation in the previous exercise calls queen-cols 9 times (since k ranges from 8 to 0).
Therefore, assuming that the program in exercise 2.42 solves the puzzle in time T it will take Louis's program (134217728/9)T = 14913081T to solve the eight-queens puzzle.

In my testing, the difference between the two implementations first became noticeable for a board size of 7x7 where the slower implementation took about 1.2 seconds of CPU time.

For 8x8 it took about 22 seconds of CPU time.
For 9x9 it took 793 seconds of CPU time (about 13.2 minutes).
For 10x10 it took about 242 minutes of CPU time (about 4 hours).

See test results in the code link above.

Comments

Popular posts from this blog

SICP Exercise 2.56 differentiation rule

SICP Exercise 1.28 (Miller-Rabin Test)

SICP Exercise 4.18 a alternative strategy for interpreting internal definitions