#include #include #include #include #include #include ///////////////////////////////////////////////////// //poly.c ///////////////////////////////////////////////////// //Version 1.0 (3/7/2011) ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// //To compile: gcc -lm -O3 poly.c //(-lm to include math.h and complex.h) //(-O3 for maximum optimization) // //Them, Run the built file with arguments "n d" // //The output will be a file in the root directory //of the form ndpq_DD.MM.YY.txt //////////////////////////////////////////////////// //Groups of polynomials will be referred to as: //(n, d, P, Q), where //n is the number of variables, //d is the maximum degree //P is the polymod //Q is the funcmod. /* This code will work correctly for the following values of n, d, P, Q: (note: d must be a positive integer) P = 2; Q = 3 P = 3; Q = 2 ------------- ------------- n = 2: d <= 2 n = 2: d <= 2 n = 3: d <= 3 n = 3: d <= 3 n = 4: d <= 4 n = 4: d <= 4 n = 5: d <= 5 n = 5: d <= 5 n = 6: d <= 5 n = 6: d <= 2 n = 7: d <= 2 n = 7: d <= 2 n = 8: d <= 2 n = 8: d <= 2 n = 9: d <= 2 n = 10: d <= 2 For the above, the number of terms (monomials) will not exceed 63, and the number of polynomials will not exceed 2^63. */ /////////////Constants///////////// //polymod p #define P 2 //funcmod q #define Q 3 //parameter for the evalTable, that will precompute //evaluation of polynomials in chunks. #define T 9 //The evalTable will be of size TABLE_X * TABLE_Y: #define TABLE_X (int)pow(P, T) #define TABLE_Y (2 << T) //Pointer to output file. FILE *fp; //full name of file (with date) char name[20]; //Array used for computing order the order of terms. //Generates all terms in the extended input. unsigned int allTerms[65][6]; //65: upper bound on # of terms. //6: upper bound on max degree //Index for allTerms array. unsigned int C = 0; ////////////////////////////////// /* x^n (for long longs)*/ unsigned long long ipow(unsigned long long x, unsigned int n){ unsigned long long ret = 1; while (n > 0){ if (n % 2){ ret *= x; n -= 1; } x *= x; n /= 2; } return ret; } /* Count the number of set bits in the binary representation * of i. Algorithm source: * http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel */ unsigned int countSetBits(unsigned int i){ i = i - ((i >> 1) & 0x55555555); i = (i & 0x33333333) + ((i >> 2) & 0x33333333); return ((i + (i >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; } /* Binomial Coefficient: (n choose m)*/ unsigned int binom(unsigned int n, unsigned int m){ if ((m > n) || (m < 0)) return 0; unsigned int i; unsigned int retval = 1; for(i = 0; i < m; i++){ retval *= (n - i); retval /= (i + 1); } return retval; } /* Returns the number of possible terms in a * polynomial of arity n and max degree d */ unsigned int countTerms(unsigned int n, unsigned int d){ unsigned int retval = 0; unsigned int i; for (i = 0; i <= d; i++){ retval += binom(n, i); } return retval; } /* Returns the number of possible polynomials * under the given modulus, with the given * arity and max degree */ unsigned long long countPolys(unsigned int termCount){ return ipow(P, termCount); } /* Given (integer representations of) a polynomial * and a term, returns the coefficient for that term * in the given modulus */ unsigned int termCoeff(unsigned long long poly, unsigned int term){ return (poly / ipow(P, term)) % P; } /* Evaluates the given term on the given input. * For {0, 1}: * Returns 1 when there is no 1 bit in the term * that is in the same position as a 0 bit in the input. * In other words: returns 1 if the bitwise logical * implication [term => inpt] is all 1's. * For {-1, 1} * Keeps track of parity by reversing it for every 1 bit * in the input that matches the corresponding bit in * the term.*/ unsigned int evalTerm(unsigned long long inpt, unsigned int term){ //{0,1}: AND #if P == 2 return (term & ~inpt) ? 0 : 1; //{-1, 1}: Parity #else unsigned int r = 0; while (0 < countSetBits(term)){ if ((term & 1) & (inpt & 1)){ r = !r; } term >>= 1; inpt >>= 1; } return r; #endif } /*Find all terms for the given n and d, reusing the given array. Loop *through all possible monomials of order d starting with variable x_n. *Record the values inside of term, copy term into the allTerms array, *increment allTerms' index, and recur.*/ void getDegTerms(unsigned int *term, unsigned int index, unsigned int rest_var, unsigned int first_var){ unsigned int i; for(i = 0; first_var - i >= rest_var; i++){ term[index] = first_var - i; if(rest_var > 1) getDegTerms(term, index + 1, rest_var - 1, first_var - i - 1); else{ memcpy(allTerms[C], term, (sizeof(int) * index + 1)); C++; } } } /*Fills in the allTerms array with all terms for polynomials *of the given n and d. Will produce these arrays in order *of largest degree to the smallest degree, which will be 1. *For example: n = d = 3 produces: ((321) (32) (31) (3) (2) (1))*/ void getAllTerms(unsigned int n, unsigned int d){ //Temporary array to store each term. unsigned int term[d]; unsigned int i; for(i = d; i > 0; i--){ //get all terms for the given degree getDegTerms(term, 0, i, n); } } /*Use the allTerms array to compute an extended input *for polynomials of n variables and degree d. This will *be done in order of smallest degree to largest.*/ unsigned long long extendInput(unsigned int n, unsigned long long inpt, unsigned int d){ unsigned long long ret = 0; //count the total number of terms excluding the constant. unsigned int numTerms = countTerms(n, d) - 2; unsigned int i, j; //Start with linear monomials. unsigned int deg = 1; unsigned int count = 0; while (deg <= d){ //There will be (n chooes deg) monomials of this degree. for (i = 0; i < binom(n, deg); i++){ ret <<= 1; unsigned int c = 0; //each x_j represents the jth bit on the extended input. Thus, //raise 2^j-1 for each j in this term. for (j = 0; j < deg; j++){ c += (1 << allTerms[numTerms-count][j]-1); } ret += evalTerm(inpt, c); count++; } deg++; } return ret; } /* Fill in the array of extended versions of * every possible set of inputs */ void allExtendedInputs(unsigned int n, unsigned int d, unsigned int termCount, unsigned long long *extdInpts){ unsigned long long numInputs = (1 << n); unsigned long long inpt; for(inpt=0; inpt> 1]; } } } /* Given the results of the partials table, computer * the V-Value of a polynomial. This value can be * directly converted to the S-value, without * compromising precision and roundoff errors. * The V-Value will always be an integer.*/ __inline unsigned long long computeV(int a, int b, int c){ int t = a; if (abs(b) < t) t = b; if (abs(c) < t) t = c; a = a - t; b = b - t; c = c - t; if (a == 0) return (b + c) * (b + c) - (3 * (b * c)); else if (b == 0) return (a + c) * (a + c) - (3 * (a * c)); else return (a + b) * (a + b) - (3 * (a * b)); } /* Compute the S-Value (V-Value) of all polynomials and returns * the maximum value found. Prints the polynomials that return * this maximum in a file of the form "ndpq_DD.MM.YY.txt" */ unsigned long long evalAllPolys(unsigned int n, unsigned int d){ unsigned int i, j, k; //number of terms for polynomials with arity n, degree d. unsigned int termCount = countTerms(n, d); //total number of polynomials with arity n, degree d. //divide by P because we do not need to look at constants, which //will be the final monomial. unsigned long long polyCount = countPolys(termCount) / P; //count number of inputs we can have unsigned long long numInpts = (1 << n); //fill in allTerms array with all terms. getAllTerms(n, d); /////////////////////////////////////////////////////////////// //precompute number of 1 bits in each input to use later. //record number of 1 bits for each input in inptBits unsigned int inptBits[numInpts]; unsigned long long l; for (l = 0; l < numInpts; l++){ inptBits[l] = countSetBits(l); } unsigned long long inpt; /////////////////////////////////////////////////////////////// //Pre-compute the extended versions of all possible inputs unsigned long long extdInpts[numInpts]; allExtendedInputs(n, d, termCount, extdInpts); //We will store results for each polynomial in the partials table. static unsigned int partials[Q][P]; //create the lookup table of evaluated polynomials % P^T static unsigned int evalTable[TABLE_X][TABLE_Y]; fillEvalTable(evalTable); //////////////////////////////////////////////////////////////// //Compute the Base polynomials: Polynomials of arity n and //degree d that do not contain any linear terms (1 > degree >= d). unsigned long long base = 0; for (i = 2; i < d+1; i++){ base += binom(n, i); } base = ipow(P, base); //////////////////////////////////////////////////////////////// //Find the number of sums of linear monomials we can make to //base polynomials (see optimization). Record in monoms. unsigned int monoms; #if P == 2 monoms = n+1; #else //P == 3 monoms = (n + 1) * (n + 2) / 2; #endif //////////////////////////////////////////////////////////////// //Create an array to record all sums to add to base polynomials //necessary to check all polynomials disregarding permutations. unsigned long long linsums[monoms]; //index for linsums. unsigned int count = 0; //Precalculate the sums for adding linear terms to a base poly. #if P == 2 unsigned long long linearSum = 0; for (i = 0; i < n+1; i++){ if (i != 0){ //Add a linear term linearSum = linearSum + ipow(P, i-1) * base; } linsums[count] = linearSum; count++; } #else //P == 3 //Addition to a base polynomial to sum a set of linear terms. unsigned long long linearSum = 0; //Addition to a base polynomial to sum a set of linear terms, //including possible 2 coefficients on these linear terms. unsigned long long linearSumCoeff = 0; //The power of P to get to the first linear term. unsigned int startPower = termCount - n - 2; //Find all sums of linear terms without 2 coefficeints. for (i = 0; i < n+1; i++){ if (i != 0) linearSum += ipow(P, i-1) * base; linearSumCoeff = linearSum; //add in a 2 coefficients as appropriate (see optimization). for (j = 0; j < i + 1; j++){ if (j > 0) linearSumCoeff += ipow(P, startPower + j); linsums[count] = linearSumCoeff; count++; } } #endif unsigned long long maxV = 0; //Maximum V-Value seen so far. unsigned int counter = 0; //number of polynomials that have the Maximum //////////////////////////////////////////////////////////////// //Main Loop. Go through all base polynomials, go through all //sums of linear monomials, record results. unsigned long long poly = 0; unsigned long long polyWithSums = 0; for(poly = 0; poly < base; poly++){ //EV progress check. Print when last x bits all 1 if ( !(poly & ((1 << 25) - 1) ) ) printf("poly=%llu, base=%llu;", poly, base); polyWithSums = poly; //add the ith sum in the linsums array to add //a set of linear terms. for (i = 0; i < monoms; i++){ polyWithSums = poly + linsums[i]; //reset partials array. for(j = 0; j < Q; j++){ for(k = 0; k < P; k++){ partials[j][k] = 0; } } //Evaluate this polynomial for all inputs. Fill in //partials table. for(inpt = 0; inpt < numInpts; inpt++){ //retrieve the resulting extended input. unsigned long long extInpt = extdInpts[inpt]; unsigned long long polyTemp = polyWithSums; //evaluated value of the polynomial for this input. unsigned int polyVal = 0; do { //look up the value of the chunk in the evalTable polyVal += evalTable[polyTemp % TABLE_X][extInpt & (TABLE_Y-1)]; //divide by chunk size to find next polynomial. #if P == 2 polyTemp >>= T; #else polyTemp /= TABLE_X; #endif //shift input by T extInpt >>= T; }while (polyTemp > 0); //Fill in partials table partials[inptBits[inpt] % Q][polyVal % P] += 1; } //////////////////////////////////////////////////// //Find V(a,b,c) int a, b, c; unsigned long long vVal; #if P == 3 a = partials[0][0] - partials[1][0]; b = partials[0][1] - partials[1][1]; c = partials[0][2] - partials[1][2]; vVal = computeV(a,b,c); #else a = partials[0][0] - partials[0][1]; b = partials[1][0] - partials[1][1]; c = partials[2][0] - partials[2][1]; vVal = computeV(a,b,c); #endif //////////////////////////////////////////////////// if (vVal > maxV){ //new Maximum //rewrite the file, so that only the latest Max is printed. fclose(fp); fp = fopen(name,"w"); //New Max vVal maxV = vVal; fprintf(fp, "\n----------------MAX V-VAL: %llu----------------\n\n", maxV); //print the polynomial. printPoly(polyWithSums, n, d); //reset counter to one. counter = 1; } //add to list of polynomials under current max. else if (vVal == maxV){ counter++; fprintf(fp, "\n"); printPoly(polyWithSums, n, d); } } } fprintf(fp, "\nThere were %d instances of the max V-Val\n\n", counter); return maxV; } /* Set the name of this file*/ void setFileName(int n, int d){ time_t now; struct tm *today; char date[10]; //get current date time(&now); today = localtime(&now); //print it in DD.MM.YY format. strftime(date, 15, "%d.%m.%Y", today); sprintf(name, "%d%d%d%d_%s.txt",n,d,P,Q,date); } int main(int argc, char *argv[]){ //////////////////////////////////////////////// //Set up n and d unsigned int n, d; if (argc == 3){ n = atoi(argv[1]); d = atoi(argv[2]); } else{ printf("Please give values for n and d!\n"); return 1; } //////////////////////////////////////////////// //set name for the output file setFileName(n, d); fp = fopen(name,"w"); printf("I am doing:\nn = %d, d = %d, mod = %d, fmod = %d\n", n, d, P, Q); //set up timer to keep track of how long computation takes. clock_t start, end; double cpu_time_used; start = clock(); //do the computation! unsigned long long maxV = evalAllPolys(n, d); //stop timer. end = clock(); cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC; //print out maximum V-Value, and time spent computing. fprintf(fp, "maximum computed V-value: %llu\n", maxV); fprintf(fp, "time computing: %f\n", cpu_time_used); //get and print the date and time computation finished. time_t now; struct tm *today; char date[30]; time(&now); today = localtime(&now); strftime(date, 30, "%c", today); fprintf(fp, "\nFinished on: %s\n", date); //print the n,d,P,Q values once more. fprintf(fp, "\nn = %d, d = %d, P = %d, Q = %d\n\n", n, d, P, Q); return 0; }