package umontreal.iro.lecuyer.hups;
/* *
* Title:
* Description:
* Copyright: Copyright (c)
* Company:
* @author
* @version 1.0
*/
/**
* This class implements basic methods for working with radical
* inverses of integers in an arbitrary basis b.
* These methods are used in classes that implement
* point sets and sequences based on the van der Corput sequence
* (the Hammersley nets and the Halton sequence, for example).
*
*
* We recall that for a k-digit integer i whose digital
* b-ary expansion is
*
*
*
* i = a0 + a1b + ... + ak-1bk-1,
*
* the radical inverse in base b is
*
*
*
* ψb(i) = a0b-1 + a1b-2 + ... + ak-1b-k.
*
* The van der Corput sequence in base b is the sequence
*
* ψb(0), ψb(1), ψb(2),...
*
*
* Note that ψb(i) cannot always be represented exactly
* as a floating-point number on the computer (e.g., if b is not
* a power of two). For an exact representation, one can use the integer
*
*
*
* bkψb(i) = ak-1 + ... + a1bk-2 + a0bk-1,
*
* which we called the integer radical inverse representation.
* This representation is simply a mirror image of the digits of the
* usual b-ary representation of i.
*
*
* It is common practice to permute locally the values of the
* van der Corput sequence. One way of doing this is to apply a
* permutation to the digits of i before computing ψb(i).
* That is, for a permutation π of the digits
* {0,..., b - 1},
*
*
*
* ψb(i) = ∑r=0k-1arb-r-1
*
* is replaced by
*
*
*
* ∑r=0k-1π(ar)b-r-1.
*
* Applying such a permutation only changes the order in which the
* values of ψb(i) are enumerated. For every integer k, the first
* bk values that are enumerated remain the same (they are the values
* of ψb(i) for
* i = 0,..., bk - 1), but they are enumerated in a
* different order. Often, different permutations π will be applied
* for different coordinates of a point set.
*
*
* The permutation π can be deterministic or random. One (deterministic)
* possibility implemented here is the Faure permutation σb of
*
* {0,..., b - 1} defined as follows.
*
* For b = 2, take
* σ = I, the identical permutation. For even
* b = 2c > 2, take
*
*
*
*
* σ[i]
* =
* 2τ[i] i = 0, 1,…, c - 1
*
*
* σ[i + c]
* =
* 2τ[i] + 1 i = 0, 1,…, c - 1
*
*
*
*
*
* where τ[i] is the Faure
* permutation for base c. For odd b = 2c + 1,
* take
*
*
*
*
* σ[c]
* =
* c
*
*
* σ[i]
* =
* τ[i], if 0 <= τ[i] < c
*
*
* σ[i]
* =
* τ[i] + 1, if c <= τ[i] < 2c
*
*
*
*
*
* for
* 0 <= i < c, and take
*
*
*
*
* σ[i]
* =
* τ[i - 1], if 0 <= τ[i - 1] < c
*
*
* σ[i]
* =
* τ[i - 1] + 1, if c <= τ[i - 1] < 2c
*
*
*
*
*
* for
* c < i <= 2c, and where τ[i] is the Faure
* permutation for base c. The Faure permutations give very small
* discrepancies (amongst the best known today) for small bases.
*
*/
public class RadicalInverse {
private static final int NP = 168; // First NP primes in table below.
private static final int PLIM = 1000; // NP primes < PLIM
// The first NP prime numbers
private static final int[] PRIMES = {
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139,
149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223,
227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293,
307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383,
389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569,
571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647,
653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743,
751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839,
853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
947, 953, 967, 971, 977, 983, 991, 997 };
private static final int NRILIM = 1000; // For nextRadicalInverse
private int b; // Base
private double invb; // 1/b
private double logb; // natural log(b)
private int JMAX; // b^JMAX = 2^32
private int co; // Counter for nextRadicalInverse
private double xx; // Current value of x
private long ix; // xx = RadicalInverse (ix)
/*
// For Struckmeier's algorithm
private static final int PARTITION_MAX = 54; // Size of partitionL, bi
private int partM; // Effective size of partitionL, bi
private double[] bi; // bi[i] = (b + 1)/b^i - 1
private double[] partitionL; // L[i] = 1 - 1/b^i
// Boundaries of Struckmeier partitions Lkp of [0, 1]
*/
/**
* Initializes the base of this object to b
* and its first value of x to x0.
*
* @param b Base
*
* @param x0 Initial value of x
*
*/
public RadicalInverse (int b, double x0) {
co = 0;
this.b = b;
invb = 1.0 / b;
logb = Math.log (b);
JMAX = (int) (32.0 * 0.69314718055994530941 / logb);
xx = x0;
ix = computeI (x0);
// initStruckmeier (b);
}
private long computeI (double x) {
// Compute i such that x = RadicalInverse (i).
int[] digits = new int[JMAX]; // Digits of x
int j;
for (j = 0; (j < JMAX) && (x > 0.5e-15); j++) {
x *= b;
digits[j] = (int) x;
x -= digits[j];
}
long i = 0;
for (j = JMAX - 1; j >= 0; j--) {
i = i * b + digits[j];
}
return i;
}
/**
* Provides an elementary method for obtaining the first n prime
* numbers larger than 1.
* Creates and returns an array that contains
* these numbers. This is useful for determining the prime bases for
* the different coordinates of the Halton sequence and Hammersley nets.
*
* @param n number of prime numbers to return
*
* @return an array with the first n prime numbers
*
*/
public static int[] getPrimes (int n) {
// Allocates an array of size n filled with the first n prime
// numbers. n must be positive (n > 0). Routine may fail if not enough
// memory for the array is available. The first prime number is 2.
int i;
boolean moreTests;
int[] prime = new int[n];
int n1 = Math.min (NP, n);
for (i = 0; i < n1; i++)
prime[i] = PRIMES[i];
if (NP < n) {
i = NP;
for (int candidate = PLIM + 1; i < n; candidate += 2) {
prime[i] = candidate;
for (int j = 1; (moreTests = prime[j] <= candidate / prime[j])
&& ((candidate % prime[j]) > 0); j++);
if (! moreTests)
i++;
}
}
return prime;
}
/**
* Computes the radical inverse of i in base b.
* If
* i = ∑r=0k-1arbr, the method computes and returns
*
*
*
* x = ∑r=0k-1arb-r-1.
*
*
* @param b base used for the operation
*
* @param i the value for which the radical inverse will be computed
*
* @return the radical inverse of i in base b
*
*/
public static double radicalInverse (int b, long i) {
double digit, radical, inverse;
digit = radical = 1.0 / (double) b;
for (inverse = 0.0; i > 0; i /= b) {
inverse += digit * (double) (i % b);
digit *= radical;
}
return inverse;
}
/**
* A fast method that incrementally computes the radical inverse xi+1
* in base b from xi = x = ψb(i),
*
* using addition with rigthward carry.
* The parameter invb is equal to 1/b.
* Using long incremental streams (i.e., calling this method several times
* in a row) cause increasing inaccuracy in x. Thus the user should
* recompute the radical inverse directly by calling
* {@link #radicalInverse radicalInverse} every once in a while (i.e. in every few
* thousand calls).
*
* @param invb 1/b where b is the base
*
* @param x the inverse xi
*
* @return the radical inverse xi+1
*
*/
public static double nextRadicalInverse (double invb, double x) {
// Calculates the next radical inverse from x in base b.
// Repeated application causes a loss of accuracy.
// Note that x can be any number from [0,1).
final double ALMOST_ONE = 1.0 - 1e-10;
double nextInverse = x + invb;
if (nextInverse < ALMOST_ONE)
return nextInverse;
else {
double digit1 = invb;
double digit2 = invb * invb;
while (x + digit2 >= ALMOST_ONE) {
digit1 = digit2;
digit2 *= invb;
}
return x + (digit1 - 1.0) + digit2;
}
}
/**
* A fast method that incrementally computes the radical inverse xi+1
* in base b from xi = ψb(i),
* using addition with rigthward carry as described in
* Wang and Hickernell.
* Since using long incremental streams (i.e., calling this method several
* times in a row) cause increasing inaccuracy in x, the method
* recomputes the radical inverse directly from i by calling
* {@link #radicalInverse radicalInverse} once in every 1000 calls.
*
* @return the radical inverse xi+1
*
*
*/
public double nextRadicalInverse () {
// Calculates the next radical inverse from xx in base b.
// Repeated application causes a loss of accuracy.
// For each NRILIM calls, a direct calculation via radicalInverse
// is inserted.
co++;
if (co >= NRILIM) {
co = 0;
ix += NRILIM;
xx = radicalInverse (b, ix);
return xx;
}
final double ALMOST_ONE = 1.0 - 1e-10;
double nextInverse = xx + invb;
if (nextInverse < ALMOST_ONE) {
xx = nextInverse;
return xx;
} else {
double digit1 = invb;
double digit2 = invb * invb;
while (xx + digit2 >= ALMOST_ONE) {
digit1 = digit2;
digit2 *= invb;
}
xx += (digit1 - 1.0) + digit2;
return xx;
}
}
/*
private void initStruckmeier (int b) {
bi = new double[1 + PARTITION_MAX];
partitionL = new double[1 + PARTITION_MAX];
logb = Math.log (b);
partitionL[0] = 0.0;
bi[0] = 1.0;
int i = 0;
while ((i < PARTITION_MAX) && (partitionL[i] < 1.0)) {
++i;
bi[i] = bi[i - 1] / b;
partitionL[i] = 1.0 - bi[i];
}
partM = i - 1;
for (i = 0; i <= partM + 1; ++i)
bi[i] = (b + 1) * bi[i] - 1.0;
}
public double nextRadicalInverse (double x) {
int k;
if (x < partitionL[partM]) {
k = 1;
// Find k such: partitionL[k-1] <= x < partitionL[k]
while (x >= partitionL[k])
++k;
} else { // x >= partitionL [partM]
k = 1 + (int)(-Math.log(1.0 - x) / logb);
}
return x + bi[k];
} */
/**
* Given the k b-ary digits of i in bdigits, returns the
* k digits of the integer radical inverse of i in idigits.
* This simply reverses the order of the digits.
*
* @param k number of digits in arrays
*
* @param bdigits digits in original order
*
* @param idigits digits in reverse order
*
*
*/
public static void reverseDigits (int k, int bdigits[], int idigits[]) {
for (int l = 0; l < k; l++)
idigits[l] = bdigits[k-l];
}
/**
* Computes the integer radical inverse of i in base b,
* equal to
* bkψb(i) if i has k b-ary digits.
*
* @param b base used for the operation
*
* @param i the value for which the integer radical inverse will be computed
*
* @return the integer radical inverse of i in base b
*
*/
public static int integerRadicalInverse (int b, int i) {
// Simply flips digits of i in base b.
int inverse;
for (inverse = 0; i > 0; i /= b)
inverse = inverse * b + (i % b);
return inverse;
}
/**
* Given the k digits of the integer radical inverse of i in bdigits,
* in base b, this method replaces them by the digits of the integer
* radical inverse of i + 1 and returns their number.
* The array must be large enough to hold this new number of digits.
*
* @param b base
*
* @param k initial number of digits in arrays
*
* @param idigits digits of integer radical inverse
*
* @return new number of digits in arrays
*
*/
public static int nextRadicalInverseDigits (int b, int k, int idigits[]) {
int l;
for (l = k-1; l >= 0; l--)
if (idigits[l] == b-1)
idigits[l] = 0;
else {
idigits[l]++;
return k;
}
if (l == 0) {
idigits[k] = 1;
return ++k;
}
return 0;
}
/**
* Computes the Faure permutation σb of the set
*
* {0,…, b - 1} and puts it in array pi.
*
* See the description in the introduction above.
*
* @param b the base
*
* @param pi an array of size at least b,
* to be filled with the permutation
*
*
*/
public static void getFaurePermutation (int b, int[] pi) {
// This is a recursive implementation.
// Perhaps not the most efficient...
int i;
if (b == 2) {
pi[0] = 0;
pi[1] = 1;
}
else if ((b & 1) != 0) {
// b is odd.
b--;
getFaurePermutation (b, pi);
for (i = 0; i < b; i++)
if (pi[i] >= b / 2)
pi[i]++;
for (i = b; i > b / 2; i--)
pi[i] = pi[i - 1];
pi[b / 2] = b / 2;
}
else {
b /= 2;
getFaurePermutation (b, pi);
for (i = 0; i < b; i++) {
pi[i] *= 2;
pi[i + b] = pi[i] + 1;
}
}
}
/**
* Computes the radical inverse of i in base b, where the digits
* are permuted using the permutation π.
* If
* i = ∑r=0k-1arbr, the method will compute and return
*
*
*
* x = ∑r=0k-1π[ar]b-r-1.
*
*
* @param b base b used for the operation
*
* @param pi an array of length at least b containing the permutation
* used during the computation
*
* @param i the value for which the radical inverse will be computed
*
* @return the radical inverse of i in base b
*
*/
public static double permutedRadicalInverse (int b, int[] pi, int i) {
double digit, radical, inverse;
digit = radical = 1.0 / (double) b;
for (inverse = 0.0; i > 0; i /= b) {
inverse += digit * (double) pi[i % b];
digit *= radical;
}
return inverse;
}
}
Ads help maintain this website.