Summary of State Representation ------------------------------- In my first two programs, I used classes to represent the SuDoKu grid, each square that went inside the grid, and the domains for each of the squares (this only pertained to #2, the forward-checking algorithm). In my 3rd representation, I dropped the Class of SuDoKu for a struct, tweaked the Domain and Square implementations, added my own Queue function, and implemented a MyArc struct, which was basically to keep track of arcs on the grid. My 4th representation was much the same as my 3rd, except I converted the MyArc struct to a struct representing an ordered pair of rows/columns. I used this in junction with my Queue to keep track of where I needed to apply the pigeonhole principle. My operators in each representation were different -------------------------------------------------- 1st - All I used was a Test() function to check whethere a value could be put at a grid space without violating SuDoKu rules 2nd - In this representation, whenever I set a square to a certain value, the puzzle automatically diminished the domains for me. 3rd - This representation worked exactly like the second, but with the extra arc consistency checking. 4th - Whenever I assigned a value to a square, the Set() function recursively kept diminishing the domains of the proper grid spaces and automatically assigning values to grid spaces with domains of size 1. It also used a queue to keep track of spaces that were automatically assigned in this manner. This way, after it was done assigning, it could go back and apply the pigeonhole principle to see of the constraints were still satisfiable given the current state. How I did my experiment ----------------------- First, I set all my programs up to read 26 different SuDoKu puzzles from a file and process/solve them. Then I used the QueryPerformanceFrequency() and QueryPerformanceCounter() function calls to time the programs as specified. Graphs/Tables ------------- Check http://www.filebox.vt.edu/users/zscronce/CS4804/graph.bmp for a graph of my results Conclusions and Lessons Learned ------------------------------- As I expected, since 5-1 was the least elegant, it was by far the slowest. It took a little under twice as long as the next fastest. I also expected 5-3 to take quite a long time because of all the queue operations. If each Arc took time 1 to process, then for each square we assign a value, we may have to go through n^2 Arcs. This was definitely reflected in its Doing to Thinking ratio. 5-3 spent almost 30 times as long doing arc-consistency checking than filling in squares! However, although I expected this program to take long, I didn't think it would be as close to 5-2 as it was. 5-2 seemed to be pretty well-rounded, but still on the gruntwork side. It spent the majority of its time in the "Doing" processes, but not by much. 5-4 was LIGHTNING FAST compared to the others. It finished in about 7.5% of the time that 5-2 took (5-2 being the next-fastest one). Overall, it seems obvious that if you can simplify the algorithm based on the constraints in any way similar to the AllDif algorithm, DO IT. The benefits are obvious. Also, grunt Depth-First searching is slow, but only by about a factor of two for SuDoKu.