/* Program to take a list of test vectors of nonnegative integers (specifying the entropies of all nonempty combinations of a given number of random variables), and try to determine whether the vectors are linearly realizable (over the reals, or over all sufficiently large finite fields); the output of the program is the list of vectors for which it could _not_ make this determination (plus further information about successful realizations if preprocessor variable VERBOSE is set) [Note: the program may not work correctly if given input vectors that do not satisfy the Shannon inequalities] */ #include #include #include /* The number of random variables to work with */ #define NVAR 6 /* The factorial of NVAR (verified later) */ #define NVARFACT 720 /* Two to the power NVAR */ #define TWOTONVAR (1 << NVAR) /* The permutations on TWOTONVAR combined variables induced by the NVARFACT permutations of NVAR original random variables */ int permarray[NVARFACT][TWOTONVAR]; /* A list of linear rank inequalities to be assumed as known (including the trivial zero inequality as a terminator) */ int knownineqs[][TWOTONVAR] = { {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}}; /* The number of known inequalities (including the trivial one */ #define NKI (sizeof(knownineqs)/(TWOTONVAR*sizeof(int))) #define MAXPROOF 10000 int main(int argc, char **argv) { int i,j,k,m,n,jj,ii; int v[TWOTONVAR]; /* The current input vector to be tested for linear realizability */ int mark[TWOTONVAR]; /* For a particular value of k (a power of 2), the value of mark[i] for i <= k is initially pv[i] (pv is a permuted version of v) but is gradually decreased as vectors are selected and "used up" (actually modded out by) */ int scr[TWOTONVAR]; /* For k as above, the value of scr[i] is initially pv[i+k]-pv[i] (i.e., the amount that the new random variable should augment the dimension of subspace i) but is gradually decreased as vectors are allocated to the new random variable */ int scr2[TWOTONVAR]; /* Initially a saved copy of the mark[] array, but then is used as an array of pairs of bits. If we are trying to adjoin an additional vector to the new random variable, scr2[i]&1 is set when it is determined that the additional vector must be in subspace i, and scr2[i]&2 is set when it is determined that the additional vector must not be in subspace i. */ char buffer[20000]; /* An input buffer for the test vectors */ int perm[NVAR]; /* The current permutation of the original random variables (represented as bit masks -- (1<>1] & n) continue; prooflen = 0; #if defined(VERBOSE) printf("Start\n"); #endif for (k = 1; k < TWOTONVAR; k <<= 1) { savedprooflen = prooflen; #if defined(VERBOSE) if (permarray[m][k] <= 32) printf(" %c:\n", "xABxCxxxDxxxxxxxExxxxxxxxxxxxxxxF"[permarray[m][k]]); #endif #if defined(ALTERNATIVE1) j = -1; for (jx = (k == TWOTONVAR/2)?1:(k-1); jx < k; jx++) { if (k == TWOTONVAR/2) { if (v[permarray[m][k+jx]] - v[permarray[m][jx]] == v[permarray[m][k]] - v[permarray[m][0]]) continue; for (i = 1; i <= jx; i <<= 1) { if ((jx & i) == i && v[permarray[m][k+(jx^i)]] - v[permarray[m][jx^i]] < v[permarray[m][k]] - v[permarray[m][0]]) break; } if (i <= jx) continue; } for (jjx = (k == TWOTONVAR/2)?jx+1:(k-1); jjx < k; jjx++) { if (k == TWOTONVAR/2) { if (v[permarray[m][k+jjx]] - v[permarray[m][jjx]] == v[permarray[m][k]] - v[permarray[m][0]]) continue; for (i = 1; i <= jjx; i <<= 1) { if ((jjx & i) == i && v[permarray[m][k+(jjx^i)]] - v[permarray[m][jjx^i]] < v[permarray[m][k]] - v[permarray[m][0]]) break; } if (i <= jjx) continue; #if defined(VERBOSE) printf(" substart\n"); #endif changej = 1; prooflen = savedprooflen; } #endif /* Set up the mark[] and scr[] arrays to respectively the sizes of the subspaces from the previous random variables and the amount that these should be augmented when the new random variable is adjoined */ for (i = 0; i < k; i++) { mark[i] = v[permarray[m][i]]; scr[i] = v[permarray[m][k+i]] - mark[i]; } if (prooflen + 1 + scr[0] > MAXPROOF) { printf("ERROR: proof too long\n"); exit(1); } for ( ; ; ) { #if defined(VERBOSE) // for (i = 0; i < k; i++) printf("%d ",mark[i]); // printf("\n"); // for (i = 0; i < k; i++) printf("%d ",scr[i]); // printf("\n"); #endif /* Select a value of j such that we will try to adjoin a generic vector from subspace j to the new random variable (checking to see that certain contradictions have not yet been reached) */ j = k; jj = mark[k-1] + scr[0] + 1; for (i = 1; i < k; i++) { if ((scr[i] > scr[0]) || (scr[i] < 0)) { j = -1; break; } if ((scr[i] < scr[0]) && (mark[i]+scr[i] < jj)) { j = i; jj = mark[j]; } } #if defined(VERBOSE) // printf(" %d\n",j); #endif if ((j == -1) || (j == k)) break; #if defined(ALTERNATIVE1) if (changej) j = jx; #endif if (mark[j] <= 0) break; proof[prooflen++] = j; #if defined(VERBOSE) printf(" %d",j); #endif jj = k; /* Update the mark[] and scr[] arrays to reflect removal of (actually modding out by) the generic vector; if it looks as though there is a problem, select a second subspace jj to work with; save the old mark[] array in scr2[] */ for (i = 0; i < k; i++) { scr2[i] = mark[i]; if (mark[i|j] > mark[i]) { scr[i]--; if (scr[i] < scr[i|j]) { if (jj == k || mark[i] < mark[jj]) jj = i; } } else mark[i]--; } #if defined(ALTERNATIVE1) if (changej) jj = jjx, changej = 0; #endif if (jj < k) { proof[prooflen-1] += jj*k; #if defined(VERBOSE) printf(" %d",jj); #endif /* Forget the generic vector from subspace j, and restore the preceding mark[] and scr[] arrays */ for (i = 0; i < k; i++) { if (scr2[i|j] > scr2[i]) scr[i]++; else mark[i]++; } /* Try to adjoin a generic vector from the intersection of subspace j and subspace jj; see whether it is possible to determine whether this vector is or is not in each of the other subspaces (i.e., whether subspace i includes the intersection of subspaces j and jj) */ for (i = 0; i < k; i++) { /* Note: if we write for subspace i, so that mark[i] is dim(), then mark[i|i'] - mark[i] = dim() - dim() = dim() - dim( intersect ) so to check whether dim(intersect) <,=,> dim(intersect), it suffices to check whether mark[i|i']-mark[i'] >,=,< mark[i|i'']-mark[i'']. */ scr2[i] = 0; /* Don't bother adding the null vector */ if (i == 0) scr2[i] |= 2; /* The generic vector is in subspace i if subspace i includes subspace j */ if (mark[i|j] == mark[i]) scr2[i] |= 1; /* It's in if subspace i includes subspace jj */ if (mark[i|jj] == mark[i]) scr2[i] |= 1; /* It's in if dim( intersect ) = dim( intersect ) = dim( intersect ) = dim( intersect ) because the first two equalities give intersect = intersect = intersect = intersect ( intersect ) */ if ((mark[j]-mark[i|j] == mark[jj]-mark[i|jj]) && (mark[j]-mark[i|j] == mark[j|jj]-mark[i|j|jj]) && (mark[i]-mark[i|j] == mark[jj]-mark[j|jj])) scr2[i] |= 1; /* It's in if dim( intersect ) = dim( intersect ) = dim( intersect ) because these give intersect = intersect = intersect = intersect ( intersect ). Similarly with j and jj interchanged. */ if ((mark[jj]-mark[j|jj] == mark[i]-mark[j|i]) && (mark[jj]-mark[j|jj] == mark[i|jj]-mark[j|i|jj])) scr2[i] |= 1; if ((mark[j]-mark[j|jj] == mark[i]-mark[jj|i]) && (mark[j]-mark[j|jj] == mark[i|j]-mark[j|i|jj])) scr2[i] |= 1; /* It's out if dim( intersect ) < dim( intersect ) */ if (mark[i|j]-mark[i] > mark[jj|j]-mark[jj]) scr2[i] |= 2; /* It's out if dim( intersect ) < dim( intersect ) */ if (mark[i|jj]-mark[i] > mark[j|jj]-mark[j]) scr2[i] |= 2; /* It's out if subspace i does not include subspace j&jj */ if (mark[i|(j&jj)] > mark[i]) scr2[i] |= 2; /* Note that if we have spaces U,V,W with V included in U, then U intersect VW = (U intersect W)V. [Right-to-left inclusion is easy. For left-to-right, if u = v+w, then v is in V and w = u-v is in U intersect W.] So if includes intersect, then we can't have dim(intersect) < dim( intersect <(i&j)|jj>) because intersect <(i&j)|jj> = ( intersect ) and the latter is included in intersect. */ if (mark[i|j]+mark[(i&j)|jj] > mark[j|jj]+mark[i]) scr2[i] |= 2; /* Same with j and jj interchanged */ if (mark[i|jj]+mark[(i&jj)|j] > mark[j|jj]+mark[i]) scr2[i] |= 2; /* If dim(intersect)=dim(intersect) and we have an inclusion between these two subspaces, then we get intersect=intersect and hence includes intersect. */ if (mark[i|j]-mark[i] == mark[j|jj]-mark[jj]) { /* Inclusion holds if is included in (because intersect is just ) */ if (mark[j|jj] == mark[jj]) scr2[i] |= 1; /* Inclusion holds if is included in */ if (mark[i|jj] == mark[jj]) scr2[i] |= 1; } /* Same with j and jj interchanged */ if (mark[i|jj]-mark[i] == mark[j|jj]-mark[j]) { if (mark[j|jj] == mark[j]) scr2[i] |= 1; if (mark[j|i] == mark[j]) scr2[i] |= 1; } /* If <(j&~jj)|(jj&~j)> (i.e., ) is independent of , then we have intersect = (intersect). [The right-to-left inclusion is easy. For the left-to-right inclusion, if x is in = <(j&~jj)|(j&jj)> and in = <(jj&~j)|(j&jj)>, then x = y1 + z1 = y2 + z2 with y1 in , y2 in , and z1,z2 in . By the independence assumption, we must have y1=y2 and z1=z2, and y1=y2 is in intersect, so we are done.] So, in this case, if we also have included in , then to get intersect included in it suffices to have intersect included in . */ if ((mark[j|jj] == mark[j&jj]+mark[j^jj]) && (mark[(j&jj)|i] == mark[i])) { /* The next three are just copies of previous tests with j and jj changed to j&~jj and jj&~j */ if (mark[(j&~jj)|i] == mark[i]) scr2[i] |= 1; if (mark[(jj&~j)|i] == mark[i]) scr2[i] |= 1; if ((mark[j&~jj]-mark[i|(j&~jj)] == mark[jj&~j]-mark[i|(jj&~j)]) && (mark[j&~jj]-mark[i|(j&~jj)] == mark[j^jj]-mark[i|(j^jj)]) && (mark[i]-mark[i|(j&~jj)] == mark[jj&~j]-mark[j^jj])) scr2[i] |= 1; /* Now repeat the previous test with i changed to i&~(j&jj) */ if ((mark[j&~jj]-mark[(i&~(j&jj))|(j&~jj)] == mark[jj&~j]-mark[(i&~(j&jj))|(jj&~j)]) && (mark[j&~jj]-mark[(i&~(j&jj))|(j&~jj)] == mark[j^jj]-mark[(i&~(j&jj))|(j^jj)]) && (mark[(i&~(j&jj))]-mark[(i&~(j&jj))|(j&~jj)] == mark[jj&~j]-mark[j^jj])) scr2[i] |= 1; } /* Apply monotonicity conditions: if the generic vector is not in subspace i and subspace ii is included in subspace ii, then the generic vector is not in subspace ii */ for (ii = 1; ii < i; ii++) { if ((i & ii) == ii) { scr2[i] |= scr2[ii]&1; scr2[ii] |= scr2[i]&2; } } } /* Check whether the determination succeeded */ for (i = 0; i < k; i++) { if ((scr2[i] == 0) || (scr2[i] == 3)) { #if defined(VERBOSE) printf("\n"); #endif break; } } if (i < k) { #if defined(VERBOSE) //for (i = 0; i < k; i++) printf("%d ",mark[i]); //printf("\n"); //for (i = 0; i < k; i++) printf("%d ",scr[i]); //printf("\n"); //for (i = 0; i < k; i++) printf("%d ",scr2[i]); //printf("\n"); //printf(" %d %d\n",j,jj); printf("\n"); #endif break; } /* Determination succeeded -- update mark[] and scr[] */ for (i = 0; i < k; i++) { if (scr2[i] == 1) mark[i]--; else scr[i]--; } } #if defined(VERBOSE) printf("\n"); #endif } #if defined(ALTERNATIVE1) if (j == k) break; } if (j == k) break; } #endif if (j != k) break; for (i = 0; i < scr[0]; i++) proof[prooflen++] = 0; if (permarray[m][k] < (1 << lastgoodvar)) proof[prooflen++] = -1; else proof[prooflen++] = -2; #if defined(VERBOSE) /* See how many entirely new vectors are in the new random variable */ if (scr[0]) { printf(" and %d new\n",scr[0]); } #endif } if (k == TWOTONVAR) { #if defined(VERBOSE) printf("--------------SUCCESS---------------\n"); #endif inner = 1; break; } else if (k == (TWOTONVAR>>1)) { n |= permarray[m][TWOTONVAR>>1]; } } /* Try a second test for realizability (which really shouldn't give anything not given by the first test) -- ADD HERE */ for (i = 0; i < TWOTONVAR; i++) mark[i] = (v[i]>0); for (i = 1; i < TWOTONVAR; i <<= 1) mark[i] = 0; for (i = 1; i < TWOTONVAR; i++) { for (j = i+1; j < TWOTONVAR; j++) { if (((j&i)==i) && (v[i]==v[j])) mark[i] = 0; k = (i|j); if ((v[k]>v[i]) && (v[k]>v[j]) && (v[k]==v[i]+v[j]-v[i&j])) mark[k] = 0; } } #if 0 /* This doesn't work!! */ for (i = 0; i < NVAR; i++) scr[i] = v[1< 1) */ printf(" "); printf("%d",v[k] /*," *x"[mark[k]]*/ ); } #endif printf("\n"); } skip: ; } }