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