1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 r"""
18 *Simple operations with magic squares.*
19
20 **Prerequisites:**
21 - NumPy_
22
23 **Functions:**
24 - `ismagic(A)` -- test whether *A* is a magic square.
25 - `magic(N)` -- create an *N* by *N* magic square.
26 - `magic_constant(A)` -- calculate the magic constant of *A*.
27
28 **Examples:**
29 >>> from magic_square import *
30 >>> print magic(3)
31 [[8 1 6]
32 [3 5 7]
33 [4 9 2]]
34 >>> magic_constant()
35 15
36 >>> ismagic(magic(4))
37 True
38 >>> magic_constant()
39 34
40 >>> magic_constant([1, 1, 1, 1])
41 2
42 >>> ismagic([[1, 2], [3, 4]])
43 False
44
45 **Notes:**
46 (1) Function `magic(N)` produces the same magic squares as Matlab
47 and Octave command ``magic(N)``. The speed of calculations for *N*
48 close to 1000 is about 100--200 times faster than in Octave.
49
50 (2) Integer arithmetic in NumPy_ is done modulo ``2**32``. That
51 can give a false positive in `ismagic(A)` for integer arrays with
52 overflowing in row, column, or diagonal sums. To avoid that and to
53 avoid wrong answers in `magic_constant(A)`, in such cases the
54 array's ``dtype`` should be changed to ``'int64'``, or if
55 ``'int64'`` also overflows, to ``'object'``.
56
57 **Screenshots:**
58
59 That's how it looks in SAGE_:
60
61 |SAGE|
62
63 And that's how it looks in IDLE_:
64
65 |IDLE|
66
67 **Author:**
68 `Alec Mihailovs`_ <alec@mihailovs.com>
69
70 **Last Updated:**
71 February 22, 2007.
72
73 .. _NumPy: http://www.scipy.org/Download
74
75 .. _SAGE: http://sage.math.washington.edu/sage/
76
77 .. _IDLE: http://www.python.org/idle/
78
79 .. |SAGE| image:: sage.png
80
81 .. |IDLE| image:: idle.png
82
83 .. _`Alec Mihailovs`: http://mihailovs.com/Alec/
84 """
85
86 __version__ = "0.2"
87 """Development Status :: 3 - Alpha"""
88
89 __author__ = "Alec Mihailovs <alec@mihailovs.com>"
90 """
91 `Alec Mihailovs`_ <alec@mihailovs.com>
92
93 .. _`Alec Mihailovs`: http://mihailovs.com/Alec/
94 """
95
96 __docformat__ = "restructuredtext"
97 """http://docutils.sourceforge.net/rst.html"""
98
99 from numpy import arange, asarray, flipud, r_, tile
100 from math import sqrt
101
102 _constant = None
103 """Last calculated magic constant."""
104
106 r"""
107 Test whether the given array is a magic square.
108
109 **Input:**
110 *A* -- 2D array, or a sequence that can be interpreted as such.
111
112 **Output:**
113 ``bool`` or ``NotImplementedType`` -- ``True`` if *A* is a
114 magic square, ``NotImplemented`` if the number of dimensions of
115 *A* is not 2 or 1, or the size is not a perfect square in the
116 1D case, and ``False`` otherwise.
117
118 **Examples:**
119 >>> from magic_square import *
120 >>> ismagic(magic(3))
121 True
122 >>> ismagic([1, 1, 1, 1])
123 True
124 >>> ismagic([[8, 1, 6], [3, 5, 7], [4, 9, 2]])
125 True
126 >>> ismagic(1) # 0 dimensions
127 NotImplemented
128 >>> ismagic('[[1]]') # a string gives 0 dimensions
129 NotImplemented
130 >>> ismagic([[[1]]]) # 3 dimensions
131 NotImplemented
132 >>> ismagic(array([[1, 2], [3, 4]]))
133 False
134
135 **Notes:**
136 Integer arithmetic in NumPy_ is done modulo ``2**32`` as in the
137 following example:
138
139 >>> from numpy import array
140 >>> array([2**16])
141 array([65536])
142 >>> _*_
143 array([0])
144
145 That can give a false positive in `ismagic(A)` for integer
146 arrays with overflowing in row, column, or diagonal sums.
147 To avoid that, in such cases the array's ``dtype`` should be
148 changed to either ``'int64'``, or ``'object'``, see
149 `magic_constant(A)` Notes.
150
151 .. _NumPy: http://www.scipy.org/Download
152 """
153 global _constant
154 _constant = None
155 a = asarray(A)
156 if a.ndim == 2:
157 m = flipud(a).trace()
158 t = (r_[a.sum(axis=0), a.sum(axis=1), a.trace()] == m).all()
159 if t == True:
160 _constant = m
161 return True
162 else:
163 return False
164 elif a.ndim == 1:
165 s = sqrt(a.size)
166 if a.size == s*s:
167 return ismagic(a.reshape(s,s))
168 else:
169 return NotImplemented
170 else:
171 return NotImplemented
172
174 r"""
175 Magic constant of the magic square.
176
177 **Input:**
178 *A* -- 2D array, or a sequence that can be interpreted as such.
179 If not entered, the last constructed `magic(n)` or last array
180 *A* tested in `ismagic(A)` is used.
181
182 **Output:**
183 ``dtype`` of the array, or Python ``long``, or ``NoneType`` --
184 the magic constant if the array is a magic square, or ``None``
185 otherwise. Python ``long`` can occur if *A* is ``None`` and the
186 magic constant is calculated for the last constructed
187 `magic(n)` with large *n*.
188
189 **Examples:**
190 >>> from magic_square import *
191 >>> magic_constant([1, 1, 1, 1])
192 2
193 >>> print magic_constant([1, 2, 3, 4])
194 None
195 >>> ismagic(magic(6))
196 True
197 >>> magic_constant()
198 111
199 >>> a = magic(5000)
200 >>> magic_constant()
201 62500002500L
202
203 **Notes:**
204 Integer arithmetic in NumPy_ is done modulo ``2**32``. That
205 makes `magic_constant(A)` to return wrong answers for integer
206 arrays with overflowing in row, column, or diagonal sums. For
207 example,
208
209 >>> magic_constant(magic(5000))
210 -1924506940
211 >>> ismagic(magic(5000))
212 True
213 >>> magic_constant()
214 -1924506940
215
216 Note that
217
218 >>> 62500002500L % 2**32 == -1924506940 % 2**32
219 True
220
221 To avoid such wrong answers, the array's ``dtype`` can be
222 changed to ``'int64'``, or if ``'int64'`` also overflows, to
223 ``'object'`` (that one significantly slows down the
224 calculations.) In this example,
225
226 >>> from numpy import array
227 >>> magic_constant(array(magic(5000), dtype='int64'))
228 62500002500
229 >>> magic_constant(array(magic(5000), dtype='object')) # long
230 62500002500L
231
232 .. _NumPy: http://www.scipy.org/Download
233 """
234 if A is None or ismagic(A) is True:
235 return _constant
236
238 r"""
239 Create an *N* by *N* magic square.
240
241 **Input:**
242 *N* -- an integer in some form, may be float or quotted.
243
244 **Output:**
245 an ``'int32'`` *N* by *N* array -- the same magic square as in
246 Matlab and Octave ``magic(N)`` commands. In particular, the
247 Siamese method is used for odd *N* (but with a different
248 implementation.)
249
250 **Examples:**
251 >>> from magic_square import *
252 >>> magic(4)
253 array([[16, 2, 3, 13],
254 [ 5, 11, 10, 8],
255 [ 9, 7, 6, 12],
256 [ 4, 14, 15, 1]])
257 >>> magic_constant()
258 34
259 >>> magic(5.0) # can be float
260 array([[17, 24, 1, 8, 15],
261 [23, 5, 7, 14, 16],
262 [ 4, 6, 13, 20, 22],
263 [10, 12, 19, 21, 3],
264 [11, 18, 25, 2, 9]])
265 >>> print magic('6') # can be quotted
266 [[35 1 6 26 19 24]
267 [ 3 32 7 21 23 25]
268 [31 9 2 22 27 20]
269 [ 8 28 33 17 10 15]
270 [30 5 34 12 14 16]
271 [ 4 36 29 13 18 11]]
272 >>> magic(2) # consistent with Octave
273 Traceback (most recent call last):
274 TypeError: No such magic squares exist.
275 >>> magic(0)
276 array([], shape=(0, 0), dtype=int32)
277 >>> magic_constant() # the empty sum is 0
278 0
279
280 **Notes:**
281 The calculations for *n* close to 1000 are about 100--200
282 times faster than in Octave.
283 """
284 global _constant
285 n = int(N)
286 if n < 0 or n == 2:
287 raise TypeError("No such magic squares exist.")
288 elif n%2 == 1:
289 m = n>>1
290 b = n*n + 1
291 _constant = n*b>>1
292 return (tile(arange(1,b,n),n+2)[m:-m-1].reshape(n,n+1)[...,1:]+
293 tile(arange(n),n+2).reshape(n,n+2)[...,1:-1]).transpose()
294 elif n%4 == 0:
295 b = n*n + 1
296 _constant = n*b>>1
297 d=arange(1, b).reshape(n, n)
298 d[0:n:4, 0:n:4] = b - d[0:n:4, 0:n:4]
299 d[0:n:4, 3:n:4] = b - d[0:n:4, 3:n:4]
300 d[3:n:4, 0:n:4] = b - d[3:n:4, 0:n:4]
301 d[3:n:4, 3:n:4] = b - d[3:n:4, 3:n:4]
302 d[1:n:4, 1:n:4] = b - d[1:n:4, 1:n:4]
303 d[1:n:4, 2:n:4] = b - d[1:n:4, 2:n:4]
304 d[2:n:4, 1:n:4] = b - d[2:n:4, 1:n:4]
305 d[2:n:4, 2:n:4] = b - d[2:n:4, 2:n:4]
306 return d
307 else:
308 m = n>>1
309 k = m>>1
310 b = m*m
311 d = tile(magic(m), (2,2))
312 _constant = _constant*8 - n - m
313 d[:m, :k] += 3*b
314 d[m:,k:m] += 3*b
315 d[ k, k] += 3*b
316 d[ k, 0] -= 3*b
317 d[m+k, 0] += 3*b
318 d[m+k, k] -= 3*b
319 d[:m,m:n-k+1] += b+b
320 d[m:,m:n-k+1] += b
321 d[:m, n-k+1:] += b
322 d[m:, n-k+1:] += b+b
323 return d
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373