int test_defaults_dp() { dgs_disc_gauss_dp_t *self; self = dgs_disc_gauss_dp_init(3.0, 0, 6, DGS_DISC_GAUSS_DEFAULT); if (self->algorithm != DGS_DISC_GAUSS_UNIFORM_TABLE) dgs_die("automatic choice of uniform table algorithm failed (%d)", self->algorithm); dgs_disc_gauss_dp_clear(self); self = dgs_disc_gauss_dp_init(3.0, 0, 1<<10, DGS_DISC_GAUSS_DEFAULT); if (self->algorithm != DGS_DISC_GAUSS_UNIFORM_TABLE) dgs_die("automatic choice of uniform table algorithm failed (%d)", self->algorithm); dgs_disc_gauss_dp_clear(self); self = dgs_disc_gauss_dp_init(3.0, 0, 1<<14, DGS_DISC_GAUSS_DEFAULT); if (self->algorithm != DGS_DISC_GAUSS_UNIFORM_LOGTABLE) dgs_die("automatic choice of uniform table algorithm failed (%d)", self->algorithm); dgs_disc_gauss_dp_clear(self); double sigma2 = sqrt(1.0/(2*log(2.0))); self = dgs_disc_gauss_dp_init(1024*sigma2, 0, 6, DGS_DISC_GAUSS_DEFAULT); if (self->algorithm != DGS_DISC_GAUSS_SIGMA2_LOGTABLE) dgs_die("automatic choice of uniform table algorithm failed (%d)", self->algorithm); dgs_disc_gauss_dp_clear(self); printf("passed\n"); return 0; }
double run_dp(double sigma, double c, int tau, dgs_disc_gauss_alg_t alg, size_t ntrials, unsigned long long *t) { double variance = 0.0; gmp_randstate_t state; gmp_randinit_default(state); dgs_disc_gauss_dp_t *gen = dgs_disc_gauss_dp_init(sigma, c, tau, alg); *t = walltime(0); for(size_t i=0; i<ntrials; i++) { long r = gen->call(gen); variance += ((double)r)*((double)r); } *t = walltime(*t); dgs_disc_gauss_dp_clear(gen); gmp_randclear(state); variance /= ntrials; return sqrt(variance); }
dgs_disc_gauss_dp_t *dgs_disc_gauss_dp_init(double sigma, double c, size_t tau, dgs_disc_gauss_alg_t algorithm) { if (sigma <= 0.0) dgs_die("sigma must be > 0"); if (tau == 0) dgs_die("tau must be > 0"); size_t upper_bound; dgs_disc_gauss_dp_t *self = (dgs_disc_gauss_dp_t*)calloc(sizeof(dgs_disc_gauss_dp_t),1); if (!self) dgs_die("out of memory"); self->sigma = sigma; self->c = c; self->c_z = (long)c; self->c_r = self->c - ((double)self->c_z); self->tau = tau; switch(algorithm) { case DGS_DISC_GAUSS_UNIFORM_ONLINE: self->call = dgs_disc_gauss_dp_call_uniform_online; upper_bound = ceil(self->sigma*tau) + 1; self->upper_bound = upper_bound; self->upper_bound_minus_one = upper_bound - 1; self->two_upper_bound_minus_one = 2*upper_bound - 1; self->f = -1.0/(2.0*(self->sigma*self->sigma)); break; case DGS_DISC_GAUSS_UNIFORM_TABLE: self->call = dgs_disc_gauss_dp_call_uniform_table; upper_bound = ceil(self->sigma*tau) + 1; self->upper_bound = upper_bound; self->upper_bound_minus_one = upper_bound - 1; self->two_upper_bound_minus_one = 2*upper_bound - 1; self->B = dgs_bern_uniform_init(0); self->f = -1.0/(2.0*(sigma*sigma)); if(self->c_r == 0) { self->call = dgs_disc_gauss_dp_call_uniform_table; self->rho = (double*)malloc(sizeof(double)*self->upper_bound); if (!self->rho) { dgs_disc_gauss_dp_clear(self); dgs_die("out of memory"); } for(unsigned long x=0; x<self->upper_bound; x++) { self->rho[x] = exp( (((double)x) - self->c_r) * (((double)x) - self->c_r) * self->f); } self->rho[0]/= 2.0; } else { self->call = dgs_disc_gauss_dp_call_uniform_table_offset; self->rho = (double*)malloc(sizeof(double)*self->two_upper_bound_minus_one); if (!self->rho) { dgs_disc_gauss_dp_clear(self); dgs_die("out of memory"); } long absmax = self->upper_bound_minus_one; for(long x=-absmax; x<=absmax; x++) { self->rho[x+self->upper_bound_minus_one] = exp( (((double)x) - self->c_r) * (((double)x) - self->c_r) * self->f); } } break; case DGS_DISC_GAUSS_UNIFORM_LOGTABLE: self->call = dgs_disc_gauss_dp_call_uniform_logtable; if (fabs(self->c_r) > DGS_DISC_GAUSS_INTEGER_CUTOFF) { dgs_disc_gauss_dp_clear(self); dgs_die("algorithm DGS_DISC_GAUSS_UNIFORM_LOGTABLE requires c%1 == 0"); } upper_bound = ceil(self->sigma*tau) + 1; self->upper_bound = upper_bound; self->upper_bound_minus_one = upper_bound - 1; self->two_upper_bound_minus_one = 2*upper_bound - 1; _dgs_disc_gauss_dp_init_bexp(self, self->sigma, self->upper_bound); break; case DGS_DISC_GAUSS_SIGMA2_LOGTABLE: { self->call = dgs_disc_gauss_dp_call_sigma2_logtable; if (fabs(self->c_r) > DGS_DISC_GAUSS_INTEGER_CUTOFF) { dgs_disc_gauss_dp_clear(self); dgs_die("algorithm DGS_DISC_GAUSS_SIGMA2_LOGTABLE requires c%1 == 0"); } double sigma2 = sqrt(1.0/(2*log(2.0))); double k = sigma/sigma2; self->k = round(k); self->sigma = self->k * sigma2; upper_bound = ceil(self->sigma*tau) + 1; self->upper_bound = upper_bound; self->upper_bound_minus_one = upper_bound - 1; self->two_upper_bound_minus_one = 2*upper_bound - 1; _dgs_disc_gauss_dp_init_bexp(self, self->sigma, self->upper_bound); self->B = dgs_bern_uniform_init(0); self->D2 = dgs_disc_gauss_sigma2p_init(); break; } default: dgs_disc_gauss_dp_clear(self); dgs_die("unknown algorithm %d", algorithm); } return self; }