The post Project Euler 114 Solution appeared first on Dreamshire.
]]>A row measuring seven units in length has red blocks with a minimum length of three units placed on it, such that any two red blocks (which are allowed to be different lengths) are separated by at least one black square. There are exactly seventeen ways of doing this.
How many ways can a row measuring fifty units in length be filled?
NOTE: Although the example above does not lend itself to the possibility, in general it is permitted to mix block sizes. For example, on a row measuring eight units in length you could use red (3), black (1), and red (4).
For the purpose of this discussion, the unit size of the space into which blocks (red) are placed is identified as n and the unit size of the red blocks, with a range in size from 3 to n, is identified as m. Also, an empty space void of any red blocks is counted.
This is a counting problem, so dynamic programming and its hand maiden linear programming come immediately to mind and usurp the notion of trying a brute-force solution.
And as far as examples go, 7 wasn't the best choice as the problem admits, but it will suffice to answer the problem.
My first analogy was shifting groups of bits in a computer's register, but here's a more festive idea. I looked at this problem like a game of Tetris (Play a game online here). This is a much simpler version as there is only one dropping shape, a "line" with a minimum size of 3 units. Let's look at the example graphic twisted slightly to show my thought process:
The only constraint is that no falling shapes can ever touch; they must be separated by at least one empty space.
As the red blocks fall the only variable is the length of the block, m; between 3 and 7. When we move to n = 8, this same configuration for n = 7 will be a subset of it. Just like n = 6 is a subset of n = 7.
In fact, to demonstrate this concept, lets try to calculate the number of ways we can fill 6 spaces:
How many survived the butchery? Change the variable n in the program to 6 and run it. Did it match your count?
By now, you could add a tile to our graphic and learn the count for 8 spaces. Soon a pattern would become obvious and a dynamic solution is born.
It's just adding a series of numbers for each n as it increase from 3 through 50. Yes, a function (with binomial tendencies) exists out there that would always put to rest a dynamic programming solution for counting, but why spoil the fun.
The post Project Euler 114 Solution appeared first on Dreamshire.
]]>The post Project Euler 139 Solution appeared first on Dreamshire.
]]>Let (a, b, c) represent the three sides of a right angle triangle with integral length sides. It is possible to place four such triangles together to form a square with length c.
For example, (3, 4, 5) triangles can be placed together to form a 5 by 5 square with a 1 by 1 hole in the middle and it can be seen that the 5 by 5 square can be tiled with twenty-five 1 by 1 squares.
However, if (5, 12, 13) triangles were used then the hole would measure 7 by 7 and these could not be used to tile the 13 by 13 square.
Given that the perimeter of the right triangle is less than one-hundred million, how many Pythagorean triangles would allow such a tiling to take place?
The paper "Tiling with Pythagorean Triples" offers a journey through the rough streets of brute forcing to the tranquil avenue of Pell's equation. The following discussion paraphrases this excellent discussion in an effort to summarize my solution.
Using Euclid's formula, the tiling condition can be expressed as:
We can rearrange and group the terms, and define two new variables, to transform the equation:
Since m and n are positive integers, with m > n , it follows from the above that x and y will also be positive integers. Given that, the last version of the tiling condition fits the Pell's equation form of Diophantine equations.
A Diophantine equation is a polynomial equation with the added constraint that only integer solutions are allowed; Pell's equation is a specific form of Diophantine equation.
Jump over to Dario's site and solve the Diophantine equation as:
The post Project Euler 139 Solution appeared first on Dreamshire.
]]>The post Project Euler 231 Solution appeared first on Dreamshire.
]]>The binomial coefficient ^{10}C_{3} = 120. ,
120 = 2^{3} ×3 ×5 = 2 × 2 × 2 × 3 × 5, and 2 + 2 + 2 + 3 + 5 = 14.
So the sum of the terms in the prime factorisation of ^{10}C_{3} is 14.
Find the sum of the terms in the prime factorisation of ^{20000000}C_{15000000}.
Calculating the binomial in this problem and factoring it would take too long so another method had to be discovered.
The paper "Prime Factors of Binomial Coefficients" by Samin Riasat explains Legendre's theorem for finding the prime factors and their exponents for factorials and this extends nicely to binomial coefficients.
An application of Legendre's theorem is to find how many zeros are there at the end of a factorial.
Let's say you want to find the number of zeros at the end of 1000! You just need to find how many times the factors 2 AND 5 (because 2 × 5 = 10) appear in the prime factorization of 1000!. Since 2 factors many more numbers without 5 but is always required with 5 in order to count the zeros we just concern ourselves with 5. To paraphrase the paper:
More generally:
This method was used to solve SPOJ 11 Trailing zeros in a factorial.
Below: Legendre's extension used in the program's loop to calculate the prime's exponent, if it's a factor. Evaluates to either 1 or 0 and then summed:
I wanted to further improve performance and studied Kummer's method for calculating the exponents of the prime factors but it didn't seem like it would make it any faster.
from Euler import prime_sieve
n, r, s = 20000000, 15000000, 0
for p in prime_sieve(n):
pj = p
while pj <= n:
s += p * (n//pj - r//pj - (n - r)//pj)
pj *= p
print "Project Euler 231 Solution =", s
Use this link to get the Project Euler 231 Solution Python 2.7 source.The post Project Euler 231 Solution appeared first on Dreamshire.
]]>The post Project Euler 455 Solution appeared first on Dreamshire.
]]>Let f(n) be the largest positive integer x less than 10^{9} such that the last 9 digits of n^{x} form the number x (including leading zeros), or zero if no such integer exists.
For example:
Find Σf(n), 2 ≤ n ≤ 10^{6}.
Well, just follow the instructions and employ Pypy to get it to run under 1 minute. This is not much different from other problems that deal with large numbers where the pow() function and the third modulus parameter are used.
I should work on improving the algorithm so I wouldn't need Pypy to bail me out of a time constraint. It takes about 67 seconds in Python.
L, s = 1000000, 0
for n in xrange(2, L):
x0, x1 = 0, n
while x0 != x1 and x1:
x0, x1 = x1, pow(n, x0, 10**9)
s += x1
print "Project Euler 455 Solution =", s
Use this link to get the Project Euler 455 Solution Pypy source.The post Project Euler 455 Solution appeared first on Dreamshire.
]]>The post The Parallelogram Law Proven Analytically appeared first on Dreamshire.
]]>Analytic proofs of geometric theorems can often be demonstrated more clearly by the use of coordinates as opposed to synthetic proofs which use deduction from axioms and previously derived theorems.
Prove analytically that the sum of the squares of the four sides of a parallelogram is equal to the sum of the squares of the
diagonals.
In ABCD, let d_{1} and d_{2} be the diagonals AC and BD, respectively. Construct a coordinate system so that A is the origin,
B lies on the positive x axis, and C and D lies above the x axis. See the diagram below. Assume
that AB is equal to DC and AD is equal to BC. We must prove that:
Let x be the x coordinate of B, let C have coordinates (x + x_{0}, y) and D have the coordinates (x_{0}, y). If x_{0} is 0 then the parallelogram is a rectangle.
Firstly, using the distance formula, let's solve for the length of the two diagonals, d_{1} and d_{2}.
Now let's sum the squares of the diagonals:
Secondly, again using the distance formula, let's solve for the length of the two sides AB and AD.
Finally, we want to sum the squares of the sides and multiply by 2 (4 sides total, 2 of each length).
Thus, we have proven that the sum of the squares of the four sides of a parallelogram is equal to the sum of the squares of the diagonals.
The post The Parallelogram Law Proven Analytically appeared first on Dreamshire.
]]>The post How to crack the Ultra Hardware push button lock from Amazon appeared first on Dreamshire.
]]>As Scott points out, this rugged, sturdy lock is secure in looks only. Their claim of thousands of combinations are in fact only 252 and can be compromised in about 5 minutes. Here's his analysis:
I thought I'd warn people that, despite its sturdy feel, it uses relatively weak security. Using it on the gate to the backyard is probably fine, as a deterrent, but using it to protect valuables is a bad idea.
The packaging mistakenly states there are 100,000 possible combinations, while in reality there are many fewer. There are only ten buttons, which can each be depressed once or not. That means there are a total of 2 to the tenth possible combinations, which is only 1024. Worse, since the lock only supports 5 digit combinations, that reduces the total number of possible combinations to 252. That means that if someone tried 30 combinations per minute (2 seconds each), they would necessarily solve it within 8 and a half minutes, and likely within 5 minutes.
Also, the combination is set at the factory and cannot be changed, which isn't a huge deal, but might irritate some, as it prevents you from changing the combination periodically.
After someone commented erroneously that it indeed has 100,000 combinations, Scott continued to explain:
"What you're saying *would* be true *if*:
In other words:
It's like picking lottery numbers -- each number can be picked only once, and the sequence doesn't matter, which intuitively reduces the number of viable combinations. Perhaps surprisingly, it massively reduces them.
Those two facts change the way you have to do the math. Instead of a "permutation with repetition," (or sometimes called "permutation with replacement"), as you suggested, it's really a "combination with no repetition," which you can read about on Wikipedia or other math sources covering "permutation vs. combination." So, instead of 100,000 possible permutations, there really are just 252 combinations.
The equation changes from: 10 to the 5th power, instead to: 10 factorial divided by all of 5 factorial times 5 factorial, which looks something like this:
{0,1,2,3,4} {0,1,2,3,5} {0,1,2,3,6} {0,1,2,3,7} {0,1,2,3,8} {0,1,2,3,9} {0,1,2,4,5} {0,1,2,4,6} {0,1,2,4,7} {0,1,2,4,8} {0,1,2,4,9} {0,1,2,5,6} {0,1,2,5,7} {0,1,2,5,8} {0,1,2,5,9} {0,1,2,6,7} {0,1,2,6,8} {0,1,2,6,9} {0,1,2,7,8} {0,1,2,7,9} {0,1,2,8,9} {0,1,3,4,5} {0,1,3,4,6} {0,1,3,4,7} {0,1,3,4,8} {0,1,3,4,9} {0,1,3,5,6} {0,1,3,5,7} {0,1,3,5,8} {0,1,3,5,9} {0,1,3,6,7} {0,1,3,6,8} {0,1,3,6,9} {0,1,3,7,8} {0,1,3,7,9} {0,1,3,8,9} {0,1,4,5,6} {0,1,4,5,7} {0,1,4,5,8} {0,1,4,5,9} {0,1,4,6,7} {0,1,4,6,8} {0,1,4,6,9} {0,1,4,7,8} {0,1,4,7,9} {0,1,4,8,9} {0,1,5,6,7} {0,1,5,6,8} {0,1,5,6,9} {0,1,5,7,8} {0,1,5,7,9} {0,1,5,8,9} {0,1,6,7,8} {0,1,6,7,9} {0,1,6,8,9} {0,1,7,8,9} {0,2,3,4,5} {0,2,3,4,6} {0,2,3,4,7} {0,2,3,4,8} {0,2,3,4,9} {0,2,3,5,6} {0,2,3,5,7} {0,2,3,5,8} {0,2,3,5,9} {0,2,3,6,7} {0,2,3,6,8} {0,2,3,6,9} {0,2,3,7,8} {0,2,3,7,9} {0,2,3,8,9} {0,2,4,5,6} {0,2,4,5,7} {0,2,4,5,8} {0,2,4,5,9} {0,2,4,6,7} {0,2,4,6,8} {0,2,4,6,9} {0,2,4,7,8} {0,2,4,7,9} {0,2,4,8,9} {0,2,5,6,7} {0,2,5,6,8} {0,2,5,6,9} {0,2,5,7,8} {0,2,5,7,9} {0,2,5,8,9} {0,2,6,7,8} {0,2,6,7,9} {0,2,6,8,9} {0,2,7,8,9} {0,3,4,5,6} {0,3,4,5,7} {0,3,4,5,8} {0,3,4,5,9} {0,3,4,6,7} {0,3,4,6,8} {0,3,4,6,9} {0,3,4,7,8} {0,3,4,7,9} {0,3,4,8,9} {0,3,5,6,7} {0,3,5,6,8} {0,3,5,6,9} {0,3,5,7,8} {0,3,5,7,9} {0,3,5,8,9} {0,3,6,7,8} {0,3,6,7,9} {0,3,6,8,9} {0,3,7,8,9} {0,4,5,6,7} {0,4,5,6,8} {0,4,5,6,9} {0,4,5,7,8} {0,4,5,7,9} {0,4,5,8,9} {0,4,6,7,8} {0,4,6,7,9} {0,4,6,8,9} {0,4,7,8,9} {0,5,6,7,8} {0,5,6,7,9} {0,5,6,8,9} {0,5,7,8,9} {0,6,7,8,9} {1,2,3,4,5} {1,2,3,4,6} {1,2,3,4,7} {1,2,3,4,8} {1,2,3,4,9} {1,2,3,5,6} {1,2,3,5,7} {1,2,3,5,8} {1,2,3,5,9} {1,2,3,6,7} {1,2,3,6,8} {1,2,3,6,9} {1,2,3,7,8} {1,2,3,7,9} {1,2,3,8,9} {1,2,4,5,6} {1,2,4,5,7} {1,2,4,5,8} {1,2,4,5,9} {1,2,4,6,7} {1,2,4,6,8} {1,2,4,6,9} {1,2,4,7,8} {1,2,4,7,9} {1,2,4,8,9} {1,2,5,6,7} {1,2,5,6,8} {1,2,5,6,9} {1,2,5,7,8} {1,2,5,7,9} {1,2,5,8,9} {1,2,6,7,8} {1,2,6,7,9} {1,2,6,8,9} {1,2,7,8,9} {1,3,4,5,6} {1,3,4,5,7} {1,3,4,5,8} {1,3,4,5,9} {1,3,4,6,7} {1,3,4,6,8} {1,3,4,6,9} {1,3,4,7,8} {1,3,4,7,9} {1,3,4,8,9} {1,3,5,6,7} {1,3,5,6,8} {1,3,5,6,9} {1,3,5,7,8} {1,3,5,7,9} {1,3,5,8,9} {1,3,6,7,8} {1,3,6,7,9} {1,3,6,8,9} {1,3,7,8,9} {1,4,5,6,7} {1,4,5,6,8} {1,4,5,6,9} {1,4,5,7,8} {1,4,5,7,9} {1,4,5,8,9} {1,4,6,7,8} {1,4,6,7,9} {1,4,6,8,9} {1,4,7,8,9} {1,5,6,7,8} {1,5,6,7,9} {1,5,6,8,9} {1,5,7,8,9} {1,6,7,8,9} {2,3,4,5,6} {2,3,4,5,7} {2,3,4,5,8} {2,3,4,5,9} {2,3,4,6,7} {2,3,4,6,8} {2,3,4,6,9} {2,3,4,7,8} {2,3,4,7,9} {2,3,4,8,9} {2,3,5,6,7} {2,3,5,6,8} {2,3,5,6,9} {2,3,5,7,8} {2,3,5,7,9} {2,3,5,8,9} {2,3,6,7,8} {2,3,6,7,9} {2,3,6,8,9} {2,3,7,8,9} {2,4,5,6,7} {2,4,5,6,8} {2,4,5,6,9} {2,4,5,7,8} {2,4,5,7,9} {2,4,5,8,9} {2,4,6,7,8} {2,4,6,7,9} {2,4,6,8,9} {2,4,7,8,9} {2,5,6,7,8} {2,5,6,7,9} {2,5,6,8,9} {2,5,7,8,9} {2,6,7,8,9} {3,4,5,6,7} {3,4,5,6,8} {3,4,5,6,9} {3,4,5,7,8} {3,4,5,7,9} {3,4,5,8,9} {3,4,6,7,8} {3,4,6,7,9} {3,4,6,8,9} {3,4,7,8,9} {3,5,6,7,8} {3,5,6,7,9} {3,5,6,8,9} {3,5,7,8,9} {3,6,7,8,9} {4,5,6,7,8} {4,5,6,7,9} {4,5,6,8,9} {4,5,7,8,9} {4,6,7,8,9} {5,6,7,8,9}
UPDATE
Scott has added an efficient way to cycle through the numbers for resolving a correct combination for the Ultra Hardware push button lock. Check out this table that could help crack this lock quickly.
Ultra Hardware push button lock from Amazon
The post How to crack the Ultra Hardware push button lock from Amazon appeared first on Dreamshire.
]]>The post Facebook hiring sample test – Missing Term in an Arithmetic Progression appeared first on Dreamshire.
]]>An Arithmetic Progression(AP) is defined as one in which there is a constant difference between the consecutive terms of a given series of numbers. You are provided with consecutive elements of an Arithmetic Progression. There is however one hitch: Exactly one term from the original series is missing from the set of numbers which have been given to you. The rest of the given series is the same as the original AP. Find the missing term.
The first line contains an Integer N, which is the number of terms which will be provided as input.
This is followed by N consecutive Integers, with a space between each pair of integers. All of these are on one line, and they are in AP (other than the point where an integer is missing).
You are provided with 5 integers. As you can can observe, they have been picked from a series, in which the starting term is 1 and the common difference is 2. The only aberration, i.e. the missing term (7), occurs between 5 and 9. This is the missing element which you need to find.
A_{1} and A_{n} are included and valid.
n = int(raw_input())
a = map(int, raw_input().split())
#n+1 because one element is missing from the series; a is a zero based list
sx = (n+1) * (a[0] + a[n-1]) / 2
#The missing element is the difference between the expected sum and the actual sum
print sx - sum(a)
The post Facebook hiring sample test – Missing Term in an Arithmetic Progression appeared first on Dreamshire.
]]>The post Project Euler 91 Solution appeared first on Dreamshire.
]]>The points P (x_{1}, y_{1}) and Q (x_{2}, y_{2}) are plotted at integer co-ordinates and are joined to the origin, O(0,0), to form ΔOPQ.
There are exactly fourteen triangles containing a right angle that can be formed when each co-ordinate lies between 0 and 2 inclusive; that is,
0 ≤ x_{1}, y_{1}, x_{2}, y_{2} ≤ 2.
Given that 0 ≤ x_{1}, y_{1}, x_{2}, y_{2} ≤ 50, how many right triangles can be formed?
There is a hyper series here...somewhere.
Data Table 1. Number of triangles from 0 ≤ x_{1}, y_{1}, x_{2}, y_{2} ≤ {1..10}.
N | # Triangles |
---|---|
1 | 3 |
2 | 14 |
3 | 33 |
4 | 62 |
5 | 101 |
6 | 148 |
7 | 207 |
8 | 276 |
9 | 353 |
10 | 448 |
Now, we can remove 3n^{2} known triangles that have an edge on either axis.
Data Table 2. Number of triangles as above but with 3n^{2} contributing to sum
N | 3N^{2} | From some other source | # Triangles |
---|---|---|---|
1 | 3 | 0 | 3 |
2 | 12 | 2 | 14 |
3 | 27 | 6 | 33 |
4 | 48 | 14 | 62 |
5 | 75 | 26 | 101 |
6 | 108 | 40 | 148 |
7 | 147 | 60 | 207 |
8 | 192 | 84 | 276 |
9 | 243 | 110 | 353 |
10 | 300 | 148 | 448 |
Data Table 3. Number of triangles as above but with N^{2}/2 contributing to sum
N | 3N^{2} | N^{2}/2 | From some other source | # Triangles |
---|---|---|---|---|
1 | 3 | 0 | 0 | 3 |
2 | 12 | 2 | 0 | 14 |
3 | 27 | 4 | 2 | 33 |
4 | 48 | 8 | 6 | 62 |
5 | 75 | 12 | 14 | 101 |
6 | 108 | 18 | 22 | 148 |
7 | 147 | 24 | 36 | 207 |
8 | 192 | 32 | 52 | 276 |
9 | 243 | 40 | 70 | 353 |
10 | 300 | 50 | 98 | 448 |
Well, brute force until I figure out the series, which seems trivial but so far elusive.
from Euler import gcd
n = 50
t = 0
for x in range(1, n+1):
for y in range(1, n):
m = gcd(x, y)
t += min(x*m/y, m*(n-y)/x)
print 'Project Euler 91 Solution =', t*2 + n*n*3
Use this link to get the Project Euler 91 Solution Python 2.7 source.The post Project Euler 91 Solution appeared first on Dreamshire.
]]>The post Project Euler 301 Solution appeared first on Dreamshire.
]]>Nim is a game played with heaps of stones, where two players take it in turn to remove any number of stones from any heap until no stones remain.
We'll consider the three-heap normal-play version of Nim, which works as follows:
- At the start of the game there are three heaps of stones.
- On his turn the player removes any positive number of stones from any single heap.
- The first player unable to move (because no stones remain) loses.
If (n_{1},n_{2},n_{3}) indicates a Nim position consisting of heaps of size n_{1}, n_{2} and n_{3} then there is a simple function X(n_{1},n_{2},n_{3}) — that you may look up or attempt to deduce for yourself — that returns:
For example X(1,2,3) = 0 because, no matter what the current player does, his opponent can respond with a move that leaves two heaps of equal size, at which point every move by the current player can be mirrored by his opponent until no stones remain; so the current player loses. To illustrate:
- current player moves to (1,2,1)
- opponent moves to (1,0,1)
- current player moves to (0,0,1)
- opponent moves to (0,0,0), and so wins.
For how many positive integers n ≤ 2^{30} does X(n,2n,3n) = 0 ?
Classic use of the Fibonacci sequence. Just find the Fibonacci Number F_{L+2}, where L is the 2's exponent.
from Euler import fibonacci
L = 30 # Limit is expressed as 2^L
print "Project Euler 301 Solution =", fibonacci(L+2)
Use this link to get the Project Euler 301 Solution Python 2.7 source.fibonacci
is listed in Common Functions and Routines for Project EulerThe post Project Euler 301 Solution appeared first on Dreamshire.
]]>The post Panmagic (Pandiagonal) and magic square generation, testing appeared first on Dreamshire.
]]>While working on an idea for maximizing a return on a financial portfolio using magic squares, we though we would share our Python code in case someone else may have some use for it.
import string
def make_magic_square(n):
if n < 1 or n == 2:
return False
if n % 2 == 1:
return make_odd_magic_square(n)
else:
if n % 4 == 0:
return make_even_4n_magic_square(n)
elif (n-2) % 4 == 0:
return make_even_4np2_magic_square(n)
else:
return False
def make_panmagic_square(n):
if n < 4:
return False
if n % 2 == 0:
return make_even_panmagic_square(n)
else:
return make_odd_panmagic_square(n)
def make_odd_magic_square(n):
"""
Source: http://blogs.mathworks.com/cleve/2012/11/05/magic-squares-part-2-algorithms/
This method is called the Siam
Build I and J matrices as follows:
1 1 1 1 1 1 2 3 4 5
2 2 2 2 2 1 2 3 4 5
I=> 3 3 3 3 3 J=> 1 2 3 4 5
4 4 4 4 4 1 2 3 4 5
5 5 5 5 5 1 2 3 4 5
"""
if n < 1 or n%2 == 0: return False #only allow odd squares 2n-1, n>0
J = [range(1, n+1)] * n
I = transpose(J)
"""
Using these indices, we generate two more matrices A and B
A = mod(I + J + (n-3)/2, n)
B = mod(I + 2*J - 2, n)
3 4 0 1 2 1 3 0 2 4
4 0 1 2 3 2 4 1 3 0
A=> 0 1 2 3 4 B=> 3 0 2 4 1
1 2 3 4 0 4 1 3 0 2
2 3 4 0 1 0 2 4 1 3
"""
A = [[(I[i][j] + J[i][j] + (n-3)/2) % n for i in range(n)] for j in range(n)]
B = [[(I[i][j] + 2*J[i][j] - 2) % n for j in range(n)] for i in range(n)]
"""
Both A and B are fledgling magic squares. They have equal row, column and
diagonal sums. But their elements are not the integers from 1 to n^2. Each
has duplicated elements between 0 and n-1. The final statement:
M = n*A + B + 1
produces a matrix whose elements are integers between 1 and n^2 and which
has equal row, column and diagonal sums. What is not obvious, is that
there are no duplicates and includes all of the integers between 1 and n^2
making it a magic square.
"""
return [[n*A[i][j] + B[i][j] + 1 for j in range(n)] for i in range(n)]
def make_even_4np2_magic_square(n):
"""
Source: http://www.math.wichita.edu/~richardson/mathematics/
magic%20squares/even-ordermagicsquares.html
The algorithm starts by partitioning the square into 4 blocks of n/2 each;
one for each quadrant. We fill those blocks with a known odd sized magic
square, A, as: A in Q II, A + (n/2)^2 in Q III, A + 2*(n/2)^2 in Q I, and
A + 3*(n/2)^2 in Q IV.
This maintains the proper column totals, but not the row or diagonal totals.
Correcting row totals is achieved by swaping selective columns (0, 1, 9) of the upper
10x10 matrix with the lower half. The columns affected are 0, 1, 2, ..., k
and n-1, n-2, ... n-k. (k=(n-2)/4)
Example (zero based):
n=6 columns 0
n=10 columns 0, 1, 9
n=14 columns 0, 1, 2, 12, 13
n=18 columns 0, 1, 2, 3, 15, 16, 17
The final step is to switch 2 values in certain columns to correct the diagonals
and make a magic square. (nx-k-1, [k-1, k]) <-> (nx+k, [k-1, k])
Example (zero based):
n=6 (1, 0) <-> (4, 0), (1, 1) <-> (4, 1)
n=10 (2, 1) <-> (7, 1), (2, 2) <-> (7, 2)
n=14 (3, 2) <-> (10, 2), (3, 3) <-> (10, 3)
n=18 (4, 3) <-> (13, 3), (4, 4) <-> (13, 4)
Fill in 4 Quads with 5x5 M.S. Swap upper and lower column sections
17 24 1 8 15 67 74 51 58 65 92 99 1 8 15 67 74 51 58 40
23 5 7 14 16 73 55 57 64 66 98 80 7 14 16 73 55 57 64 41
4 6 13 20 22 54 56 63 70 72 79 81 13 20 22 54 56 63 70 47
10 12 19 21 3 60 62 69 71 53 85 87 19 21 3 60 62 69 71 28
11 18 25 2 9 61 68 75 52 59 86 93 25 2 9 61 68 75 52 34
92 99 76 83 90 42 49 26 33 40 17 24 76 83 90 42 49 26 33 65
98 80 82 89 91 48 30 32 39 41 23 5 82 89 91 48 30 32 39 66
79 81 88 95 97 29 31 38 45 47 4 6 88 95 97 29 31 38 45 72
85 87 94 96 78 35 37 44 46 28 10 12 94 96 78 35 37 44 46 53
86 93 100 77 84 36 43 50 27 34 11 18 100 77 84 36 43 50 27 59
You will see our typical 5 x 5 magic
square in Q II (top left corner)
The finished M.S after the 2 switches
92 99 1 8 15 67 74 51 58 40
98 80 7 14 16 73 55 57 64 41
79 6 88 20 22 54 56 63 70 47
85 87 19 21 3 60 62 69 71 28
86 93 25 2 9 61 68 75 52 34
17 24 76 83 90 42 49 26 33 65
23 5 82 89 91 48 30 32 39 66
4 81 13 95 97 29 31 38 45 72
10 12 94 96 78 35 37 44 46 53
11 18 100 77 84 36 43 50 27 59
"""
nx, k = n/2, (n-2)/4
if n < 6 or nx % 2 == 0: return False #only allow even squares 4n+2, n>1
#make an odd nx x nx magic square
A = make_odd_magic_square(nx)
#fill in each quadrant with an augmentation of A according to algorithm
I = A + sc_add(A, 3*nx*nx)
J = sc_add(A, 2*nx*nx) + sc_add(A, nx*nx)
#create initial square by concatenating I and J - column sums are "magic"
B = [I[i]+J[i] for i in range(n)]
#swap upper and lower halves of specific columns to make row sums "magic"
for j in range(k) + range(n-1, n-k, -1):
for i in range(nx):
B[i][j], B[i+nx][j] = B[i+nx][j], B[i][j]
#switch middle values for 2 columns to make diagonals (and square) magic
B[nx-k-1][k-1], B[nx+k][k-1] = B[nx+k][k-1], B[nx-k-1][k-1]
B[nx-k-1][k], B[nx+k][k] = B[nx+k][k], B[nx-k-1][k]
return B
def make_even_4n_magic_square(n):
"""
Source: http://mathworld.wolfram.com/MagicSquare.html
An elegant method for constructing magic squares of doubly even order n=4m
is to draw Xs through each 4 x 4 subsquare and fill all squares in sequence.
Then replace each entry A[i][j] on a crossed-off diagonal by (n^2+1) - A[i][j]
or, equivalently, reverse the order of the crossed-out entries.
Here is a mask of the crossed out matrix:
1 0 0 1 1 0 0 1
0 1 1 0 0 1 1 0
0 1 1 0 0 1 1 0
1 0 0 1 1 0 0 1
1 0 0 1 1 0 0 1
0 1 1 0 0 1 1 0
0 1 1 0 0 1 1 0
1 0 0 1 1 0 0 1
"""
if n < 4 or n%4: return False #only allow even squares 4n, n>0
c, cms, A = 1, n*n + 1, [[0]*n for i in range(n)]
for i in range(n):
for j in range(n):
A[i][j] = cms-c if i%4 == j%4 or (i+j)%4 == (n-1)%4 else c
c += 1
return A
def make_even_panmagic_square(n):
"""
Description and algorithm from Wikipedia
https://en.wikipedia.org/wiki/Pandiagonal_magic_square
A pandiagonal magic square remains pandiagonally magic not only under
rotation or reflection, but also if a row or column is moved from one
side of the square to the opposite side. As such, an n x n pandiagonal
magic square can be regarded as having 8n^2 orientations.
No (4n+2)x(4n+2) panmagic square exists.
"""
if n < 4 or n%4: return False #only allow 4n even squares
nx = n/2
x = range(1, n+1)
"""
Integrating a few steps into one, compose a matrix as follows:
(example for n=2 (8x8))
[1,2,3,4,8,7,6,5]
[8,7,6,5,1,2,3,4]
...
...
repeat pattern until full, then rotate 90 degrees
"""
A = (x[:nx]+x[:nx-1:-1], x[:nx-1:-1]+x[:nx]) * nx
B = rotate_ccw(A)
"""
Build the final square by multiplying the B square by n, adding
the A square and subtract n from each cell.
Example: A + n x B - n
"""
return [[a + n*b - n for a, b in zip(r1, r2)] for r1, r2 in zip(A, B)]
def make_odd_panmagic_square(n):
#order 6n +/- 1: 5, 7, 11, 13, 17, 19, 23, ...
if n > 4 and (n%6 == 1 or n%6 == 5):
A = [[(j*2 + i) % n + 1 for j in range(n)] for i in range(n)]
#order 6n + 3: 9, 15, 21, 27, ...
elif n > 8 and n%6 == 3:
q, dir = n / 3, 1
B = [[1,2,3],
[5,6,4],
[9,7,8]]
for i in range(10, n, 3):
B.append(range(i, i+3)[::dir])
dir = -dir
A = [[0]*n for i in range(n)]
for i in range(q):
for j in range(3):
t = B[i % q][j % 3]
for k in range(n):
A[(i+k) % n][(j + 3*k) % n] = t
else:
return False
T = transpose(A)
return [[a + n*b - n for a, b in zip(r1, r2)] for r1, r2 in zip(A, T)]
def check_magic_square(matrix, seq=True, mc=0):
"""
seq: Boolean used to restrict the square to having distinct numbers from 1..n^2
mc: Integer to specify a magic constant
A (normal) magic square is a square array(1) of numbers consisting of the distinct
positive integers 1, 2, ..., n^2(2) arranged such that the sum of the
n numbers in any horizontal(3), vertical(4), or main diagonal(5) line is always the
same number (Kraitchik 1942, p. 142; Andrews 1960, p. 1; Gardner 1961, p. 130;
Madachy 1979, p. 84; Benson and Jacoby 1981, p. 3; Ball and Coxeter 1987, p. 193),
known as the magic constant(6)
A square that fails to be magic only because one or both of the main diagonal sums
do not equal the magic constant is called a semimagic square(5)
It is an unsolved problem to determine the number of magic squares of an arbitrary
order, but the number of distinct magic squares (excluding those obtained
by rotation and reflection) of order n=1, 2, 3, ... are 1, 0, 1, 880, 275305224, ...
(Sloane's A006052; Madachy 1979, p. 87).(6)
"""
global err_message
#(6) check for invalid size and shape (non-square)
n = square_size(matrix)
if (n < 1 or n == 2):
err_message = "The array must be square and can't be <1 or 2."
return False
#(1) quick check for a square array
if (not isinstance(matrix[0], (list, tuple)) or
any(len(row) != n for row in matrix)):
err_message = "Must be a square, i.e. the same number of rows and columns."
return False
#(6) calculate the magic constant and working variables
if not mc: mc = n * (n*n + 1) / 2
d1, d2, r, c, a = 0, 0, [0]*n, [0]*n, set()
for i in range(n):
d1, d2 = d1+matrix[i][i], d2+matrix[i][n-i-1]
for j in range(n):
r[i] += matrix[i][j]
c[j] += matrix[i][j]
a.add(matrix[i][j])
#(2) check distinct positive integers 1, 2, ..., n^2
if seq == True and not all(x in a for x in range(1, n*n+1)):
err_message = "The numbers 1 through " + str(n*n) + \
" must appear once and only once in the array."
return False
#(3) check that all horizontal lines equal the magic constant
row_sum = set(r)
if (len(row_sum) != 1 or mc not in row_sum):
err_message = "All the rows didn't add to the magic constant, " + str(mc)
return False
#(4) check that all vertical lines equal the magic constant
col_sum = set(c)
if (len(col_sum) != 1 or mc not in col_sum):
err_message = "All the columns didn't add to the magic constant, " + str(mc)
return False
#(5) check that both diagonal lines equal the magic constant
if (d1 != mc or d2 != mc):
err_message = "One or both diagonals didn't add to the magic constant, " \
+ str(mc) + "\nThis is a semimagic square."
return False
return True
def check_panmagic_square(A):
"""
If all diagonals (including those obtained by wrapping around) of a magic
square sum to the magic constant, the square is said to be a panmagic
square (also called a diabolic square or pandiagonal square). There are no
panmagic squares of order 3 or 4n+2.
"""
n = square_size(A)
if n < 1 or n == 3 or (n-2)%4 == 0: return False
if check_magic_square(A): #make sure A is magic before panmagic test
mc = n * (n*n + 1) / 2 #magic constant
for i in range(n):
s1 = sum(A[(i-j) % n][j] for j in range(n))
s2 = sum(A[(i+j) % n][j] for j in range(n))
if s1 != mc or s2 != mc: return False
return True
return False
def check_associative_square(A):
"""
Reference: https://en.wikipedia.org/wiki/Associative_magic_square
An associative magic square is a magic square for which every pair
of numbers symmetrically opposite to the center sum up to the same
value. There are no associative magic squares of singly-even order.
"""
n = square_size(A)
if n < 1 or n%4 != 0 and n%2 == 0: return False
if check_magic_square(A): #make sure A is magic before associative test
amc = n*n + 1 #associative magic constant
odd_square = n % 2
if all(A[i][j] + A[n-i-1][n-j-1] == amc
for i in range(n) for j in range(n/2 + odd_square)):
return True
return False
def check_bimagic_square(A):
"""
If replacing each number in A with its square produces another magic
square, then the square is said to be a bimagic square (or doubly
magic square).
"""
if check_magic_square(A): #make sure A is magic before bimagic test
n = len(A)
np = n*n
mc = n * (np + 1) * (2*np + 1) / 6 #magic constant
if check_magic_square([[x*x for x in row] for row in A], False, mc):
return True
return False
"""
Basic matrix operations in native Python. Most of the time we simulate
these operations by accessing the matrix in a different order.
"""
def square_size(A):
try:
n = len(A)
except:
return 0
if (not isinstance(A[0], (list, tuple)) or
any(len(row) != n for row in A)):
return 0
return n
def transpose(A):
"""
reflect A over its main diagonal (which runs from top-left to bottom-right)
Example:
1, 2, 3 1, 4, 7
4, 5, 6 => 2, 5, 8
7, 8, 9 3, 6, 9
"""
return [list(a) for a in zip(*A)]
def rotate_cw(A):
"""
rotatet A clockwise (right-turn, -90 degrees)
Example:
1, 2, 3 7, 4, 1
4, 5, 6 => 8, 5, 2
7, 8, 9 9, 6, 3
"""
return [list(a) for a in zip(*A[::-1])]
def rotate_ccw(A):
"""
rotate A counterclockwise (left-turn, 90 degrees)
Example:
1, 2, 3 3, 6, 9
4, 5, 6 => 2, 5, 8
7, 8, 9 1, 4, 7
"""
return [list(a) for a in zip(*A)[::-1]]
def flip(matrix):
"""
flip A over horizontally
Example:
1, 2, 3 7, 8, 9
4, 5, 6 => 4, 5, 6
7, 8, 9 1, 2, 3
"""
return matrix[::-1]
def sc_add(A, n):
"""
Scalar add n to matrix A
"""
return [[x+n for x in row] for row in A]
def print_matrix(matrix):
"""
Source: David Robinson from
http://stackoverflow.com/questions/8747500/pythons-pretty-printing-of-matrix
"""
max_lens = [max([len(str(r[i])) for r in matrix])
for i in range(len(matrix[0]))]
print "\n".join(["".join([string.rjust(str(e), l + 2)
for e, l in zip(r, max_lens)]) for r in matrix])
def demo(A):
if check_magic_square(A):
print_matrix(A)
print "this is a magic square"
else:
print err_message
return False
if check_panmagic_square(A): print "**panmagic"
if check_associative_square(A): print "**associative"
if check_bimagic_square(A): print "**bimagic"
print
def swap_col(A, n, m):
l = len(A)
for i in range(l):
A[i][n], A[i][m] = A[i][m], A[i][n]
return A
def swap_row(A, n, m):
l = len(A)
for i in range(l):
A[n][i], A[m][i] = A[m][i], A[n][i]
return A
"""
n = 4*1
print "4n (doubly even) pandiagonal or panmagic square, n=",n/4
M = make_even_panmagic_square(n)
for x in range(1):
demo(M)
N = rotate_cw(M)
demo(rotate_cw(M))
demo(rotate_cw(rotate_cw(M)))
demo(rotate_ccw(M))
demo(flip(M))
demo(flip(rotate_ccw(M)))
demo(flip(rotate_cw(M)))
demo(flip(rotate_cw(rotate_cw(M))))
M=swap_row(N, 0,1)
M=swap_row(M, 2,3)
"""
n = 7
print "Odd magic square, n=",n
M = make_magic_square(n)
demo(M)
print "Odd panmagic square, 6n+1, 6n+5"
n = 7
M=make_panmagic_square(n)
demo(M)
n = 11
M=make_panmagic_square(n)
demo(M)
print "Odd panmagic square, 6n+3"
n = 9
M=make_panmagic_square(n)
demo(M)
n = 4*2
print "4n (doubly even), magic square, n=",n/4
M = make_magic_square(n)
demo(M)
n = 4*2
print "4n (doubly even) panmagic square, n=",n/4
M = make_panmagic_square(n)
demo(M)
print "8 x 8 bimagic square test check"
T =[[56, 34, 8, 57, 18, 47, 9, 31],
[33, 20, 54, 48, 7, 29, 59, 10],
[26, 43, 13, 23, 64, 38, 4, 49],
[19, 5, 35, 30, 53, 12, 46, 60],
[15, 25, 63, 2, 41, 24, 50, 40],
[ 6, 55, 17, 11, 36, 58, 32, 45],
[61, 16, 42, 52, 27, 1, 39, 22],
[44, 62, 28, 37, 14, 51, 21, 3]]
demo(T)
n=4*2 + 2
print "Even, 4n + 2, magic square, n=",(n-2)/4
M = make_magic_square(n)
demo(M)
print "Even, 4n, square associative test"
T = [[2,13,16,3],
[11,8,5,10],
[7,12,9,6],
[14,1,4,15]]
demo(T)
print "Odd square associative test"
T = [[25,22,5,10,3],
[7,12,11,17,18],
[2,6,13,20,24],
[8,9,15,14,19],
[23,16,21,4,1]]
demo(T)
The post Panmagic (Pandiagonal) and magic square generation, testing appeared first on Dreamshire.
]]>