web-dev-qa-db-ja.com

Matlabのmagic()に相当するNumPy

Ocatave/Matlabでは、 magic() を使用して魔方陣を取得できます。例:

_magic(4)

  16    2    3   13
   5   11   10    8
   9    7    6   12
   4   14   15    1
_

定義:魔方陣は、各行、列、および主対角線のエントリが同じ数(N(N^2+1)/2に等しい)になる数のN×Nグリッドです。

NumPyを使用して同じものを生成するにはどうすればよいですか?

7
Tom Hale

この実装はMatlabの実装に従い、次の例外を除いてまったく同じ結果をもたらすはずです。Matlabのようにn = 2の場合に非魔方陣_[[1, 3], [4, 2]]_を返すのではなく、n <3の場合にエラーをスローします。

いつものように、3つのケースがあります:奇数、4で割り切れる、偶数ですが4で割り切れない、最後のケースが最も複雑です。

_def magic(n):
  n = int(n)
  if n < 3:
    raise ValueError("Size must be at least 3")
  if n % 2 == 1:
    p = np.arange(1, n+1)
    return n*np.mod(p[:, None] + p - (n+3)//2, n) + np.mod(p[:, None] + 2*p-2, n) + 1
  Elif n % 4 == 0:
    J = np.mod(np.arange(1, n+1), 4) // 2
    K = J[:, None] == J
    M = np.arange(1, n*n+1, n)[:, None] + np.arange(n)
    M[K] = n*n + 1 - M[K]
  else:
    p = n//2
    M = magic(p)
    M = np.block([[M, M+2*p*p], [M+3*p*p, M+p*p]])
    i = np.arange(p)
    k = (n-2)//4
    j = np.concatenate((np.arange(k), np.arange(n-k+1, n)))
    M[np.ix_(np.concatenate((i, i+p)), j)] = M[np.ix_(np.concatenate((i+p, i)), j)]
    M[np.ix_([k, k+p], [0, k])] = M[np.ix_([k+p, k], [0, k])]
  return M 
_

これをテストする関数も作成しました。

_def test_magic(ms):
  n = ms.shape[0]
  s = n*(n**2+1)//2 
  columns = np.all(ms.sum(axis=0) == s)
  rows = np.all(ms.sum(axis=1) == s)
  diag1 = np.diag(ms).sum() == s 
  diag2 = np.diag(ms[::-1, :]).sum() == s
  return columns and rows and diag1 and diag2 
_

[test_magic(magic(n)) for n in range(3, 20)]を試して正しいことを確認してください。

5
user6655984

私は同じ問題を抱えていました、これは私が使用したものです:

import numpy as np

matrix = np.random.random((15,15))
for x in range(15):
    for y in range(15):
        matrix[x][y] = int(matrix[x][y]*10)

0〜10の整数が必要でしたが、わかります...

1
Mark

これは、奇数および二重偶数の場合の簡単な実装です。

def magic_odd(n):
    if n % 2 == 0:
        raise ValueError('n must be odd')
    return np.mod((np.arange(n)[:, None] + np.arange(n)) + (n-1)//2+1, n)*n + \
          np.mod((np.arange(1, n+1)[:, None] + 2*np.arange(n)), n) + 1


def magic_double_even(n):
    if n % 4 != 0:
        raise ValueError('n must be a multiple of 4')
    M = np.empty([n, n], dtype=int)
    M[:, :n//2] = np.arange(1, n**2//2+1).reshape(-1, n).T
    M[:, n//2:] = np.flipud(M[:, :n//2]) + (n**2//2)
    M[1:n//2:2, :] = np.fliplr(M[1:n//2:2, :])
    M[n//2::2, :] = np.fliplr(M[n//2::2, :])
    return M

奇妙なケースは ここ からであり、残りは 偶数次の魔方陣を構築する方法 から得ました。それから私は単一の偶数の場合に怠惰になりましたが、考え方は似ています。

1
percusse