package umontreal.iro.lecuyer.hups;
/* *
* Title:
* Description:
* Copyright: Copyright (c)
* Company:
* @author
* @version 1.0
*/
import umontreal.iro.lecuyer.util.PrintfFormat;
import umontreal.iro.lecuyer.rng.RandomStream;
/**
* This class implements point sets defined by integration
* lattices of rank 1, defined as follows.
* One selects an arbitrary positive integer n and a s-dimensional
* integer vector
* (a0,..., as-1), where
* 0 <= aj < n for each j.
* Usually, a0 = 1. The points are defined by
*
*
*
* ui = (i/n)(a0, a1,…, as-1) mod 1
*
* for
* i = 0,..., n - 1.
* These n points are distinct provided that n and the aj's have
* no common factor.
*
*/
public class Rank1Lattice extends PointSet {
protected int[] genAs; // Lattice generator: a[i]
protected double[] v; // Lattice vector: v[i] = a[i]/n
protected double normFactor; // 1/n.
protected double[] shift; // Random shift, initially null.
/**
* Instantiates a {@link Rank1Lattice} with n points and lattice
* vector a of dimension s.
*
* @param n there are n points
*
* @param a the lattice vector
*
* @param s dimension of the lattice vector a
*
*/
public Rank1Lattice (int n, int[] a, int s) {
dim = s;
numPoints = n;
normFactor = 1.0 / (double) n;
v = new double[s];
genAs = new int[s];
for (int j = 0; j < s; j++) {
if (a[j] < 0 || a[j] >= n)
throw new IllegalArgumentException
("Rank1Lattice must have 0 <= a[j] < n");
v[j] = normFactor * a[j];
genAs[j] = a[j];
}
}
/**
* Returns the generator aj of the lattice. Its components
* are returned as a[j], for
* j = 0, 1,…,(s - 1).
*
*/
public int[] getAs() {
return genAs;
}
/**
* Adds a random shift to all the points of the point set,
* using stream stream to generate the random numbers.
* For each coordinate j from d1 to d2-1,
* the shift dj is generated uniformly over [0, 1) and added modulo 1 to
* all the coordinates of all the points.
*
* @param d1 lower dimension of shift
*
* @param d2 upper dimension of shift is d2 - 1
*
* @param stream random number stream used to generate uniforms
*
*
*/
public void addRandomShift (int d1, int d2, RandomStream stream) {
if (null == stream)
throw new IllegalArgumentException (
PrintfFormat.NEWLINE +
" Calling addRandomShift with null stream");
if (0 == d2)
d2 = Math.max (1, dim);
if (shift == null) {
shift = new double[d2];
capacityShift = d2;
} else if (d2 > capacityShift) {
int d3 = Math.max (4, capacityShift);
while (d2 > d3)
d3 *= 2;
double[] temp = new double[d3];
capacityShift = d3;
for (int i = 0; i < d1; i++)
temp[i] = shift[i];
shift = temp;
}
dimShift = d2;
for (int i = d1; i < d2; i++)
shift[i] = stream.nextDouble ();
shiftStream = stream;
}
/**
* Clears the random shift.
*
*/
public void clearRandomShift() {
super.clearRandomShift();
shift = null;
}
public String toString() {
StringBuffer sb = new StringBuffer ("Rank1Lattice:" +
PrintfFormat.NEWLINE);
sb.append (super.toString());
return sb.toString();
}
public double getCoordinate (int i, int j) {
double x = (v[j] * i) % 1.0;
if (shift != null) {
if (j >= dimShift) // Extend the shift.
addRandomShift (dimShift, j + 1, shiftStream);
x += shift[j];
if (x >= 1.0)
x -= 1.0;
if (x <= 0.0)
x = EpsilonHalf; // avoid x = 0
}
return x;
}
// Recursive method that computes a^e mod m.
protected long modPower (long a, int e, int m) {
// If parameters a and m == numPoints could be omitted, then
// the routine would run much faster due to reduced stack usage.
// Note that a can be larger than m, e.g. in lattice sequences !
if (e == 0)
return 1;
else if (e == 1)
return a % m;
else if ((e & 1) == 1)
return (a * modPower(a, e - 1, m)) % m;
else {
long p = modPower(a, e / 2, m);
return (p * p) % m;
}
}
protected double radicalInverse (int base, int i) {
double digit, radical, inverse;
digit = radical = 1.0 / (double) base;
for (inverse = 0.0; i > 0; i /= base) {
inverse += digit * (double) (i % base);
digit *= radical;
}
return inverse;
}
public PointSetIterator iterator() {
return new Rank1LatticeIterator();
}
// ************************************************************************
protected class Rank1LatticeIterator extends PointSet.DefaultPointSetIterator
{
public double nextCoordinate() {
// I tried with long's and with double's. The double version is
// 4.5 times faster than the long version.
if (curPointIndex >= numPoints || curCoordIndex >= dim)
outOfBounds();
// return (curPointIndex * v[curCoordIndex++]) % 1.0;
double x = (curPointIndex * v[curCoordIndex]) % 1.0;
if (shift != null) {
if (curCoordIndex >= dimShift) // Extend the shift.
addRandomShift (dimShift, curCoordIndex + 1, shiftStream);
x += shift[curCoordIndex];
if (x >= 1.0)
x -= 1.0;
if (x <= 0.0)
x = EpsilonHalf; // avoid x = 0
}
curCoordIndex++;
return x;
}
}
}
Ads help maintain this website.