Algorithm 每行和每列有两个非相邻非零的等概率随机平方二元矩阵的算法
如果有人能给我指出一种算法,让我能够:Algorithm 每行和每列有两个非相邻非零的等概率随机平方二元矩阵的算法,algorithm,matrix,random,Algorithm,Matrix,Random,如果有人能给我指出一种算法,让我能够: 创建一个带有条目0和1的随机方阵,以便 每行和每列正好包含两个非零条目 两个非零条目不能相邻 所有可能的矩阵都是等概率的 现在,我通过以下步骤实现了第1点和第2点:这样一个矩阵可以通过适当的行和列排列,转换成一个具有该形式块的对角块矩阵 1 1 0 0 ... 0 0 1 1 0 ... 0 0 0 1 1 ... 0 ............. 1 0 0 0 ... 1 因此,我从这样一个矩阵开始,使用[0,…,n-1]的分区,通过随机排列行和列对其
1 1 0 0 ... 0
0 1 1 0 ... 0
0 0 1 1 ... 0
.............
1 0 0 0 ... 1
因此,我从这样一个矩阵开始,使用[0,…,n-1]的分区,通过随机排列行和列对其进行置乱。不幸的是,我找不到整合邻接条件的方法,而且我很确定我的算法不会平等对待所有矩阵
更新
我已设法达到第3点。答案其实就在我眼前:我正在创建的块矩阵包含了考虑邻接条件所需的所有信息。首先是一些属性和定义:
- 一个合适的矩阵定义了
的排列,可以这样构建:在[1,…,n]
行中选择一个1。包含此条目的列在与1不同的行1
上正好包含一个等于1的其他条目。同样,行a
包含列中的另一个条目1,该列包含行a
上的第二个条目1,依此类推。这将启动一个排列b
1->a->b…
v
1 0 1 0 0 0 | 1
0 1 0 0 0 1 | 2
1 0 0 1 0 0 | 3
0 0 1 0 1 0 | 4
0 0 0 1 0 1 | 5
0 1 0 0 1 0 | 6
------------+--
1 2 3 4 5 6 |
我们得到排列1->3->5->2->6->4->1
- 这种置换的循环导致了我前面提到的块矩阵。我还提到在行和列上使用任意排列对块矩阵进行置乱,以重建符合要求的矩阵
1 1 0 0 0 0 | 1
0 1 1 0 0 0 | 2
1 0 1 0 0 0 | 3
0 0 0 1 1 0 | 4
0 0 0 0 1 1 | 5
0 0 0 1 0 1 | 6
------------+--
1 2 3 4 5 6 |
这里的行1
、2
和3
互不兼容,正如4
、5
和6
一样。随机选择一行,例如3
我们将以数组的形式编写一个排列:[2,5,6,4,3,1]
意思是1->2
,2->5
,3->6
。。。这意味着块矩阵的行2
将成为最终矩阵的第一行,行5
将成为第二行,依此类推
现在,让我们通过随机选择一行来构建一个合适的排列,比如说3
:
p=[3,…]
3
兼容的剩余行中随机选择下一行:4
、5
和6
。假设我们选择4
:
p=[3,4,…]
1
和2
之间进行下一个选择,例如1
:
p=[3,4,1,…]
p=[3,4,1,5,2,6]
将此置换应用于块矩阵,我们得到:
1 0 1 0 0 0 | 3
0 0 0 1 1 0 | 4
1 1 0 0 0 0 | 1
0 0 0 0 1 1 | 5
0 1 1 0 0 0 | 2
0 0 0 1 0 1 | 6
------------+--
1 2 3 4 5 6 |
这样,我们就能够垂直隔离所有非零条目。对列也必须这样做,例如使用排列p'=[6,3,5,1,4,2]
来最终获得
0 1 0 1 0 0 | 3
0 0 1 0 1 0 | 4
0 0 0 1 0 1 | 1
1 0 1 0 0 0 | 5
0 1 0 0 0 1 | 2
1 0 0 0 1 0 | 6
------------+--
6 3 5 1 4 2 |
因此,这似乎非常有效,但构建这些排列需要谨慎,因为人们很容易陷入困境:例如,使用n=6
和分区6=2+2+2
,遵循前面设置的构造规则可能会导致p=[1,3,2,4,
。不幸的是,5
和6
是不兼容的,因此选择其中一个会使最后一个选择变得不可能。我想我已经找到了所有导致死胡同的情况。我将用r
表示剩余选项集:
p=[…,x,,]
,r={y}
与x
和y
不兼容p=[…,x,,?]
,r={y,z}
,其中y
和z
都与x
不兼容(无法选择)p=[…,?,?]
,r={x,y}
与x
和y
不兼容(任何选择都会导致情况1)p=[…,?,?,?]
,r={x,y,z}
与x
,y
和z
循环连续(选择x
或z
将导致情况2,选择y
进入情况3)p=[…,w,,?,?]
,r={x,y,z}
,其中xwy
为3个循环(既不能选择x
也不能选择y
,选择z
将导致情况3)p=[…,?,?,?,?,?]
,r={w,x,y,z}
,其中wxyz
为4个循环(任何选择都会导致情况4)p=[…,?,?,,?,?]
,r={w,x,y,z}
wi
3 0
4 2
5 16
6 722
7 33988
8 2215764
9 179431924
10 17849077140
------------
no sol found
------------
------------
no sol found
------------
------------
no sol found
------------
------------
sol not unique
------------
------------
FOUND
a -> !b
<->
!a v !b (propositional logic)
sum(var_set) <= k
<->
sum(negated(var_set)) >= len(var_set) - k
public static void main(String[] args) throws Exception {
int n = 100;
Random rnd = new Random();
byte[] mat = new byte[n*n];
byte[] colCount = new byte[n];
//generate row by row
for (int x = 0; x < n; x++) {
//generate a random first bit
int b1 = rnd.nextInt(n);
while ( (x > 0 && mat[(x-1)*n + b1] == 1) || //not adjacent to the one above
(colCount[b1] == 2) //not in a column which has 2
) b1 = rnd.nextInt(n);
//generate a second bit, not equal to the first one
int b2 = rnd.nextInt(n);
while ( (b2 == b1) || //not the same as bit 1
(x > 0 && mat[(x-1)*n + b2] == 1) || //not adjacent to the one above
(colCount[b2] == 2) || //not in a column which has 2
(b2 == b1 - 1) || //not adjacent to b1
(b2 == b1 + 1)
) b2 = rnd.nextInt(n);
//fill the matrix values and increment column counts
mat[x*n + b1] = 1;
mat[x*n + b2] = 1;
colCount[b1]++;
colCount[b2]++;
}
String arr = Arrays.toString(mat).substring(1, n*n*3 - 1);
System.out.println(arr.replaceAll("(.{" + n*3 + "})", "$1\n"));
}
package rndsqmatrix;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.IntStream;
public class RndSqMatrix {
/**
* Generate a random matrix
* @param size the size of the matrix
* @return the matrix encoded in 1d array i=(x+y*size)
*/
public static int[] generate(final int size) {
return generate(size, new int[size * size], new int[size],
new int[size]);
}
/**
* Build a matrix recursivly with a random walk
* @param size the size of the matrix
* @param matrix the matrix encoded in 1d array i=(x+y*size)
* @param rowSum
* @param colSum
* @return
*/
private static int[] generate(final int size, final int[] matrix,
final int[] rowSum, final int[] colSum) {
// generate list of valid positions
final List<Integer> positions = new ArrayList();
for (int y = 0; y < size; y++) {
if (rowSum[y] < 2) {
for (int x = 0; x < size; x++) {
if (colSum[x] < 2) {
final int p = x + y * size;
if (matrix[p] == 0
&& (x == 0 || matrix[p - 1] == 0)
&& (x == size - 1 || matrix[p + 1] == 0)
&& (y == 0 || matrix[p - size] == 0)
&& (y == size - 1 || matrix[p + size] == 0)) {
positions.add(p);
}
}
}
}
}
// no valid positions ?
if (positions.isEmpty()) {
// if the matrix is incomplete => return null
for (int i = 0; i < size; i++) {
if (rowSum[i] != 2 || colSum[i] != 2) {
return null;
}
}
// the matrix is complete => return it
return matrix;
}
// random walk
Collections.shuffle(positions);
for (int p : positions) {
// set '1' and continue recursivly the exploration
matrix[p] = 1;
rowSum[p / size]++;
colSum[p % size]++;
final int[] solMatrix = generate(size, matrix, rowSum, colSum);
if (solMatrix != null) {
return solMatrix;
}
// rollback
matrix[p] = 0;
rowSum[p / size]--;
colSum[p % size]--;
}
// we can't find a valid matrix from here => return null
return null;
}
public static void printMatrix(final int size, final int[] matrix) {
for (int y = 0; y < size; y++) {
for (int x = 0; x < size; x++) {
System.out.print(matrix[x + y * size]);
System.out.print(" ");
}
System.out.println();
}
}
public static void printStatistics(final int size, final int count) {
final int sumMatrix[] = new int[size * size];
for (int i = 0; i < count; i++) {
final int[] matrix = generate(size);
for (int j = 0; j < sumMatrix.length; j++) {
sumMatrix[j] += matrix[j];
}
}
printMatrix(size, sumMatrix);
}
public static void checkAlgorithm() {
final int size = 8;
final int count = 2215764;
final int divisor = 122;
final int sumMatrix[] = new int[size * size];
for (int i = 0; i < count/divisor ; i++) {
final int[] matrix = generate(size);
for (int j = 0; j < sumMatrix.length; j++) {
sumMatrix[j] += matrix[j];
}
}
int total = 0;
for(int i=0; i < sumMatrix.length; i++) {
total += sumMatrix[i];
}
final double factor = (double)total / (count/divisor);
System.out.println("Factor=" + factor + " (theory=16.0)");
}
public static void benchmark(final int size, final int count,
final boolean parallel) {
final long begin = System.currentTimeMillis();
if (!parallel) {
for (int i = 0; i < count; i++) {
generate(size);
}
} else {
IntStream.range(0, count).parallel().forEach(i -> generate(size));
}
final long end = System.currentTimeMillis();
System.out.println("rate="
+ (double) (end - begin) / count + "ms/matrix");
}
public static void main(String[] args) {
checkAlgorithm();
benchmark(8, 10000, true);
//printStatistics(8, 2215764/36);
printStatistics(8, 2215764);
}
}
Factor=16.0 (theory=16.0)
rate=0.2835ms/matrix
552969 554643 552895 554632 555680 552753 554567 553389
554071 554847 553441 553315 553425 553883 554485 554061
554272 552633 555130 553699 553604 554298 553864 554028
554118 554299 553565 552986 553786 554473 553530 554771
554474 553604 554473 554231 553617 553556 553581 553992
554960 554572 552861 552732 553782 554039 553921 554661
553578 553253 555721 554235 554107 553676 553776 553182
553086 553677 553442 555698 553527 554850 553804 553444