pomp
Inference for partially observed Markov processes
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
sobolseq.c
Go to the documentation of this file.
1// -*- C++ -*-
2/* Copyright (c) 2007 Massachusetts Institute of Technology
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24/* Generation of Sobol sequences in up to 1111 dimensions, based on the
25 algorithms described in:
26 P. Bratley and B. L. Fox, Algorithm 659, ACM Trans.
27 Math. Soft. 14 (1), 88-100 (1988),
28 as modified by:
29 S. Joe and F. Y. Kuo, ACM Trans. Math. Soft 29 (1), 49-57 (2003).
30
31 Note that the code below was written without even looking at the
32 Fortran code from the TOMS paper, which is only semi-free (being
33 under the restrictive ACM copyright terms). Then I went to the
34 Fortran code and took out the table of primitive polynomials and
35 starting direction #'s ... since this is just a table of numbers
36 generated by a deterministic algorithm, it is not copyrightable.
37 (Obviously, the format of these tables then necessitated some
38 slight modifications to the code.)
39
40 For the test integral of Joe and Kuo (see the main() program
41 below), I get exactly the same results for integrals up to 1111
42 dimensions compared to the table of published numbers (to the 5
43 published significant digits).
44
45 This is not to say that the authors above should not be credited for
46 their clear description of the algorithm (and their tabulation of
47 the critical numbers). Please cite them. Just that I needed
48 a free/open-source implementation. */
49
50/* AAK Notes:
51 I have removed the dependence on the NLOPT headers and on "stdint.h".
52 The assumption is (according to R_ext/Random.h) that Int32 is a 32-bit
53 integer. The fall-back to pseudo-random numbers for sequences of length
54 greater than 2^32-1 has also been removed. This case generates an error.
55*/
56
57#include "internal.h"
58
59typedef Int32 uint32_t;
61static nlopt_sobol nlopt_sobol_create(unsigned sdim);
63static void nlopt_sobol_skip(nlopt_sobol s, unsigned n, double *x);
64
65typedef struct nlopt_soboldata_s {
66 unsigned sdim; /* dimension of sequence being generated */
67 uint32_t *mdata; /* array of length 32 * sdim */
68 uint32_t *m[32]; /* more convenient pointers to mdata, of direction #s */
69 uint32_t *x; /* previous x = x_n, array of length sdim */
70 unsigned *b; /* position of fixed point in x[i] is after bit b[i] */
71 uint32_t n; /* number of x's generated so far */
73
74/* Return position (0, 1, ...) of rightmost (least-significant) zero bit in n.
75 *
76 * This code uses a 32-bit version of algorithm to find the rightmost
77 * one bit in Knuth, _The Art of Computer Programming_, volume 4A
78 * (draft fascicle), section 7.1.3, "Bitwise tricks and
79 * techniques."
80 *
81 * Assumes n has a zero bit, i.e. n < 2^32 - 1.
82 *
83 */
84static unsigned rightzero32 (uint32_t n)
85{
86 const uint32_t a = 0x05f66a47; /* magic number, found by brute force */
87 static const unsigned decode[32] = {0,1,2,26,23,3,15,27,24,21,19,4,12,16,28,6,31,25,22,14,20,18,11,5,30,13,17,10,29,9,8,7};
88 n = ~n; /* change to rightmost-one problem */
89 n = a * (n & (-n)); /* store in n to make sure mult. is 32 bits */
90 return decode[n >> 27];
91}
92
93/* generate the next term x_{n+1} in the Sobol sequence, as an array
94 x[sdim] of numbers in (0,1). Returns 1 on success, 0 on failure
95 (if too many #'s generated) */
96static int sobol_gen (soboldata *sd, double *x)
97{
98 unsigned c, b, i, sdim;
99
100 if (sd->n == 4294967295U) return 0; /* n == 2^32 - 1 ... we would
101 need to switch to a 64-bit version
102 to generate more terms. */
103 c = rightzero32(sd->n++);
104 sdim = sd->sdim;
105 for (i = 0; i < sdim; ++i) {
106 b = sd->b[i];
107 if (b >= c) {
108 sd->x[i] ^= sd->m[c][i] << (b - c);
109 x[i] = ((double) (sd->x[i])) / (1U << (b+1));
110 }
111 else {
112 sd->x[i] = (sd->x[i] << (c - b)) ^ sd->m[c][i];
113 sd->b[i] = c;
114 x[i] = ((double) (sd->x[i])) / (1U << (c+1));
115 }
116 }
117 return 1;
118}
119
120#include "soboldata.h"
121
122static int sobol_init (soboldata *sd, unsigned sdim)
123{
124 unsigned i,j;
125
126 if (!sdim || sdim > MAXDIM) return 0;
127
128 sd->mdata = (uint32_t *) R_Calloc(sdim*32,uint32_t);
129 if (!sd->mdata) return 0;
130
131 for (j = 0; j < 32; ++j) {
132 sd->m[j] = sd->mdata + j * sdim;
133 sd->m[j][0] = 1; /* special-case Sobol sequence */
134 }
135 for (i = 1; i < sdim; ++i) {
136 uint32_t a = sobol_a[i-1];
137 unsigned d = 0, k;
138
139 while (a) {
140 ++d;
141 a >>= 1;
142 }
143 d--; /* d is now degree of poly */
144
145 /* set initial values of m from table */
146 for (j = 0; j < d; ++j)
147 sd->m[j][i] = sobol_minit[j][i-1];
148
149 /* fill in remaining values using recurrence */
150 for (j = d; j < 32; ++j) {
151 a = sobol_a[i-1];
152 sd->m[j][i] = sd->m[j - d][i];
153 for (k = 0; k < d; ++k) {
154 sd->m[j][i] ^= ((a & 1) * sd->m[j-d+k][i]) << (d-k);
155 a >>= 1;
156 }
157 }
158 }
159
160 sd->x = (uint32_t *) R_Calloc(sdim,uint32_t);
161 if (!sd->x) { R_Free(sd->mdata); return 0; }
162
163 sd->b = (unsigned *) R_Calloc(sdim,unsigned);
164 if (!sd->b) { R_Free(sd->x); R_Free(sd->mdata); return 0; }
165
166 for (i = 0; i < sdim; ++i) {
167 sd->x[i] = 0;
168 sd->b[i] = 0;
169 }
170
171 sd->n = 0;
172 sd->sdim = sdim;
173
174 return 1;
175}
176
177static void sobol_destroy (soboldata *sd)
178{
179 R_Free(sd->mdata);
180 R_Free(sd->x);
181 R_Free(sd->b);
182}
183
184/************************************************************************/
185/* NLopt API to Sobol sequence creation, which hides soboldata structure
186 behind an opaque pointer */
187
188static nlopt_sobol nlopt_sobol_create (unsigned sdim)
189{
190 nlopt_sobol s = (nlopt_sobol) R_Calloc(1,soboldata);
191 if (!s) return 0;
192 if (!sobol_init(s, sdim)) { R_Free(s); return NULL; }
193 return s;
194}
195
197{
198 if (s) {
199 sobol_destroy(s);
200 R_Free(s);
201 }
202}
203
204/* next vector x[sdim] in Sobol sequence, with each x[i] in (0,1) */
205// void nlopt_sobol_next01 (nlopt_sobol s, double *x)
206// {
207// if (!sobol_gen(s, x))
208// err("too many points requested");
209// }
210
211/* next vector in Sobol sequence, scaled to (lb[i], ub[i]) interval */
212// void nlopt_sobol_next (nlopt_sobol s, double *x,
213// const double *lb, const double *ub)
214// {
215// unsigned i, sdim;
216// nlopt_sobol_next01(s, x);
217// for (sdim = s->sdim, i = 0; i < sdim; ++i)
218// x[i] = lb[i] + (ub[i] - lb[i]) * x[i];
219// }
220
221/* if we know in advance how many points (n) we want to compute, then
222 adopt the suggestion of the Joe and Kuo paper, which in turn
223 is taken from Acworth et al (1998), of skipping a number of
224 points equal to the largest power of 2 smaller than n */
225static void nlopt_sobol_skip(nlopt_sobol s, unsigned n, double *x)
226{
227 if (s) {
228 unsigned k = 1;
229 while (k*2 < n) k *= 2;
230 while (k-- > 0) sobol_gen(s, x);
231 }
232}
233
234SEXP sobol_sequence (SEXP dim, SEXP length)
235{
236 SEXP data;
237 unsigned int d = (unsigned int) INTEGER(dim)[0];
238 unsigned int n = (unsigned int) INTEGER(length)[0];
239 double *dp;
240 unsigned int k;
241 nlopt_sobol s = nlopt_sobol_create((unsigned int) d);
242 if (s==0) err("dimension is too high");
243 PROTECT(data = allocMatrix(REALSXP,d,n)); dp = REAL(data);
244 nlopt_sobol_skip(s,n,dp);
245 for (k = 1; k < n; k++) sobol_gen(s,dp+k*d);
247 UNPROTECT(1);
248 return(data);
249}
#define err(...)
Definition pomp.h:21
#define MAXDIM
Definition soboldata.h:34
static const uint32_t sobol_a[MAXDIM-1]
Definition soboldata.h:40
static const uint32_t sobol_minit[MAXDEG+1][MAXDIM-1]
Definition soboldata.h:150
static void nlopt_sobol_destroy(nlopt_sobol s)
Definition sobolseq.c:196
static nlopt_sobol nlopt_sobol_create(unsigned sdim)
Definition sobolseq.c:188
static int sobol_init(soboldata *sd, unsigned sdim)
Definition sobolseq.c:122
Int32 uint32_t
Definition sobolseq.c:59
struct nlopt_soboldata_s soboldata
static unsigned rightzero32(uint32_t n)
Definition sobolseq.c:84
static void nlopt_sobol_skip(nlopt_sobol s, unsigned n, double *x)
Definition sobolseq.c:225
SEXP sobol_sequence(SEXP dim, SEXP length)
Definition sobolseq.c:234
static void sobol_destroy(soboldata *sd)
Definition sobolseq.c:177
static int sobol_gen(soboldata *sd, double *x)
Definition sobolseq.c:96
struct nlopt_soboldata_s * nlopt_sobol
Definition sobolseq.c:60
unsigned * b
Definition sobolseq.c:70
unsigned sdim
Definition sobolseq.c:66
uint32_t * x
Definition sobolseq.c:69
uint32_t * mdata
Definition sobolseq.c:67
uint32_t * m[32]
Definition sobolseq.c:68