diff options
Diffstat (limited to 'gsl-1.9/qrng/niederreiter-2.c')
-rw-r--r-- | gsl-1.9/qrng/niederreiter-2.c | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/gsl-1.9/qrng/niederreiter-2.c b/gsl-1.9/qrng/niederreiter-2.c new file mode 100644 index 0000000..1a28009 --- /dev/null +++ b/gsl-1.9/qrng/niederreiter-2.c @@ -0,0 +1,353 @@ +/* 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; +} |