C
这是一个有效的答案,并且比Haskell显着提高了内存效率。不幸的是,我的计算机仍然太慢,无法在任何合理的时间内达到优于14/8的水平。
尝试gcc -std=c99 -O2 -fopenmp -o matrices.exe matrices.c
使用matrices.exe width height
或类似版本进行编译并运行。输出是一个整数,该整数的位构成所讨论矩阵的基础,例如:
$ matrices.exe 8 14
...
valid i: 1650223
然后,由于1650223 = 0b110010010111000101111
,所讨论的矩阵为:
0 0 1 1 1 0 1 0 0 1 0 0 1 1
0 ...
1 ...
0
1
1
1
1
如果某人拥有8个核心并且有时间,可以将其运行一会儿,我认为可能会带来一些好处:)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
/*
* BEGIN WIKIPEDIA CODE
*/
const long long m1 = 0x5555555555555555; //binary: 0101...
const long long m2 = 0x3333333333333333; //binary: 00110011..
const long long m4 = 0x0f0f0f0f0f0f0f0f; //binary: 4 zeros, 4 ones ...
const long long m8 = 0x00ff00ff00ff00ff; //binary: 8 zeros, 8 ones ...
const long long m16 = 0x0000ffff0000ffff; //binary: 16 zeros, 16 ones ...
const long long m32 = 0x00000000ffffffff; //binary: 32 zeros, 32 ones
const long long hff = 0xffffffffffffffff; //binary: all ones
const long long h01 = 0x0101010101010101; //the sum of 256 to the power of 0,1,2,3...
//This uses fewer arithmetic operations than any other known
//implementation on machines with fast multiplication.
//It uses 12 arithmetic operations, one of which is a multiply.
long long hamming(long long x) {
x -= (x >> 1) & m1; //put count of each 2 bits into those 2 bits
x = (x & m2) + ((x >> 2) & m2); //put count of each 4 bits into those 4 bits
x = (x + (x >> 4)) & m4; //put count of each 8 bits into those 8 bits
return (x * h01)>>56; //returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ...
}
/*
* END WIKIPEDIA CODE
*/
int main ( int argc, char *argv[] ) {
int height;
int width;
sscanf(argv[1], "%d", &height);
sscanf(argv[2], "%d", &width);
#pragma omp parallel for
for (
/*
* We know that there are 2^(h+w-1) T-matrices, defined by the entries
* in the first row and first column. We'll let the long long i
* represent these entries, with 1s represented by set bits.
*
* The first (0) and last (1) matrix we will ignore.
*/
long long i = 1;
i < (1 << (height+width-1))-1;
i++
) {
// Flag for keeping track as we go along.
int isvalid = 1;
/*
* Start by representing the matrix as an array of columns, with each
* non-zero matrix entry as a bit. This allows us to construct them and
* check equality very quickly.
*/
long *cols = malloc(sizeof(long)*width);
long colmask = (1 << height)-1;
for (int j = 0; j < width; j++) {
cols[j] = (i >> j) & colmask;
if (cols[j] == 0) {
//check no zero rows
isvalid = 0;
} else {
//check no duplicate rows
for (int k = 0; k < j; k++) {
if (cols[j] == cols[k]) {
isvalid = 0;
}
}
}
}
if (isvalid == 1) {
/*
* We'll also represent the matrix as an array of rows, in a
* similar manner.
*/
long *rows = malloc(sizeof(long)*height);
long rowmask = (1 << width)-1;
for (int j = 0; j < height; j++) {
rows[j] = (i >> j) & rowmask;
}
int *sums[(1 << width)];
for (long j = 0; j < 1<<width; j++) {
sums[j] = (int*)malloc(sizeof(int)*height);
}
for (
/*
* The powerset of columns has size 2^width. Again with the
* long; this time each bit represents whether the
* corresponding row is a member of the subset. The nice thing
* about this is we can xor the permutation with each row,
* then take the hamming number of the resulting number to get
* the sum.
*/
long permutation = 1;
(isvalid == 1) && (permutation < (1 << width)-1);
permutation ++
) {
for (int j = 0; j < height; j++) {
sums[permutation][j] = hamming( rows[j] & permutation);
}
for (int j = permutation-1; (isvalid == 1) && (j > -1); j--) {
if (memcmp(sums[j], sums[permutation], sizeof(int)*height) == 0) {
isvalid = 0;
}
}
}
for (long j = 0; j < 1<<width; j++) {
free(sums[j]);
}
free(rows);
}
if (isvalid == 1) {
printf ("valid i: %ld\n", i);
}
free(cols);
}
return 0;
}