📄 niederreiter-2.c
字号:
/* Author: G. Jungman *//* Implement Niederreiter base 2 generator. * See: * Bratley, Fox, Niederreiter, ACM Trans. Model. Comp. Sim. 2, 195 (1992) */#include <config.h>#include <gsl/gsl_qrng.h>#define NIED2_CHARACTERISTIC 2#define NIED2_BASE 2#define NIED2_MAX_DIMENSION 12#define NIED2_MAX_PRIM_DEGREE 5#define NIED2_MAX_DEGREE 50#define NIED2_BIT_COUNT 30#define NIED2_NBITS (NIED2_BIT_COUNT+1)#define MAXV (NIED2_NBITS + NIED2_MAX_DEGREE)/* Z_2 field operations */#define NIED2_ADD(x,y) (((x)+(y))%2)#define NIED2_MUL(x,y) (((x)*(y))%2)#define NIED2_SUB(x,y) NIED2_ADD((x),(y))static size_t nied2_state_size(unsigned int dimension);static int nied2_init(void * state, unsigned int dimension);static int nied2_get(void * state, unsigned int dimension, double * v);static const gsl_qrng_type nied2_type = { "niederreiter-base-2", NIED2_MAX_DIMENSION, nied2_state_size, nied2_init, nied2_get};const gsl_qrng_type * gsl_qrng_niederreiter_2 = &nied2_type;/* primitive polynomials in binary encoding */static const int primitive_poly[NIED2_MAX_DIMENSION+1][NIED2_MAX_PRIM_DEGREE+1] ={ { 1, 0, 0, 0, 0, 0 }, /* 1 */ { 0, 1, 0, 0, 0, 0 }, /* x */ { 1, 1, 0, 0, 0, 0 }, /* 1 + x */ { 1, 1, 1, 0, 0, 0 }, /* 1 + x + x^2 */ { 1, 1, 0, 1, 0, 0 }, /* 1 + x + x^3 */ { 1, 0, 1, 1, 0, 0 }, /* 1 + x^2 + x^3 */ { 1, 1, 0, 0, 1, 0 }, /* 1 + x + x^4 */ { 1, 0, 0, 1, 1, 0 }, /* 1 + x^3 + x^4 */ { 1, 1, 1, 1, 1, 0 }, /* 1 + x + x^2 + x^3 + x^4 */ { 1, 0, 1, 0, 0, 1 }, /* 1 + x^2 + x^5 */ { 1, 0, 0, 1, 0, 1 }, /* 1 + x^3 + x^5 */ { 1, 1, 1, 1, 0, 1 }, /* 1 + x + x^2 + x^3 + x^5 */ { 1, 1, 1, 0, 1, 1 } /* 1 + x + x^2 + x^4 + x^5 */};/* degrees of primitive polynomials */static const int poly_degree[NIED2_MAX_DIMENSION+1] ={ 0, 1, 1, 2, 3, 3, 4, 4, 4, 5, 5, 5, 5};typedef struct{ unsigned int sequence_count; int cj[NIED2_NBITS][NIED2_MAX_DIMENSION]; int nextq[NIED2_MAX_DIMENSION];} nied2_state_t;static size_t nied2_state_size(unsigned int dimension){ return sizeof(nied2_state_t);}/* Multiply polynomials over Z_2. * Notice use of a temporary vector, * side-stepping aliasing issues when * one of inputs is the same as the output * [especially important in the original fortran version, I guess]. */static void poly_multiply( const int pa[], int pa_degree, const int pb[], int pb_degree, int pc[], int * pc_degree ){ int j, k; int pt[NIED2_MAX_DEGREE+1]; int pt_degree = pa_degree + pb_degree; for(k=0; k<=pt_degree; k++) { int term = 0; for(j=0; j<=k; j++) { const int conv_term = NIED2_MUL(pa[k-j], pb[j]); term = NIED2_ADD(term, conv_term); } pt[k] = term; } for(k=0; k<=pt_degree; k++) { pc[k] = pt[k]; } for(k=pt_degree+1; k<=NIED2_MAX_DEGREE; k++) { pc[k] = 0; } *pc_degree = pt_degree;}/* Calculate the values of the constants V(J,R) as * described in BFN section 3.3. * * px = appropriate irreducible polynomial for current dimension * pb = polynomial defined in section 2.3 of BFN. * pb is modified */static void calculate_v( const int px[], int px_degree, int pb[], int * pb_degree, int v[], int maxv ){ const int nonzero_element = 1; /* nonzero element of Z_2 */ const int arbitrary_element = 1; /* arbitray element of Z_2 */ /* The polynomial ph is px**(J-1), which is the value of B on arrival. * In section 3.3, the values of Hi are defined with a minus sign: * don't forget this if you use them later ! */ int ph[NIED2_MAX_DEGREE+1]; /* int ph_degree = *pb_degree; */ int bigm = *pb_degree; /* m from section 3.3 */ int m; /* m from section 2.3 */ int r, k, kj; for(k=0; k<=NIED2_MAX_DEGREE; k++) { ph[k] = pb[k]; } /* Now multiply B by PX so B becomes PX**J. * In section 2.3, the values of Bi are defined with a minus sign : * don't forget this if you use them later ! */ poly_multiply(px, px_degree, pb, *pb_degree, pb, pb_degree); m = *pb_degree; /* Now choose a value of Kj as defined in section 3.3. * We must have 0 <= Kj < E*J = M. * The limit condition on Kj does not seem very relevant * in this program. */ /* Quoting from BFN: "Our program currently sets each K_q * equal to eq. This has the effect of setting all unrestricted * values of v to 1." * Actually, it sets them to the arbitrary chosen value. * Whatever. */ kj = bigm; /* Now choose values of V in accordance with * the conditions in section 3.3. */ for(r=0; r<kj; r++) { v[r] = 0; } v[kj] = 1; if(kj >= bigm) { for(r=kj+1; r<m; r++) { v[r] = arbitrary_element; } } else { /* This block is never reached. */ int term = NIED2_SUB(0, ph[kj]); for(r=kj+1; r<bigm; r++) { v[r] = arbitrary_element; /* Check the condition of section 3.3, * remembering that the H's have the opposite sign. [????????] */ term = NIED2_SUB(term, NIED2_MUL(ph[r], v[r])); } /* Now v[bigm] != term. */ v[bigm] = NIED2_ADD(nonzero_element, term); for(r=bigm+1; r<m; r++) { v[r] = arbitrary_element; } } /* Calculate the remaining V's using the recursion of section 2.3, * remembering that the B's have the opposite sign. */ for(r=0; r<=maxv-m; r++) { int term = 0; for(k=0; k<m; k++) { term = NIED2_SUB(term, NIED2_MUL(pb[k], v[r+k])); } v[r+m] = term; }}static void calculate_cj(nied2_state_t * ns, unsigned int dimension){ int ci[NIED2_NBITS][NIED2_NBITS]; int v[MAXV+1]; int r; unsigned int i_dim; for(i_dim=0; i_dim<dimension; i_dim++) { const int poly_index = i_dim + 1; int j, k; /* Niederreiter (page 56, after equation (7), defines two * variables Q and U. We do not need Q explicitly, but we * do need U. */ int u = 0; /* For each dimension, we need to calculate powers of an * appropriate irreducible polynomial, see Niederreiter * page 65, just below equation (19). * Copy the appropriate irreducible polynomial into PX, * and its degree into E. Set polynomial B = PX ** 0 = 1. * M is the degree of B. Subsequently B will hold higher * powers of PX. */ int pb[NIED2_MAX_DEGREE+1]; int px[NIED2_MAX_DEGREE+1]; int px_degree = poly_degree[poly_index]; int pb_degree = 0; for(k=0; k<=px_degree; k++) { px[k] = primitive_poly[poly_index][k]; pb[k] = 0; } for (;k<NIED2_MAX_DEGREE+1;k++) { px[k] = 0; pb[k] = 0; } pb[0] = 1; for(j=0; j<NIED2_NBITS; j++) { /* If U = 0, we need to set B to the next power of PX * and recalculate V. */ if(u == 0) calculate_v(px, px_degree, pb, &pb_degree, v, MAXV); /* Now C is obtained from V. Niederreiter * obtains A from V (page 65, near the bottom), and then gets * C from A (page 56, equation (7)). However this can be done * in one step. Here CI(J,R) corresponds to * Niederreiter's C(I,J,R). */ for(r=0; r<NIED2_NBITS; r++) { ci[r][j] = v[r+u]; } /* Advance Niederreiter's state variables. */ ++u; if(u == px_degree) u = 0; } /* The array CI now holds the values of C(I,J,R) for this value * of I. We pack them into array CJ so that CJ(I,R) holds all * the values of C(I,J,R) for J from 1 to NBITS. */ for(r=0; r<NIED2_NBITS; r++) { int term = 0; for(j=0; j<NIED2_NBITS; j++) { term = 2*term + ci[r][j]; } ns->cj[r][i_dim] = term; } }}static int nied2_init(void * state, unsigned int dimension){ nied2_state_t * n_state = (nied2_state_t *) state; unsigned int i_dim; if(dimension < 1 || dimension > NIED2_MAX_DIMENSION) return GSL_EINVAL; calculate_cj(n_state, dimension); for(i_dim=0; i_dim<dimension; i_dim++) n_state->nextq[i_dim] = 0; n_state->sequence_count = 0; return GSL_SUCCESS;}static int nied2_get(void * state, unsigned int dimension, double * v){ static const double recip = 1.0/(double)(1U << NIED2_NBITS); /* 2^(-nbits) */ nied2_state_t * n_state = (nied2_state_t *) state; int r; int c; unsigned int i_dim; /* Load the result from the saved state. */ for(i_dim=0; i_dim<dimension; i_dim++) { v[i_dim] = n_state->nextq[i_dim] * recip; } /* Find the position of the least-significant zero in sequence_count. * This is the bit that changes in the Gray-code representation as * the count is advanced. */ r = 0; c = n_state->sequence_count; while(1) { if((c % 2) == 1) { ++r; c /= 2; } else break; } if(r >= NIED2_NBITS) return GSL_EFAILED; /* FIXME: better error code here */ /* Calculate the next state. */ for(i_dim=0; i_dim<dimension; i_dim++) { n_state->nextq[i_dim] ^= n_state->cj[r][i_dim]; } n_state->sequence_count++; return GSL_SUCCESS;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -