如何生成具有排列的矩阵,其中任何 2x2 正方形都有 4 个不同的值?

How to generate a matrix with permutations where any 2x2 square has 4 non-identical values?

假设我的矩阵看起来像这样(总是一个正方形):

a1 a2 a3
b1 b2 b3
c1 c2 c3

我希望正方形 (a1, a2, b1, b2)(a2, a3, b2, b3)etc 中的元素不相似 — 意思是:a1 != a2 != b1 != b2.

我有递归生成矩阵的代码:

def generate(elements):
    if not elements:
        return (),
    final = []
    for items in generate(elements[:-1]):
        for item in elements[-1]:
            final.append(items + (item,))
    return final

def product(*args, repeat=1):
    pools = [list(pool) for pool in args] * repeat
    return list(generate(pools))

def main():
    D = 3
    combinations = product([0, 128, 196], repeat=D)
    matrices = product(combinations, repeat=D)
    return matrices

其中 elements 是整数列表(未知数),假设 [0, 128, 196]repeat 是方阵的大小。

我想在函数的某处应用规则,以便它只会根据我提到的规则生成矩阵。

因此最终结果将是 3x3 矩阵的所有可能变体,但应用了该规则。

宁愿不导入 pandas 或类似的东西。

有一种可能:

  • 使用itertools.permutationsnumpy.reshape生成所有可能的矩阵;
  • 检查矩阵是否适合使用 numpy.diff 来测试相邻元素是否相等。
from more_itertools import distinct_permutations
from numpy import array, diff, count_nonzero

def check_matrix(m):
    d_vert = diff(m, axis=0)                # vertically adjacent
    if count_nonzero(d_vert) < d_vert.size:
        return False
    d_hori = diff(m, axis=1)                # horizontally adjacent
    if count_nonzero(d_hori) < d_hori.size:
        return False
    d_dia1 = d_vert[:,:-1] + d_hori[1:,:]   # northwest-southeast diagonally adjacent
    if count_nonzero(d_dia1) < d_dia1.size:
        return False
    d_dia2 = d_hori[:-1,:] - d_vert[:,:-1]  # southwest-northeast diagonally adjacent
    return count_nonzero(d_dia2) == d_dia2.size

def gen_matrices(h,w, elements):
    for p in distinct_permutations(elements, h*w):
        m = array(p).reshape((h,w))
        if check_matrix(m):
            yield m

for m in gen_matrices(2, 3, [1,2,3,4,1,2]):  # should be 8 results with 3 and 4 in the middle column
    print(m)
# [[1 3 1]
#  [2 4 2]]

# [[1 3 2]
#  [2 4 1]]

# [[1 4 1]
#  [2 3 2]]

# [[1 4 2]
#  [2 3 1]]

# [[2 3 1]
#  [1 4 2]]

# [[2 3 2]
#  [1 4 1]]

# [[2 4 1]
#  [1 3 2]]

# [[2 4 2]
#  [1 3 1]]

文档:

通过添加一个检查每 2 行的新函数解决了这个问题。有点慢,但它有效。

def square_chec(row1, row2):
    if row1[-1] == row2[-1]:
        return False
    for num in range(len(row1)-1):
        if row2[num+1] == row1[num] or row2[num] == row1[num] or row1[num+1] == row2[num] or row2[num] == row1[num]:
            return False
    return True

def generate(elements):
    if not elements:
        return (),
    final = []
    for items in generate(elements[:-1]):
        for item in elements[-1]:
            if items:
                if items[-1] != item:
                    if type(item) == tuple:
                        if square_chec(items[-1], item):
                            final.append(items + (item,))
                    else:
                        final.append(items + (item,))
            else:
                final.append(items + (item,))
    return final