SDDS ToolKit Programs and Libraries for C and Python
Loading...
Searching...
No Matches
halton.c
Go to the documentation of this file.
1/**
2 * @file halton.c
3 * @brief Implementation of Halton and modified Halton sequences.
4 *
5 * @copyright
6 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
7 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
8 *
9 * @license
10 * This file is distributed under the terms of the Software License Agreement
11 * found in the file LICENSE included with this distribution.
12 *
13 * @author M. Borland, R. Soliday, H. Shang, Y. Wang
14 */
15
16#include "mdb.h"
17
18static MDB_THREAD_LOCAL double *lastPointValue = NULL;
19static MDB_THREAD_LOCAL long *R = NULL;
20static MDB_THREAD_LOCAL long sequencesInUse = 0;
21/* These 12 primes work pretty well together.
22 * If more are needed, they are generated on the fly.
23 */
24#define N_SEQ_PREDEFINED 12
25static const long Rvalues[N_SEQ_PREDEFINED] = {2, 3, 5, 7, 11, 19, 23, 29, 37, 47, 59, 67};
26
27/**
28 * @brief Initialize and start a new Halton sequence.
29 *
30 * Initializes a new Halton sequence with the given radix and starting value.
31 * If the provided radix is not a prime or is non-positive, a suitable prime is chosen.
32 *
33 * @param radix Pointer to an integer specifying the desired prime radix.
34 * If non-positive, a prime is chosen automatically.
35 * @param value The starting value for the sequence.
36 * @return The sequence ID (1-based) on success, or 0 on failure.
37 */
38int32_t startHaltonSequence(int32_t *radix, double value) {
39 int32_t ID;
40 if ((sequencesInUse == 0 &&
41 (!(lastPointValue = malloc(sizeof(*lastPointValue))) ||
42 !(R = malloc(sizeof(*R))))) ||
43 (!(lastPointValue = realloc(lastPointValue, (sequencesInUse + 1) * sizeof(*lastPointValue))) ||
44 !(R = realloc(R, (sequencesInUse + 1) * sizeof(*R)))))
45 return 0;
46 if (*radix > 0) {
47 if (is_prime(*radix) != 1)
48 return 0;
49 R[sequencesInUse] = *radix;
50 ID = sequencesInUse;
51 } else {
52 /* generate a new, unique prime number for use as the radix */
53 long i, passed;
54 if ((ID = sequencesInUse) < N_SEQ_PREDEFINED)
55 /* try one of the favored values */
56 *radix = Rvalues[ID];
57 else
58 *radix = 2;
59 passed = 0;
60 while (!passed) {
61 passed = 1;
62 for (i = 0; i < sequencesInUse; i++) {
63 if (R[i] == *radix) {
64 passed = 0;
65 (*radix)++;
66 while (is_prime(*radix) != 1)
67 (*radix)++;
68 }
69 }
70 }
71 R[ID] = *radix;
72 }
73 lastPointValue[ID] = value;
74 sequencesInUse++;
75 return ID + 1;
76}
77
78/**
79 * @brief Restart an existing Halton sequence from a new initial value.
80 *
81 * Resets the specified Halton sequence so that subsequent calls will continue from
82 * the given initial value.
83 *
84 * @param ID The sequence ID to restart.
85 * @param value The new starting value.
86 * @return 1 on success, or -1 if the ID is invalid.
87 */
88int32_t restartHaltonSequence(long ID, double value) {
89 ID -= 1;
90
91 if (ID >= sequencesInUse || ID < 0)
92 return -1;
93
94 lastPointValue[ID] = value;
95
96 return 1;
97}
98
99/**
100 * @brief Get the next point in a Halton sequence.
101 *
102 * Computes the next value in the specified Halton sequence.
103 *
104 * @param ID The sequence ID.
105 * @return The next point in the sequence, or -1 if the ID is invalid.
106 */
107double nextHaltonSequencePoint(long ID) {
108 double r, f, value;
109
110 ID -= 1;
111
112 if (ID >= sequencesInUse || ID < 0)
113 return -1;
114
115 f = 1 - lastPointValue[ID];
116 r = 1. / R[ID];
117 while (f <= r)
118 r = r / R[ID];
119 value = lastPointValue[ID] + (R[ID] + 1) * r - 1;
120 lastPointValue[ID] = value;
121 return value;
122}
123
124/*following code is from outside for improved halton sequence
125 Alogrithm 659, Collected Algorithm from ACM
126 This is the C version of halton sequences
127 Derandom Algorithm is added on 8/12/03
128 by Hongmei CHI (CS/FSU)
129 Modified (9.29.03)
130*/
131#define MAX_D 500
132static MDB_THREAD_LOCAL int32_t sDim = 12;
133static MDB_THREAD_LOCAL int32_t nextPoint[12];
134static MDB_THREAD_LOCAL double eError;
135static MDB_THREAD_LOCAL int32_t prime[] = {
136 2,
137 3,
138 5,
139 7,
140 11,
141 13,
142 17,
143 19,
144 23,
145 29,
146 31,
147 37,
148 41,
149 43,
150 47,
151 53,
152 59,
153 61,
154 67,
155 71,
156 73,
157 79,
158 83,
159 89,
160 97,
161 101,
162 103,
163 107,
164 109,
165 113,
166 127,
167 131,
168 137,
169 139,
170 149,
171 151,
172 157,
173 163,
174 167,
175 173,
176 179,
177 181,
178 191,
179 193,
180 197,
181 199,
182 211,
183 223,
184 227,
185 229,
186 233,
187 239,
188 241,
189 251,
190 257,
191 263,
192 269,
193 271,
194 277,
195 281,
196 283,
197 293,
198 307,
199 311,
200 313,
201 317,
202 331,
203 337,
204 347,
205 349,
206 353,
207 359,
208 367,
209 373,
210 379,
211 383,
212 389,
213 397,
214 401,
215 409,
216 419,
217 421,
218 431,
219 433,
220 439,
221 443,
222 449,
223 457,
224 461,
225 463,
226 467,
227 479,
228 487,
229 491,
230 499,
231};
232static MDB_THREAD_LOCAL double iprime[] = {
233 2,
234 3,
235 5,
236 7,
237 11,
238 13,
239 17,
240 19,
241 23,
242 29,
243 31,
244 37,
245 41,
246 43,
247 47,
248 53,
249 59,
250 61,
251 67,
252 71,
253 73,
254 79,
255 83,
256 89,
257 97,
258 101,
259 103,
260 107,
261 109,
262 113,
263 127,
264 131,
265 137,
266 139,
267 149,
268 151,
269 157,
270 163,
271 167,
272 173,
273 179,
274 181,
275 191,
276 193,
277 197,
278 199,
279 211,
280 223,
281 227,
282 229,
283 233,
284 239,
285 241,
286 251,
287 257,
288 263,
289 269,
290 271,
291 277,
292 281,
293 283,
294 293,
295 307,
296 311,
297 313,
298 317,
299 331,
300 337,
301 347,
302 349,
303 353,
304 359,
305 367,
306 373,
307 379,
308 383,
309 389,
310 397,
311 401,
312 409,
313 419,
314 421,
315 431,
316 433,
317 439,
318 443,
319 449,
320 457,
321 461,
322 463,
323 467,
324 479,
325 487,
326 491,
327 499,
328};
329
330static MDB_THREAD_LOCAL int32_t modSequenceInUse = 0;
331static const int32_t primroots[][10] = {
332 {1, 2, 3, 3, 8, 11, 12, 14, 7, 18},
333 {12, 13, 17, 18, 29, 14, 18, 43, 41, 44},
334 {40, 30, 47, 65, 71, 28, 40, 60, 79, 89},
335 {56, 50, 52, 61, 108, 56, 66, 63, 60, 66},
336 {104, 76, 111, 142, 71, 154, 118, 84, 127, 142},
337 {84, 105, 186, 178, 188, 152, 165, 159, 103, 205},
338 {166, 173, 188, 181, 91, 233, 210, 217, 153, 212},
339};
340
341static const int32_t warnockOpt[] = {
342 1,
343 2,
344 2,
345 5,
346 3,
347 7,
348 3,
349 10,
350 18,
351 11,
352 17,
353 5,
354 17,
355 26,
356 40,
357 14,
358 40,
359 44,
360 12,
361 31,
362 45,
363 70,
364 8,
365 38,
366 82,
367 8,
368 12,
369 38,
370 47,
371 70,
372 29,
373 57,
374 97,
375 110,
376 32,
377 48,
378 84,
379 124,
380 155,
381 26,
382 69,
383 83,
384 157,
385 171,
386 8,
387 22,
388 112,
389 205,
390 15,
391 31,
392 61,
393 105,
394 127,
395 212,
396 12,
397 57,
398 109,
399 133,
400 179,
401 210,
402 231,
403 34,
404 161,
405 199,
406 222,
407 255,
408 59,
409 120,
410 218,
411 237,
412 278,
413 341,
414 54,
415 110,
416 176,
417 218,
418 280,
419 369,
420 17,
421 97,
422 193,
423 221,
424 331,
425 350,
426 419,
427 21,
428 85,
429 173,
430 221,
431 243,
432 288,
433 424,
434 45,
435 78,
436 173,
437 213,
438 288,
439 426,
440 455,
441 138,
442};
443static MDB_THREAD_LOCAL double *quasi = NULL;
444
445int32_t power(int32_t a, int32_t b, int32_t m) {
446 int32_t i, c = 1;
447 for (i = 0; i < b; i++)
448 c = (c * a) % m;
449 return c;
450}
451
452int32_t primes() {
453 int32_t i, j, a[MAX_D + 1];
454 for (a[1] = 0, i = 2; i <= MAX_D; i++)
455 a[i] = 1;
456 for (i = 2; i <= MAX_D / 2; i++)
457 for (j = 2; j <= MAX_D / i; j++)
458 a[i * j] = 0;
459 for (i = 1, j = 0; i <= MAX_D; i++) {
460 if (a[i]) {
461 prime[j] = i;
462 iprime[j] = (double)i;
463 j++;
464 }
465 }
466 return j;
467}
468
469int inhalt(int dimen, int atmost, double tiny, double *quasi) {
470 double delta;
471 int i /*,m*/;
472
473 /* check dimen */
474 sDim = dimen;
475 if (sDim < 1 || sDim > 1000)
476 return (-1);
477
478 /* compute and check tolerance*/
479
480 eError = 0.9 * (1.0 / (atmost * prime[sDim - 1]) - 10.0 * tiny);
481 delta = 100 * tiny * (double)(atmost + 1) * log10((double)atmost);
482 if (delta >= 0.09 * (eError - 10.0 * tiny))
483 return (-2);
484
485 /* now compute first vector */
486
487 /*m=1;*/
488 for (i = 0; i < sDim; i++) {
489 iprime[i] = 1.0 / prime[i];
490 quasi[i] = iprime[i];
491 /*m=i*prime[i];*/
492 nextPoint[i] = 2;
493 }
494
495 /*printf("largest prime=%d, %d \n",prime[sDim-1], m);*/
496
497 return 0;
498}
499
500/**
501 * @brief Start a modified Halton sequence.
502 *
503 * Initializes a modified Halton sequence with predefined prime bases and internal parameters.
504 *
505 * @param radix Pointer to an integer to store the chosen prime radix.
506 * @param tiny A small tolerance value.
507 * @return The sequence ID (1-based) on success, or -1 on failure.
508 */
509int32_t startModHaltonSequence(int32_t *radix, double tiny) {
510 int32_t modID, dimen = 12, total_points = 100000;
511 tiny = 0;
512 /* check dimen*/
513 if (!modSequenceInUse) {
514 /*generate primes
515 primes(); */
516 /* commented out primes generation and put it as global constants to skip generate it every time when start the sequence*/
517 if (!quasi)
518 quasi = malloc(sizeof(*quasi) * sDim);
519 if (inhalt(dimen, total_points, tiny, quasi) < 0) {
520 fprintf(stderr, "Unable to start modHalton sequence.\n");
521 return -1;
522 }
523 }
524 modID = modSequenceInUse;
525 *radix = prime[modID];
526 modSequenceInUse++;
527 return modID + 1;
528}
529
530/**
531 * @brief Restart an existing modified Halton sequence.
532 *
533 * Resets internal parameters so that the modified Halton sequence restarts.
534 *
535 * @param ID The sequence ID.
536 * @param tiny A small tolerance value.
537 * @return 1 on success, or -1 on failure.
538 */
539int32_t restartModHaltonSequence(long ID, double tiny) {
540 int32_t dimen = 12, total_points = 100000;
541
542 tiny = 0;
543 if (inhalt(dimen, total_points, tiny, quasi) < 0) {
544 fprintf(stderr, "Unable to start modHalton sequence.\n");
545 return -1;
546 }
547
548 return 1;
549}
550
551int32_t generateModHaltSequence(double *quasi, double *dq, double *wq, long ID) {
552 int32_t i = (int32_t)ID, j, k, ytemp[40], xtemp[40], ltemp, mtemp;
553 double t, f, g, h;
554 /* generate quasi one compoment at a time using radix prime[k] for
555 component k */
556
557 t = iprime[i];
558 f = 1.0 - quasi[i];
559 g = 1.0;
560 h = t;
561 while ((f - h) < eError)
562 /* this checks whether q+h>1-eError */
563 {
564 g = h;
565 h *= t;
566 }
567 quasi[i] = g + h - f;
568
569 k = 0;
570 mtemp = nextPoint[i];
571 ltemp = prime[i];
572
573 while (mtemp != 0) {
574 ytemp[k] = mtemp % ltemp;
575 mtemp = mtemp / ltemp;
576 k++;
577 }
578 /*generating Optimal primitive root */
579 for (j = 0; j < k; j++) {
580 /* xtemp[j] = (ytemp[j]*power(primroots[i/10][i%10], nextn%ltemp, ltemp))%ltemp; */
581 xtemp[j] = (warnockOpt[i] * power(primroots[i / 10][i % 10], ytemp[j], ltemp)) % ltemp;
582 xtemp[j] -= ytemp[j];
583 }
584 dq[i] = 0;
585 t = iprime[i];
586 for (j = 0; j < k; j++) {
587 dq[i] += xtemp[j] * t;
588 t *= iprime[i];
589 }
590 dq[i] += quasi[i];
591 /* generating Warnock Optimal sequences */
592 for (j = 0; j < k; j++) {
593 /* if( i%2==0)xtemp[j]= (ytemp[j]*warnockOpt[i])%ltemp;
594 else xtemp[j]= (ytemp[j]*warnockOpt[i]*warnockOpt[i])%ltemp;
595 */
596 xtemp[j] = (ytemp[j] * power(warnockOpt[i], i + 1, ltemp)) % ltemp;
597 /* if(i>=3)
598 xtemp[j]=((prime[i-1]-1)*power(warnockOpt[i],ytemp[j],ltemp))%ltemp;
599 else xtemp[j]= (power(warnockOpt[i],ytemp[j],ltemp))%ltemp;
600 */
601 xtemp[j] -= ytemp[j];
602 }
603
604 wq[i] = 0;
605 t = iprime[i];
606 for (j = 0; j < k; j++) {
607 wq[i] += xtemp[j] * t;
608 t *= iprime[i];
609 }
610 wq[i] += quasi[i];
611
612 nextPoint[i]++;
613
614 return (0);
615}
616
617/**
618 * @brief Retrieve the next point from the modified Halton sequence.
619 *
620 * Generates and returns the next value for a given sequence ID in the modified Halton sequence.
621 *
622 * @param ID The sequence ID.
623 * @return The next point in the modified Halton sequence.
624 */
626 static MDB_THREAD_LOCAL double *dq = NULL, *wq = NULL;
627
628 ID -= 1;
629 if (dq == NULL)
630 dq = malloc(sizeof(*dq) * sDim);
631 if (wq == NULL)
632 wq = malloc(sizeof(*wq) * sDim);
633 if (!modSequenceInUse) {
634 fprintf(stderr, "ModHalton sequence not started.\n");
635 exit(1);
636 }
637 if (ID < 0 || ID > sDim - 1) {
638 fprintf(stderr, "Invalid ID (%ld) provided\n", ID);
639 exit(1);
640 }
641 generateModHaltSequence(quasi, dq, wq, ID);
642
643 return wq[ID];
644}
int64_t is_prime(int64_t number)
Determine if a number is prime.
Definition factorize.c:26
int32_t startModHaltonSequence(int32_t *radix, double tiny)
Start a modified Halton sequence.
Definition halton.c:509
double nextModHaltonSequencePoint(long ID)
Retrieve the next point from the modified Halton sequence.
Definition halton.c:625
int32_t restartHaltonSequence(long ID, double value)
Restart an existing Halton sequence from a new initial value.
Definition halton.c:88
int32_t startHaltonSequence(int32_t *radix, double value)
Initialize and start a new Halton sequence.
Definition halton.c:38
int32_t restartModHaltonSequence(long ID, double tiny)
Restart an existing modified Halton sequence.
Definition halton.c:539
double nextHaltonSequencePoint(long ID)
Get the next point in a Halton sequence.
Definition halton.c:107