Python 生成所有可能的二进制矩阵,使每一行和每一列对每个矩阵加起来最多为1
我试图为给定的n生成所有可能的平方二元矩阵,这样: 对于每个二进制矩阵:Python 生成所有可能的二进制矩阵,使每一行和每一列对每个矩阵加起来最多为1,python,algorithm,numpy,matrix,reinforcement-learning,Python,Algorithm,Numpy,Matrix,Reinforcement Learning,我试图为给定的n生成所有可能的平方二元矩阵,这样: 对于每个二进制矩阵: 1) the rows sum up to at most 1 2) the columns sum up to at most 1 例如: 对于n=2,有效矩阵为: [0 0] [0 0] [0 0] [0 1] [0 0] [1 0] [0 1] [0 0] [0 1] [1 0] [1 0] [0 0] [1 0] [0 1] 我需要生成所有这些矩阵 在python中,对于n=k,我现在有下面的蛮力方
1) the rows sum up to at most 1
2) the columns sum up to at most 1
例如:
对于n=2,有效矩阵为:
[0 0]
[0 0]
[0 0]
[0 1]
[0 0]
[1 0]
[0 1]
[0 0]
[0 1]
[1 0]
[1 0]
[0 0]
[1 0]
[0 1]
我需要生成所有这些矩阵
在python中,对于n=k,我现在有下面的蛮力方法
allwords = list(it.product(*([(0, 1)] * (n**2)))) # Generate all possible binary matrices
allarrays = map(np.asarray, allwords) # Convert to array # Convert them toarray
allmatrices = [a.reshape(n, self.n) for a in allarrays] # Matrixify # Make a matrix
# The following checks if the matrix has row sum at most 1 and column sum at most 1
validActions = [x for x in allmatrices if contains(x)] # Final list has only vlaid matrices
包含定义为
def contains(x): # Checks if row and column sums are at most 1 for each entry
colSums = np.sum(x, axis=0)
rowSums = np.sum(x, axis=1)
return (np.all(colSums <= 1) and np.all(rowSums <= 1)) and np.all(x >= 0)
这在n=5或更高的情况下几乎是中断的,所以我需要一种更聪明的方法来做到这一点
目标是最终为强化学习创建一个离散状态空间,并将该离散状态空间中的每个条目映射到一个有效的二进制矩阵。有效的二进制矩阵是具有行和列的每一个矩阵,它们最多相加1。< P>可以考虑递归的解决方案。考虑生成所有这样的NXN矩阵。首先生成顶行:它在某个位置有一个1,或者全是零。对于第一种情况,生成所有可能的n-1xn-1矩阵,然后通过在顶部插入新行,为每个列位置和每个较小的矩阵生成一个nxn矩阵。例如,如果您有子矩阵
0 1
1 0
您可以生成3x3矩阵
1 0 0 0 1 0 0 0 1
0 0 1 0 0 1 0 1 0
0 1 0 1 0 0 1 0 0
通过在顶部插入一行和一个新的额外列
然后,要处理全零行,只需生成所有可能的n-1xn矩阵,并在顶部添加一个零行
从数学上讲,这将生成您想要的所有矩阵 >你可以考虑递归的解决方案。考虑生成所有这样的NXN矩阵。首先生成顶行:它在某个位置有一个1,或者全是零。对于第一种情况,生成所有可能的n-1xn-1矩阵,然后通过在顶部插入新行,为每个列位置和每个较小的矩阵生成一个nxn矩阵。例如,如果您有子矩阵
0 1
1 0
您可以生成3x3矩阵
1 0 0 0 1 0 0 0 1
0 0 1 0 0 1 0 1 0
0 1 0 1 0 0 1 0 0
通过在顶部插入一行和一个新的额外列
然后,要处理全零行,只需生成所有可能的n-1xn矩阵,并在顶部添加一个零行
从数学上讲,这将生成您想要的所有矩阵 这个问题实际上只是一个有nxn个板和m
0->2, 1
Row 2 has a one in column zero since it has an incoming edge from 0
0 0 0
0 0 0
1 0 0
---
0->2->0, 1->1
Row 2 has a one in column 0 since it has an incoming edge from 0
Row 0 has a one in column 2 since it has an incoming edge from 2
Row 1 has a one in column 1 since it has an incoming edge from 1
0 0 1
0 1 0
1 0 0
---
因此,我们将首先将n个数字划分为npart分区。我们需要考虑所有分区。
示例:我们将0、1、2、3划分为两个分区:[0、1、2]、[3]。
我们将允许每个分区形成一个循环或一个路径注意,路径是非循环的。我们需要考虑循环/路径的所有组合。
示例:我们让[0,1,2]形成一个循环,[3]形成一条路径。
我们根据每个分区是循环还是路径来排列它。我们将递归地考虑这一部分来考虑所有的安排。
示例:[0,1,2]只能形成循环0-1-2-0和0-2-1-0。请注意,1-2-0-1与0-1-2-0相同。
示例:如果我们选择[0,1,2]来形成路径的元素,那么所有长度为3的排列都是有效的:即0-1-2,0-2-1,1-0-2,1-2-0,2-0-1,2-1-0。
n=2的输出
n=4给出了32,由给出的解也是如此。
n=8给出1441729,由给出的解也是如此
原始答案不正确,因为仅考虑所有行均为1的情况
这里有一个解决这个问题的方法。首先,我们认识到,您想要的任何矩阵实际上都是单位矩阵的行置换。因此,我们只需要生成n行的所有可能排列,并将每个排列应用于单位矩阵。生成排列的一种方法是使用Heap算法。下面的代码是经过一些修改后无耻地从中摘取的
import numpy as np
def printArr(a):
print('------')
for i in range(n):
for j in range(n):
print(a[i, j],end=" ")
print()
def heapPermutation(a, size, n):
# if size becomes 1 then prints the obtained
# permutation
if (size == 1):
printArr(I[a]) # permute the rows of I
return
for i in range(size):
heapPermutation(a,size-1,n);
# if size is odd, swap first and last
# element
# else If size is even, swap ith and last element
if size&1:
a[0], a[size-1] = a[size-1],a[0]
else:
a[i], a[size-1] = a[size-1],a[i]
n = 3
I = np.identity(n, dtype=int) # use dtype=bool if that is sufficient
a = np.arange(n)
heapPermutation(a, n, n)
结果:
------
1 0 0
0 1 0
0 0 1
------
0 1 0
1 0 0
0 0 1
------
0 0 1
1 0 0
0 1 0
------
1 0 0
0 0 1
0 1 0
------
0 1 0
0 0 1
1 0 0
------
0 0 1
0 1 0
1 0 0
因为我不知道你想对矩阵做什么,所以我选择只打印出来,而不保存它们,虽然保存每一个矩阵可能需要大量的RAM来处理大型n。这个问题实际上只是n x n板和m
0->2, 1
Row 2 has a one in column zero since it has an incoming edge from 0
0 0 0
0 0 0
1 0 0
---
0->2->0, 1->1
Row 2 has a one in column 0 since it has an incoming edge from 0
Row 0 has a one in column 2 since it has an incoming edge from 2
Row 1 has a one in column 1 since it has an incoming edge from 1
0 0 1
0 1 0
1 0 0
---
因此,我们将首先将n个数字划分为npart分区。我们需要考虑所有分区。
示例:我们将0、1、2、3划分为两个分区:[0、1、2]、[3]。
我们将允许每个分区形成一个循环或一个路径注意,路径是非循环的。我们需要考虑循环/路径的所有组合。
示例:我们让[0,1,2]表示
m是一个循环[3]形成一条路径。
我们根据每个分区是循环还是路径来排列它。我们将递归地考虑这一部分来考虑所有的安排。
示例:[0,1,2]只能形成循环0-1-2-0和0-2-1-0。请注意,1-2-0-1与0-1-2-0相同。
示例:如果我们选择[0,1,2]来形成路径的元素,那么所有长度为3的排列都是有效的:即0-1-2,0-2-1,1-0-2,1-2-0,2-0-1,2-1-0。
n=2的输出
n=4给出了32,由给出的解也是如此。
n=8给出1441729,由给出的解也是如此
原始答案不正确,因为仅考虑所有行均为1的情况
这里有一个解决这个问题的方法。首先,我们认识到,您想要的任何矩阵实际上都是单位矩阵的行置换。因此,我们只需要生成n行的所有可能排列,并将每个排列应用于单位矩阵。生成排列的一种方法是使用Heap算法。下面的代码是经过一些修改后无耻地从中摘取的
import numpy as np
def printArr(a):
print('------')
for i in range(n):
for j in range(n):
print(a[i, j],end=" ")
print()
def heapPermutation(a, size, n):
# if size becomes 1 then prints the obtained
# permutation
if (size == 1):
printArr(I[a]) # permute the rows of I
return
for i in range(size):
heapPermutation(a,size-1,n);
# if size is odd, swap first and last
# element
# else If size is even, swap ith and last element
if size&1:
a[0], a[size-1] = a[size-1],a[0]
else:
a[i], a[size-1] = a[size-1],a[i]
n = 3
I = np.identity(n, dtype=int) # use dtype=bool if that is sufficient
a = np.arange(n)
heapPermutation(a, n, n)
结果:
------
1 0 0
0 1 0
0 0 1
------
0 1 0
1 0 0
0 0 1
------
0 0 1
1 0 0
0 1 0
------
1 0 0
0 0 1
0 1 0
------
0 1 0
0 0 1
1 0 0
------
0 0 1
0 1 0
1 0 0
因为我不知道你想对矩阵做什么,所以我选择只打印出来,而不保存它们,虽然保存每个矩阵可能需要大量的RAM以获得较大的n。下面是另一种方法,它基于itertools在^2空间生成所有这样的矩阵。排列:
以下是另一种基于itertools.permutations在^2空间生成所有此类矩阵的方法:
请注意,该数字随n呈指数增长:请参阅每个n有多少个矩阵的列表。是的,绝对是。我想,我主要是需要它为n=5/6工作。我只是想确保没有一种方法可以做到这一点,这样我就不会产生所有可能的结果,然后再减少它。我想这就是为什么现在这么慢的原因。请注意,这个数字随n呈指数增长:请参阅每个n有多少个矩阵的列表。是的,绝对是这样。我想,我主要是需要它为n=5/6工作。我只是想确保没有一种方法可以做到这一点,这样我就不会产生所有可能的结果,然后再减少它。我想这就是为什么现在速度变慢的原因。在你的例子中,行和列的总和都是1。OP要求最多1。修复了该解决方案。示例中的行和列总计为1。OP要求最多1。修复了解决方案。这是否解决了总和最多为1的规定?是的。每次在顶部插入新行时,也会插入只有一个1的列,因此在任何行或列中都不会有多个1。我还使用这种递归策略来生成这种形式的矩阵数量,并将其与OEIS序列进行匹配。这似乎很难理解。你能通过一个小例子来详细说明算法吗?这是否解决了求和最多为1的规定?是的。每次在顶部插入新行时,也会插入只有一个1的列,因此在任何行或列中都不会有多个1。我还使用这种递归策略来生成这种形式的矩阵数量,并将其与OEIS序列进行匹配。这似乎很难理解。你能通过一个小例子详细说明一下算法吗?