extended essay - matej hamašmatejhamas.weebly.com/.../_extended_essay_matej_hamas.pdf ·...
TRANSCRIPT
Extended Essay
Subject: Computer Science
A comparison of different algorithms for solving magic squares
Name: Matej Hamaš
Candidate number: 000771-023
Examination session: May 2012
Supervisor: Ms. Eva Hanulová
Word Count: 3980
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
2
(blank page)
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
3
Acknowledgments
I would like to give special thanks to Artur Ejsmont who gave me a helping hand and found
time for a discussion on the topic of evolutionary algorithms.
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
4
Abstract
This essay deals with different algorithms for solving magic squares (squares of size
containing numbers 1, …, , having equal sum in every row, column and diagonal) and
comparing their efficiency under several criteria, such as the speed of the algorithm, the
ability to search systematically for all solutions and certainty of finding solution.
Besides some examples found on the internet, the core of the essay lays in proposing two
algorithms I have designed. The first is deterministic, based on brute force recursion. The
second one is probabilistic, thus possessing the feature of randomness.
The essay explains how I have been developing these two algorithms, to make them as
efficient as possible. Regarding the deterministic one, it initially worked on pure brute force
recursion, and then many backtracking features have been added in order not to waste time
exploring options that certainly did not lead to right solution. Speaking about the
probabilistic algorithm, at the beginning it was swapping two random cells until a magic
square was found. Hill climbing and evolutionary features were later implemented to
improve its efficiency.
After testing best versions of both algorithms, the deterministic one proved to be more
suitable for smaller squares (up to 4x4) where it is able to efficiently find all the possible
magic squares. The probabilistic one, despite the uncertainty of finding the solution, turned
out to be better choice for larger squares (up to 15x15) where deterministic approach fails.
Both algorithms are obviously not absolutely efficient so I am proposing also improvements
that might be implemented further, such as using several computers or processor cores
during the search. In the appendices I include the source codes of best versions of both
algorithms.
Word count: 283
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
5
Table of Contents
Acknowledgments ...................................................................................................................... 3
Abstract ...................................................................................................................................... 4
Table of Contents ....................................................................................................................... 5
1. Introduction ............................................................................................................................ 7
1.1. Nature of Magic Squares ................................................................................................. 7
1.2. Plan of investigation ........................................................................................................ 8
2. Criteria for assessing different algorithms ............................................................................. 8
3. Methods for magic square solving that already exist ............................................................ 9
3.1. Mathematical approaches ............................................................................................... 9
3.2. Brute force an backtracking........................................................................................... 10
3.3 Genetic algorithm ........................................................................................................... 11
4. Proposal, improvements and drawbacks of my algorithms ................................................ 11
4.1. Probabilistic algorithms ................................................................................................. 12
Brute force ........................................................................................................................ 12
Intelligent check ............................................................................................................... 12
Hill climbing added ........................................................................................................... 13
Evolutionary aspect added ............................................................................................... 14
The problem of local maxima ........................................................................................... 15
My approaches of solving local maxima problems .......................................................... 15
Further possible improvements of avoiding local maxima .............................................. 16
4.2. Deterministic algorithms ............................................................................................... 16
Brute Force Recursion ....................................................................................................... 17
Each number just once ..................................................................................................... 17
End points checks ............................................................................................................. 17
Remembering line’s sums ................................................................................................. 17
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
6
More decision points ........................................................................................................ 17
Automatic calculation of end points ................................................................................ 18
Rotation ............................................................................................................................ 18
5. Comparison of algorithms efficiency ................................................................................... 18
6. Conclusion ............................................................................................................................ 23
7. References ............................................................................................................................ 24
Appendices ............................................................................................................................... 26
Appendix A – screenshot of found solution of squares of order 14 and 15 ........................ 26
Appendix B: Email communication with Artur Ejsmont ....................................................... 27
Appendix C: Probabilistic Algorithm ..................................................................................... 28
Class Square ...................................................................................................................... 28
Class Generation ............................................................................................................... 32
Class PA ............................................................................................................................ 36
Appendix D: Deterministic Algorithm ................................................................................... 38
Class Backtracking ............................................................................................................ 38
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
7
1. Introduction
I firstly came across the term magic square at the mathematical grammar school a few years
ago. All I learnt about them came back to me at the end of 1st year at IB, when we were
supposed to create a didactic computer application for primary school children. I decided to
create an application, training children’s mathematical skills while solving magic squares,
with some already prefilled numbers, depending on chosen difficulty.
While finishing the application, I thought about implementing a feature allowing children to
see the correct result. It means I thought about how computer could actually solve the
magic square. This problem was challenging and later inspired me to choose it as the topic
for my extended essay. I am going to elaborate on different ways how magic squares can be
solved by computer. Explicitly, I will attempt to answer the following question:
How effective are different approaches for solving magic squares by computers?
1.1. Nature of Magic Squares
Magic square is a structure which has fascinated mathematicians for centuries. It is defined
as square array of numbers consisting of positive integers 1…n2 in such a way that sum of
each row, column and diagonal of this array is the same (1). Firstly it is essential to define
terms connected to this structure, which will be extensively used further in the essay.
Size n, or order, of the magic square expresses the length of one side of the square
array.
Each row, column or diagonal is made of n cells.
Magic constant c is the sum of every row, column or diagonal of the square. Since
magic square contains numbers 1, …, n2, magic constant can be easily calculated as
the sum of arithmetic sequence 1, …, n2 divided by n.
∑
( )
( ) (1)
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
8
Example of magic square
Magic square of size 3, containing numbers 1, 2, 3, …, 9 has magic constant
.
There are many magic squares of order 3. One of them is the following.
Figure 1: Example of magic square of size 3. Arrows show sums in particular column, row or diagonal.
1.2. Plan of investigation
Defining criteria for assessing different algorithms / computing approaches
Searching for existing algorithms and indications of solving methods
Proposing my algorithms
Stating issues of my computing approaches and their possible future
improvements
Assessing and comparing efficiency of both created and found algorithms
2. Criteria for assessing different algorithms
The problem of solving magic squares from computer science point of view has not yet been
deeply studied, and I have not been able to find any common criteria for assessing different
algorithms for solving such problem. Therefore I decided to make these criteria up. I
brainstormed to gather things I found important for an algorithm to work as efficiently as
possible. I tried to look at the problem from various points of view. Lastly, I picked up criteria
I found most relevant. There is a list of them:
15 15 15 15
8 1 6 15
3 5 7 15
4 9 2 15
15
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
9
1. Certainty of finding solution
a. In finite time: algorithm is able to find solution in finite time. There is 100 %
probability that the solution will be found.
b. In infinite time: there is just certain probability (always lower than 100 %) that
the algorithm will find a solution.
2. Ability to search systematically for all solutions
3. Solving time
a. Until the first solution is found
b. Until all solutions are found (if possible)
4. Robustness of the algorithm
a. Algorithm is able to solve only blank squares
b. Algorithm is able to solve squares with a few prefilled numbers
5. Maximum square order – how large magic squares can algorithm solve
3. Methods for magic square solving that already exist
During the research I have come across a few methods that have been already used for
solving this problem. However, not many studies deal with this topic and in many cases only
indications are provided that magic squares have been solved by particular method,
unfortunately often with lack of deeper explanation. The advantage of this was that it
offered me more space to make up something on my own.
3.1. Mathematical approaches
There are different mathematical methods of constructing magic square of any order. For
constructing magic squares of odd order, de la Loubere’s method can be used. There are also
methods for constructing square of double-even (divisible by 4) and even order, e.g. “LUX”
method (1). Generally, major limitation of such algorithms is that they can be used just for
solving blank squares. They also cannot be used for finding wide variety of solutions (though
some other solutions can be obtained by particular further reflections, rotations or other
mathematical transformations (9)). These are main disadvantages of such approaches, and
since they are based on mathematical, rather than on computational principle, I will not
discuss them further into greater depth.
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
10
3.2. Brute force and backtracking
Brute force method is crude computing method involving trying to find out straightforward
solution to a problem (6). In this case it means trying all possible combinations of numbers
from 1 to n2. For a square of order n, there are possible arrangements of numbers.
Figure 2. shows this relationship.
Figure 2: The relationship between square size n and number of possible arrangements of numbers into the
square, using pure brute force approach. Notice how rapidly the series increases1.
It is clear that pure brute force approach is really inefficient for squares of higher orders,
since number of possible arrangements rises very rapidly (the complexity in this case is even
higher than factorial complexity) with increasing order2. And that is the reason for
introducing backtracking. Backtracking is based on brute force, but enriched with feature of
making decisions in so called decision points. If you make good decision, you will approach
the right solution. If you realize you reached a dead end or that the previous choices were
incorrect, you ‘backtrack’ (return) to a previous step and try a different path (2)(a). This way,
1 This relationship could be described by the relation ( ) .
2 For square of order 8 there are possible arrangements, for square of order 13 even .
11E+161E+321E+481E+641E+801E+96
1E+1121E+1281E+1441E+1601E+1761E+1921E+2081E+2241E+2401E+2561E+2721E+2881E+304
1 2 3 4 5 6 7 8 9 10 11 12 13
(n2)!
Square order n
10304 10288 10272
10256 10240 10224 10208 10192 10176 10160 10144 10128 10112 1096 1080 1064 1048 1032
1016 1
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
11
lot of time is spared, since the algorithm does not waste time exploring arrangements that
are certainly wrong from early stage. I have found backtracking algorithm proposed by
Dr. Meyer, which is able to solve magic square of maximal order 6 in reasonable time (3).
Unfortunately I did not succeed in obtaining further information about concrete application
of this method on magic square problem. I therefore decided to propose my own
backtracking algorithm, which is present further in the essay.
3.3 Genetic algorithm
The next already finished solution I have found is based on genetic approach method (4).
Such a method was inspired by evolution, mainly on the survival of the fittest and natural
selection (5). It is based on generating new sets (generations) of solutions based on previous
generation through crossovers and mutations. Since the solutions I have found either did not
work very properly and were not very successful in finding the solution (4), or were just
outlined (10), I decided to work on this algorithm myself and I am going to elaborate on this
method in the following chapter.
4. Proposal, improvements and drawbacks of my algorithms
I would like to begin this chapter with short description of a way I have been developing my
algorithms. I started with very inefficient, but simple, methods and have been trying to
improve these methods by adding or changing certain aspects. This way, algorithms have
been evolving and their efficiency has been increasing (or unfortunately often also
decreasing). This kind of developing approach has been quite experimental and was
encouraged by following motto: “Truth is not discovered by proofs but by exploration. It is
always experimental.” (2)(b).
I designed my algorithms in a way they can solve not only blank magic square, but also one
with a few prefilled numbers. Prefilled numbers have to be obviously put in a way that magic
square can be created by filling in missing numbers. I was inspired by the Sudoku game and
decided to develop algorithms that would be helpful for solving squares, what can be
beneficial e.g. in didactic applications.
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
12
4.1. Probabilistic algorithms
Probabilistic algorithms are algorithms working on randomized principle. The probability we
find a solution is never 100 %, but these types of algorithms come useful for large search
spaces or in many optimization problems (problems that need to be solved by finding the
optimal solution – in our case finding the magic square among all possible squares), where
other algorithms fail.
Brute force
Brute force method does not have to be used exclusively as the core of backtracking as
mentioned above. My approach of using brute force method in this case is simple. I firstly
randomly fill in missing numbers to the square and randomly swap these numbers. After
each step I check whether this square is the magic one. Algorithm keeps swapping until
solution is found or certain maximum number of swaps3 is reached.
Intelligent check
The first improvement handles the way the square is tested whether it is a magic one.
Instead of exhausting checking after every swap I added two arrays of length n (row[n] and
column[n]) and variables diagonalLeft and diagonalRight. In every item of either array or in
any of these two variables the actual deviation dline of particular row, column or diagonal
(they are later called simply lines), is stored. This deviation is calculated as the difference
between actual sums of numbers in particular line and the magic constant c.
Next variable I used was total deviation d acquired as a sum of dline of every line. This
deviation determines the quality (fitness) of every square. For now, let us suppose that the
lower is d, the better is the quality, since this square is somehow ‘nearer’ to the optimal
magic one.
∑| |
∑| | | | | |
3 I have set this number to 2*10
4
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
13
Deviations are calculated at the very beginning after numbers are randomly distributed in
the square and are further modified in real time. Magic square has .
Hill climbing added
After addition of d an idea came into my mind. What if I enable just such swaps that would
decrease the d and thus lead to better solutions? After each swap new deviation (dnew) is
compared to old deviation (dold) and the swap is accepted only if . I later found
out this approach is very similar to hill climbing algorithm. This algorithm is used for
optimization problems and is based on moving from worse to better solutions (climbing up a
hill) (7).
There are ( ) of all possible squares of order n, and only few of them are magic ones. They
are interconnected, since from every square we can make many others by swapping two
cells. Let us connect every two squares that differ only in two swapped cells with an
imaginary thread. We will call such two squares neighbours. If we imagine these squares in
three dimensions, they would create a spacious net, with threads going from each square to
numerous others. If we create levels of squares according to quality of each square (the best
quality d = 0 in the top level), we would probably get discontinuous three dimensional graph
reminding of the countryside with many larger and smaller ‘hills’. From each square at a
particular level, we would be able to get many squares at different levels by single swap of
two cells. However, we cannot assume that we can jump over many levels and create square
with low total deviation from square with high total deviation (and vice versa) by a single
swap. The reason is that by every swap, we are able to alter the square deviation just a little
and thus to move just few levels up or down. For simplification, I will imagine the 3D
discontinuous net of magic squares as 3D continuous graph.
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
14
Figure 3: Simplified hill climbing environment for magic square problem, demonstrating
concepts of local and global optima (8)(a)
Peaks of ‘hills’ visible in Figure 3. are called global and local optima (8)(b). Magic squares are
located at global maxima, and local maxima are squares which total deviation is smaller
than total deviation of any of its neighbours. The concept of these optima is very important,
since existence of local maxima creates difficult obstacles in many optimization algorithms,
including using hill climbing technique for solving magic squares. Due to existence of local
maxima, I have to reconsider the assumption that lower d automatically means that the
square is ‘nearer’ to the magic one.
Evolutionary aspect added
I thought about whether it would not be more efficient to have more squares to choose
from at every decision point (after every swap) during the hill climbing. Therefore instead of
working with one square, I decided to create many squares from initial one and create a set
of magic squares. Every square differs from the original just in two cells. Then I choose the
best square from the set and repeat creating new set from this one. The hill climbing then
becomes apparently more efficient, since there is greater probability that we choose squares
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
15
leading to better solutions. During the research I encountered information about
evolutionary algorithms and realized that my approach is in fact the elitism evolutionary
algorithm (8)(c). Sets of squares are called generations. Each generation is created by one or
more parents (one in this case) and consists of offspring. They were originated through
mutations (random swap of two cells) of parent. In every generation, only the fittest
survives, becomes new parent and creates new generation. This process is repeated until
magic square is found or the program exceeds the set number of generations.
The problem of local maxima
During the testing of both simple and improved hill climbing algorithm, I found out it often
got stuck in local maxima, what was expressed by d of a square being constant in several
consecutive generations. If the initial square is located under the local maximum, then the
algorithm climbs the hills towards this maximum and never reaches the global maximum,
thus it never finds the magic square. I later found out the problem of local maxima often
appears in optimization problems.
My approaches of solving local maxima problems
1. Hill descending – if the square gets stuck in the local maximum, next few (ca. 5-10)
swaps are accepted only if leading to the increase of d. The square ‘climbs down’ the
hill and there is probability that next time it starts climbing hill which peaks at global
maximum.
2. Element of chaos– during the hill descending few (ca. 1-3) random swaps occur.
3. Avoiding elitism – not only the best square of generation becomes the parent of a
new generation, but rather certain fraction (e.g.
).
4. Crossover added – offspring is not created from one parent by simple mutation, but
from two parents, which are merged. Random part of offspring square contains
numbers from one parent and the rest from second parent. After merge, multiple
occurrences of certain numbers are removed and replaced by numbers absenting in
the square.
5. Age parameter – if a particular square from the generation gets stuck in local
maximum, instead of hill descending, it is destroyed after surviving through certain
number of generations.
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
16
Hill descending and element of chaos led to real improvement of the algorithm, and I can
conclude that evolutionary algorithm based on hill climbing with these two added
improvements showed best results. The rest of aforementioned improvements showed no
large contribution to the algorithm.
Further possible improvements of avoiding local maxima
I would also like to outline several more approaches of avoiding local maxima I have made
up.
1. Simultaneous searching – many (n) initial squares are generated, and many
independent generations are created. Therefore, there is higher probability that
global maximum will be found. However, the solving time increases, since in every
step4, we have to create n generations instead of one, so the whole process is n times
slower. Although I still think this approach could improve the efficiency algorithm in
large searching spaces5 where the probability of finding the magic square is usually
extremely low.
2. Sudden restart – if a solution is not found within certain time, the whole process is
restarted, a new initial square is generated and the search for magic square starts
again.
3. Parallel processing – if several computers or processor cores were used to look for
magic square simultaneously and independently, the whole process would become
much faster and the probability of finding the magic square would increase.
4.2. Deterministic algorithms
By definition, deterministic algorithm is algorithm which behaviour can be completely
predicted from the input (11). It means that in contrast with probabilistic algorithm,
deterministic one behaves in the same way every time we run it on particular data. I have
tried to design my own backtracking recursive algorithm and gradually have been improving
its efficiency.
4 step (iteration) – creating a new generation from the best member of the current one
5 magic squares of high orders
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
17
Brute Force Recursion
This algorithm creates basis for all further improvements I made. It is based on trying all
arrangements of numbers from 1 to (every number can be filled even more than once) in
the square by simple recursion. After adding last number, algorithm checks whether magic
square has been found, by calculating its total deviation d. Since every number can be filled
into the square more than once, there are ( ) possibilities how to fill in the numbers. E.g.
for square of order 4, there are possibilities, which is an extremely high
number. This algorithm is really inefficient, since every time a number is filled in second
time, it is clear this square will never be magic. However, algorithm keeps exploring all
additional options and thus wastes time.
Each number just once
First improvement I made was that every number from 1 to could be filled exactly once in
the square. Number of all possible arrangements dropped from ( ) to just ( ) , which is
still huge number, but much smaller than the previous one.
End points checks
I thought about whether it was meaningful to continue particular branch of recursion if sum
in any line already does not equal magic sum. To continue such recursion is obviously
unworthy, since no magic square will be found. I have therefore implemented following
improvement. At the end of every line, sum is calculated and the branch of recursion
continues only if this sum equals magic constant. Otherwise algorithms returns one step
back (it ‘backtracks’).
Remembering line’s sums
I soon realized it was quite exhausting to calculate sum at the end of every line, so I added
variables, such as in case of probabilistic algorithm, for remembering actual sums in lines.
These data could be obtained and used in real time, without need of their exhausting
recalculation.
More decision points
Until now, decision points were located only at the end of every line. However, I thought
about whether I could not make decision after every filled number. I created one more array
where I remembered all numbers that had not been yet filled in. This array is being updating
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
18
in real time, according to how recursion keeps filling more numbers or backtracks to
previous steps. According to information in this array, after every filled cell, method
findSmallestSum(int x) for every line containing this cell is called. This function calculates the
smallest possible sum that can be created by summing x free numbers from this array.
Number x is calculated as the difference between the square order and actual position of
filled cell. If actual sum in the line plus findSmallestSum() of this line exceeded magic
constant, algorithm backtracks.
Automatic calculation of end points
There was no need for trying different number at the ends of lines, since these numbers
could be easily calculated as the difference between actual sum of line and magic constant.
Only if such number existed and was free, recursion continued.
Rotation
This improvement is a bit mathematical. I thought about whether it was necessary to try
numbers in the corners (except from the upper left one). If the number ( )
had already been tried in the upper left corner, there was no need to fill it in other corner,
since the square which would be created would be just the rotated square with in upper
left corner. Therefore, we can find just ¼ of all possible magic squares and we are able to
create rest ¾ by rotations of those found.
5. Comparison of algorithms efficiency
In this part I am going to concentrate on comparing the best version of backtracking and
probabilistic algorithm I have developed. Complete codes can be found in appendices. I have
tested6 backtracking algorithm three times for every square order, and the output was the
same every time, as a result of algorithm’s deterministic nature. Probabilistic algorithm has
been tested5 twenty times for every square order and every number of blank cells, every
time with randomly generated prefilled numbers.
6 Algorithms have been written in Java 6 and tested on the same computer with these parameters: Intel(R)
Core(TM) i5 CPU, 2.40 GHz, RAM 4.00 G, Operating system: Windows 7 Home Premium 32-bit
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
19
Following table provides the comparison of these algorithms under criteria I set earlier.
Backtracking Probabilistic algorithm
1. Certainty of finding
solution
Finite time Infinite time
2. Ability to systematically
search for all solutions
Yes No
3. Solving time – first solution See values in Table 2. See values in Table 2.
4. Solving time – all solutions See values in Table 2. -
5. Robustness Both blank square and
square with prefilled values
Both blank square and
square with prefilled values
6. Maximum square order 4 15
Table 1: Comparison of backtracking and probabilistic algorithm under criteria defined from
the beginning of the essay (“-” sign expresses the inability to determine the particular value)
The first advantage of backtracking algorithm is that it is able to find all solutions in finite
time, while probabilistic method does not provide us with certainty of finding solution and
cannot systematically search for all solution. Both algorithms are able to solve both blank
and prefilled squares.
The time of finding first solution and the maximum square order seem to be the most crucial
in comparison of these two algorithms. Backtracking algorithm I have developed is able to fill
in a blank square of maximum order 4. Since this algorithm is based on a recursion, the
number of blank cells is the important value determining how deep the recursion has to go.
Therefore we may tell that this algorithm is able to solve any square which has up to 16
blank cells. Probabilistic algorithm I have designed is able to solve maximum a blank square
of order 15.
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
20
Let us now compare the times that are necessary for these algorithms to solve a blank
square of order 4.
Backtracking Probabilistic algorithm
Time of first solution [s] 0 1
Time of all solution [s] 227 -
Table 2: Comparison of solving times of backtracking and probabilistic algorithm (”-” sign
expresses we were not able to determine this value) on the square of order 4
We see that both backtracking and probabilistic algorithm is really fast for square of order
4x4. Just for quick comparison, I have estimated that pure recursion with ‘Each number just
one’ improvement would solve such square in approximately 2.5 days, and without this
improvement it would take incredible 5800 years7.
Although we are not able to obtain the solving times for higher square orders for
backtracking algorithm, we may predict it would rise quickly, as this algorithm tends to have
factorial complexity (see Figure 2).
7 I have estimated that the computer performs operations per second. With this improvement, there are
operations to be performed, and the computer could handle this task in ca.
. Without the
improvement, there are operations to be performed, and the computer is able to handle this task in ca.
.
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
21
Following table depicts solving times of probabilistic algorithm for blank squares of higher
orders.
Square order Solving time [s]
5 2
6 8
7 14
8 21
9 71
10 30
11 100
12 73
13 67
14 372 ( )
15 2027 ( )
Table 3: Solving times of probabilistic algorithm for squares order 5-15.
Despite this algorithm’s surprising speed, there is one limitation, which has surprised me and
acts as a relevant disadvantage. Following figure shows the rate of success (percentage of
cases when solution has been found) for different numbers of blank cells in square of order
7.
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
22
Figure 4: Rate of success depending on the number of blank cells in the square of order 7.
We see that for numbers of blank cells from 17 to 37 (‘middle area’), the rate of success
gradually decreases and is even 0 % from 25-31. It means that in this area, algorithm is
unsuitable at all since it does not find a solution. I have discussed this problem with
programmer Artur Ejsmont (12), who has offered me a solution I agree with.
“If you add some numbers it will make it harder to find the solution as you throw away most
of the valid answers. If you add enough numbers finding the solution becomes easy again as
there is a lot of fixed data. So I think in the middle there is an area of hard to solve problems
where you don’t have a lot of hints but enough to dismiss most of the valid answers.” (12)
0
10
20
30
40
50
60
70
80
90
100
3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49
Successful cases [%]
Number of blank cells
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
23
6. Conclusion
In the essay I have shown and compared two possible algorithms that could be used for
solving magic square problem. I have also explained the process of how I have been
designing and improving them and outlined some possible improvements that can be
implemented in the future.
Backtracking algorithm has shown itself to be very efficient for squares of low order,
especially for its ability to search systematically for solutions and certainty that it will find
solution. I would say that for such squares backtracking is more suitable than the
probabilistic algorithm. However backtracking is highly time demanding algorithm for
squares of higher order, where probabilistic algorithm shows better results.
Despite probabilistic algorithm’s incapability of finding the solution in the ‘middle area’, I
consider it to be the better choice when solving magic square problem. The most efficient
would be perhaps the combination of using backtracking for few blank cells and in the
‘middle areas’ and probabilistic approach for squares of higher orders.
Regarding the method I used, it could be improved by increasing the number of test cases
for each algorithm, which would make results more accurate and representative. It would be
perhaps also worthy to try implementing parallel processing on multiple computers or using
multiple processor cores, as it could rapidly decrease the time required for finding the
solution.
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
24
7. References
(1) Weisstein, E.W.: "Magic Square." in MathWorld--A Wolfram Web [online] , Retrieved on
November 15, 2011, Available from: http://mathworld.wolfram.com/MagicSquare.html
(2) Roberts, E. and Zelenski, J.: “Chapter 7. Backtracking algorithms” [online], Retrieved on
November 15, 2011 Available from:
http://www-csfaculty.stanford.edu/~eroberts/courses/cs106b/chapters/07-
backtracking-algorithms.pdf
(a) p. 238., para. 1.
(b) p. 237., citation by Weil, S. The New York Notebook, 1942
(3) Meyer, H.B.: “Magic squares 6x6” [online], Retrieved on November 15, 2011 Available
from: http://www.hbmeyer.de/backtrack/mag6en.htm
(4) Paechter, B.: “Evolving a magic square using genetic algorithm” from Napier Edinburgh
University [online], Retrieved on November 15, 2011 Available from:
http://www.soc.napier.ac.uk/~benp/summerschool/jdemos/herdy/magic_problem2.html
(5) Dyer, C.R.: “Genetics algorithms (chapter 4.1.4.)” From University of Wisconsin –
Madison [online], Retrieved on November 15, 2011, Available from:
http://pages.cs.wisc.edu/~dyer/cs540/notes/ga.html
(6) Bolton, D.: “Definition of Brute Force” [online], Retrieved on November 15, 2011,
Available from: http://cplus.about.com/od/glossar1/g/bruteforce.htm
(7) Saha, A.K.: “Hill Climbing: A simple optimization method” [online], on October 4 2011,
Retrieved on November 5, 2011, Available from: http://echorand.me/2010/03/14/hill-
climbing-a-simple-optimization-method/
(8) Weise, T.: “Global Optimization Algorithms –Theory and Application-” [online], on June
26, 2009, Retrieved on November 2, 2011, Available from: http://www.it-
weise.de/projects/book.pdf
(a) p. 26., Figure 1.2.: Global and local optima of a two-dimensional function
(b) p. 25., p. 26, Definitions 1.6, 1.7, 1.8, 1.9, 1.10, 1.11
(c) p. 103., Definition 2.4
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
25
(9) Robertson, J.P.: “Theory of 4x4 Magic Squares” [online], Retrieved on November 7,
2011, Available from: http://www.jpr2718.org/thy4x4.pdf
(10) Ejsmont, A.: “3. SpreadGen (Magic Squares)” [online], in 2004, Retrieved on November
11, 2011, Available from: http://artur.ejsmont.org/blog/content/some-my-college-
projects
(11) Paul E. Black "deterministic algorithm", in Dictionary of Algorithms and Data
Structures [online], Paul E. Black, ed., U.S. National Institute of Standards and
Technology. On 14 January 2009, Retrieved on November 13, 2011, Available
from: http://www.nist.gov/dads/HTML/deterministicAlgorithm.html
(12) Ejsmont, A.: [email protected] (http://artur.ejsmont.org/blog/) [email
communication]
The communication is included in Appendix B
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
26
Appendices
Appendix A – screenshot of found solution of squares of order 14 and 15
Zoomed found square of order 15
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
27
Appendix B: Email communication with Artur Ejsmont
Artur Ejsmont, <[email protected]> September 3, 2011
Recipient me
I dont remember the exact numbers but yes i start with 100 sequences, sort by score, pick 50
best ones. Then i loop, pick one sequence, select randomly what operation do i want to
perform on int (mutation or single replacement or join with another seqence etc). Then i
apply the modification and save it as new sequence. When i fill up to 100 i sort them again.
So i dont have to compare sequence to another i just sort by score.
about the other issue ... dont know man ... maybe it has to do with algorithm not being
able to explore other solutions? Every magic square will have tons and tons of solutions. If
you add some numbers it will make it harder to find the solution as you throw away most
of the valid answers. So you now have to find this one or one of a handful that match. If
you add enough numbers finding the solution becomes easy again as there is a lot of fixed
data. So i think in the middle there is an area of hard to solve problems where you dont
have a lot of hints but enough to dismiss most of the valid answers ;)
hope it helps
art
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
28
Appendix C: Probabilistic Algorithm
There is the best version of probabilistic algorithm I have designed. Javax.swing.Timer and
java.awt.event.* have been imported.
Class Square
public class Square{
public int[][][] a;
public int size;
public int[] row;
public int[] column;
public int diagonalLeft;
public int diagonalRight;
public int deviation;
public boolean[] initialValues;
public int numberOfBlankCells;
public int magicConstant;
public int lastDeviation;
public Square(int n){
size=n;
a=new int [n][n][2];
row=new int[n];
column=new int[n];
diagonalLeft=0;
diagonalRight=0;
initialValues=new boolean[size*size+1];
for (int i=0;i<=size*size;i++) initialValues[i]=false;
magicConstant=(1+size*size)*size/2;
calculateDeviation();
calculateSums();}
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
29
public Square(Square s){
size=s.size;
numberOfBlankCells=s.numberOfBlankCells;
a=new int[size][size][2];
for (int i=0;i<size;i++)
for (int j=0;j<size;j++){
a[i][j][0]=s.a[i][j][0];
a[i][j][1]=s.a[i][j][1];}
row=new int[s.size];
column=new int[s.size];
for (int i=0;i<s.size;i++){
row[i]=s.row[i];
column[i]=s.column[i];}
diagonalLeft=s.diagonalLeft;
diagonalRight=s.diagonalRight;
initialValues=new boolean[s.size*s.size+1];
for(int i=0;i<=s.size*s.size;i++)
initialValues[i]=s.initialValues[i];
magicConstant=s.magicConstant;
deviation=s.deviation;}
public void setInitialValues(int[][] values){
numberOfBlankCells=size*size;
for (int i=0;i<size;i++)
for (int j=0;j<size;j++){
a[i][j][0]=values[i][j];
if (values[i][j]!=0) {
a[i][j][1]=1;
initialValues[values[i][j]]=true;
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
30
numberOfBlankCells--;}}}
public void setSpecificInitialValue(int x,int y,int value) {
a[x][y][0]=value;
a[x][y][1]=1;
initialValues[value]=true;}
public void showSquare(){
for (int i=0;i<size;i++){
for (int j=0;j<size;j++){
if (a[i][j][0]/10==0) System.out.print(" ");
System.out.print(a[i][j][0]+" ");}
System.out.println();}
System.out.println();}
public void nullSquare(){
for (int i=0;i<size;i++)
for (int j=0;j<size;j++){
a[i][j][0]=0;
a[i][j][1]=0;}
for (int i=1;i<=size*size;i++) initialValues[i]=false;
calculateSums();
calculateDeviation();}
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
31
public boolean isMagic(){
if (deviation==0) return true; return false;}
public void calculateSums(){
for (int i=0;i<size;i++){
row[i]=0;
column[i]=0;}
diagonalLeft=0;
diagonalRight=0;
for (int i=0;i<size;i++)
for (int j=0;j<size;j++){
row[i]+=a[i][j][0];
column[j]+=a[i][j][0];
if (i==j) diagonalLeft+=a[i][j][0];
if (i+j==size-1) diagonalRight+=a[i][j][0];}}
public void calculateDeviation(){
deviation=0;
for (int i=0;i<size;i++){
deviation+=Math.abs(magicConstant-row[i]);
deviation+=Math.abs(magicConstant-column[i]);}
deviation+=Math.abs(magicConstant-diagonalLeft);
deviation+=Math.abs(magicConstant-diagonalRight);}
public void fillInMissingNumbers(){
int temp=1;
while (initialValues[temp]) temp++;
for (int i=0;i<size;i++)
for (int j=0;j<size;j++){
if(a[i][j][1]==0){
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
32
a[i][j][0]=temp;
temp++;
if (temp<=size*size)
while (initialValues[temp]){
temp++;
if (temp>size*size) break;}}}
}
Class Generation
public class Generation{
public Square[] generation;
public static int sizeOfGeneration;
public Generation(Square parent){
generation=new Square[sizeOfGeneration];
for (int i=0;i<sizeOfGeneration;i++){
generation[i]=new Square(randomSwap(parent));}}
public Square getBestOffspring(){
int temp=0;
int smallestDeviation=generation[0].deviation;
for (int i=1;i<sizeOfGeneration;i++){
if (generation[i].deviation<smallestDeviation){
temp=i;
smallestDeviation=generation[i].deviation;}}
return generation[temp];}
public Square getWorstOffspring(){
int temp=0;
int largestDeviation=generation[0].deviation;
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
33
for (int i=1;i<sizeOfGeneration;i++){
if (generation[i].deviation>largestDeviation){
temp=i;
largestDeviation=generation[i].deviation;}}
return generation[temp];}
public Square Mutate(){
Generation p=new Generation(this.getWorstOffspring());
for (int i=1;i<=(random(3)+1);i++){
p=new Generation(p.getWorstOffspring()); }
Square s=p.getWorstOffspring();
if (version)
for (int i=1;i<=3;i++)randomSwap(s);
return s;}
public void showGeneration(){
for (int i=0;i<sizeOfGeneration;i++) {
generation[i].showSquare();}}
public static void setSizeOfGeneration(int blankCells){
sizeOfGeneration=200;
// another possibility
sizeOfGeneration=combinatorialNumber(blankCells,2);}
public static int combinatorialNumber(int n,int k) {
if (k>n/2) k=n-k;
int temp=1;
for (int i=n;i>n-k;i--) temp=temp*i;
temp=temp/factorial(k);
return temp;}
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
34
public static int factorial(int n){
int temp=1;
for (int i=n;i>1;i--) temp=temp*i;
return temp;}
public static Square randomSwap(Square s){
Square square=new Square(s);
// Choosing 2 random different cells
int x1,y1,x2,y2;
do{
x1=random(square.size);
y1=random(square.size);
}while (square.a[x1][y1][1]==1);
do{
x2=random(square.size);
y2=random(square.size);
}while (square.a[x2][y2][1]==1 ||
square.a[x2][y2][0]==square.a[x1][y1][0]);
//Swaping two randomly chose cells
/*1st step = Handling correct sums int variables
square.row[], square.column[], square.diagonalLeft and
square.diagonalRight*/
square.row[x1]-=square.a[x1][y1][0];
square.column[y1]-=square.a[x1][y1][0];
square.row[x2]+=square.a[x1][y1][0];
square.column[y2]+=square.a[x1][y1][0];
square.row[x2]-=square.a[x2][y2][0];
square.column[y2]-=square.a[x2][y2][0];
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
35
square.row[x1]+=square.a[x2][y2][0];
square.column[y1]+=square.a[x2][y2][0];
if (x1==y1)
{square.diagonalLeft =square.diagonalLeft-
square.a[x1][y1][0]+square.a[x2][y2][0];}
if (x2==y2)
{square.diagonalLeft =square.diagonalLeft-
square.a[x2][y2][0]+square.a[x1][y1][0];}
if (x1+y1==square.size-1)
{square.diagonalRight=square.diagonalRight-
square.a[x1][y1][0]+square.a[x2][y2][0];}
if (x2+y2==square.size-1)
{square.diagonalRight=square.diagonalRight-
square.a[x2][y2][0]+square.a[x1][y1][0];}
//Calculating correct value of square.deviation
square.calculateDeviation();
//Swap itself
int temp=square.a[x1][y1][0];
square.a[x1][y1][0]=square.a[x2][y2][0];;
square.a[x2][y2][0]=temp;
return square;}
public static int random(int upperBorder){
int temp=(int)(Math.random()*upperBorder);
while(temp==upperBorder)
temp=(int)(Math.random()*upperBorder);
return temp;}
}
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
36
Class PA
public class PA{
public static int time=0;
// This variable remembers the actual total deviation of
the square.
public static int currentDeviation=0;
/*This variable holds the number of identical deviation,
which is important for deciding whether particular square
got stuck in the local maximum.*/
public static int counterOfIdenticalDeviations=0;
/*This is the main method of PA class. First parent is passed
through parameter. This method return number of generations,
if the magic square is found and -1, if the number of
generations exceeds 20000 without finding magic square. It
also keeps track of time elapsed.*/
public static int PA (Square square) {
boolean first=true;
Generation generation;
time=0;
/*Timer is created and started. The time value will later
provide us with information, how quickly the magic square
is found.*/
Timer timer = new Timer(1000,new ActionListener(){
public void actionPerformed (ActionEvent e)
{time++;}});
timer.start();
/*Filling missing numbers (excluding initial values) into
the square - numbers are filled in randomly.*/
square.fillInMissingNumbers();
// Calculating sum of each row, column and diagonal
square.calculateSums();
// Calculating total deviation
square.calculateDeviation();
int temp=1;
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
37
/*The core of PA method - variable temp further acts as
the counter of the generations(generations)*/
while (square.deviation!=0 && temp<20000){
generation=new Generation(square);
/*If the generation is the first, we want to have many
really different members of generations, we do not want
them to differ just in single swap. The piece of code
below does 100 random swaps (taking care of prefilled
numbers) to each member of this first generation.*/
if (first){
for (int I =
0;i<generation.sizeOfGeneration;i++){
for (int j = 1;j <= 100;j++)
generation.generation[i]=Generation.randomSwap(genera
tion.generation[i]);}
first=false;}
/*Square becomes the best square of whole generation. This
square later forms new generation.*/
square=new Square(generation.getBestOffspring());
// This piece of code deals with escaping from local
maximum.
if (square.deviation == currentDeviation){
if (counterOfIdenticalDeviations>5){
square=generation.Mutate();}
else{counterOfIdenticalDeviations++;}
}else{
currentDeviation=square.deviation;
counterOfIdenticalDeviations=0;}
temp++;
}
// End of while
timer.stop();
if (temp==20000) return -1;
return temp;
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
38
}
// End of PA() method
// This method returns random integer number x;
0<=x<upperBorder.
public static int random(int upperBorder){
int temp = (int)(Math.random()*upperBorder);
while(temp==upperBorder)
temp=(int)(Math.random()*upperBorder);
return temp;}
}
Appendix D: Deterministic Algorithm
Java.awt.*, java.awt.event.*, javax.swing.* and java.io.* have been imported.
Class Backtracking
public class Backtracking{
private int[]a;
private int max;
private int length;
private int counter=0;
private Timer timer;
private int time=0;
private int totalSum;
private int sum;
private int tempSum;
private int size;
private boolean check=true;
// Variables improving remembering sums in lines
private int[] column, row;
private int diagonalLeft, diagonalRight;
private int[] corner;
// Variables for method findSmallestSum
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
39
private int[] array;
public Backtracking(int highestNumber,int lengthOfArray){
max=highestNumber;
length=lengthOfArray;
a=new int[length];
timer=new Timer(1000,new ActionListener(){
public void actionPerformed(ActionEvent e){time++;}});
size=(int)(Math.sqrt(length));
totalSum=((1+max)*max)/2;
sum=totalSum/size;
tempSum=0;
corner=new int[max+1];
array=new int[max+1];
for (int i=1;i<=max;i++) array[i]=i;
column=new int[size];
row=new int[size];
diagonalLeft=0;
diagonalRight=0;}
// The core of the backtracking class
private void recursion(int level,String usedOptions){
if (level==length-1){
if (usedOptions.indexOf (" "+(sum-diagonalLeft)+" ")==-1 &&
sum-diagonalLeft>0 && sum-diagonalLeft<=max &&
corner[sum-diagonalLeft]==0) {
a[level]=sum-diagonalLeft;
diagonalLeft+=a[level];
column[size-1]+=a[level];
row[size-1]+=a[level];
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
40
if (column[size-1]==sum && row[size-1]==sum){
counter++;
rotation();}}
}else
if (level==size-1){
if (usedOptions.indexOf(" "+(sum-row[0])+" ")==-1 &&
sum-row[0]>0 && sum-row[0]<=max && corner[sum-row[0]]==0){
a[level]=sum-row[0];
diagonalRight+=a[level];
column[size-1]+=a[level];
row[0]+=a[level];
if(row[0]==sum)
recursion(level+1,usedOptions+a[level]+" ");}
}else
if (level==length-size){
if (usedOptions.indexOf(" "+(sum-column[0])+" ")==-1
&& sum-column[0]>0 && sum-column[0]<=max &&
corner[sum-column[0]]==0){
a[level]=sum-column[0];
diagonalRight+=a[level];
column[0]+=a[level];
row[size-1]+=a[level];
if(diagonalRight==sum)
recursion(level+1,usedOptions+a[level]+" ");}
} else
if (level%size==size-1){
if (usedOptions.indexOf(" "+(sum-row[level/size])+"
")==-1 && sum-row[level/size]>0 && sum-
row[level/size]<=max){
a[level]=sum-row[level/size];
if(level==size-1) diagonalRight+=a[level];
row[level/size]+=a[level];
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
41
column[size-1]+=a[level];
if(row[level/size]==sum)
recursion (level+1,usedOptions+a[level]+" ");}
}else
if (level/size==size-1){
if (usedOptions.indexOf(" "+(sum-
column[level%size])+" ")==-1 && sum-
column[level%size]>0 && sum-column[level%size]<=max){
a[level]=sum-column[level%size];
row[size-1]+=a[level];
column[level%size]+=a[level];
if (column[level%size]==sum)
recursion (level+1,usedOptions+a[level]+" ");}
}else
for (int i=1;i<=max;i++){
if (usedOptions.indexOf(" "+i+" ")==-1){
column[level%size]-=a[level];
row[level/size]-=a[level];
if(level%size==level/size)
diagonalLeft-=a[level];
if(level%size+level/size==size-1)
diagonalRight-=a[level];
if (a[level]!=0)array[a[level]]=a[level];
a[level]=i;
column[level%size]+=i;
row[level/size]+=i;
if (level%size==level/size) diagonalLeft+=i;
if(level%size+level/size==size-1) diagonalRight+=i;
array[a[level]]=0;
check=true;
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
42
if(column[level%size]>sum-findSmallestSum(size-
1-(level/size))) check=false;
if (check)
if(row[level/size]>sum-findSmallestSum(size-1-
(level%size))) check=false;
if (check)
if(diagonalLeft>sum-findSmallestSum(size-1-
(level/size))) check=false;
if (check)
if(diagonalRight>sum-findSmallestSum(size-1-
(level/size))) check=false;
if (check)
if ((level+1)%size==0){
if (row[level/size]!=sum) check=false;}
if (check)
if (level>=length-size){
if (column[level%size]!=sum) check=false;}
if (check)
if (level==length-size){
if (diagonalRight!=sum) check=false;}
if (check) recursion(level+1,usedOptions+i+" ");}
if (level==0) corner[i]=i;
}
column[level%size]-=a[level];
row[level/size]-=a[level];
if (level%size==level/size) diagonalLeft-=a[level];
if (level%size+level/size==size-1)
diagonalRight-=a[level];
if (a[level]!=0) array[a[level]]=a[level];
a[level]=0;}
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
43
private int findSmallestSum(int n){
int temp=0;
int sum=0;
if (temp==n) return temp;
for (int i=1;i<=max;i++){
if (array[i]!=0){
sum+=array[i];
temp++;}
if (temp==n) return sum;}
return sum;}
public void recursionStart(int number){
for (int i=1;i<=number;i++){
counter=0;
time=0;
for (int j=0;j<length;j++) a[j]=0;
for (int j=0;j<length;j++) array[j]=j;
for (int j=0;j<size;j++) column[j]=0;
for (int j=0;j<size;j++) row[j]=0;
diagonalLeft=0;
diagonalRight=0;
timer.start();
recursion(0," ");
timer.stop();
System.out.println("Time (s) = "+time);}}
private void rotation(){
int[][] tempSquare=new int[size][size];
int[] tempArray=a;
int temp=0;
for (int k=1;k<=4;k++){
A comparison of different algorithms for solving magic squares Candidate number: 000771-023
44
temp=0;
for (int j=size-1;j>=0;j--)
for (int i=0;i<size;i++){
tempSquare[i][j]=tempArray[temp];
temp++;}
tempArray=twoTOone(tempSquare);}}
private int[] twoTOone (int[][] temp){
int c=0;
int[]tempArray=new int[size*size];
for (int i=0;i<size;i++)
for (int j=0;j<size;j++){
tempArray[c]=temp[i][j];
c++;}
return tempArray;}
}