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.*; /** * This class provides the basic structures for storing and * manipulating linear digital nets in base b, for an arbitrary * base b >= 2. We recall that a net contains n = bk points in * s dimensions, where the ith point * ui, * for * i = 0,..., bk - 1, is defined as follows: *
*

* * * * * * * * * * * * * * * * * * *
i     =     ∑r=0k-1ai, rbr, *  
(ui, j, 1 ui, j, 2 …)T     =     Cj (ai, 0 ai, 1 … ai, k-1)T, *  
ui, j     =     ∑r=1∞ui, j, rb-r, *  
ui     =     (ui, 0, …, ui, s-1). *  
*
* * In our implementation, the matrices * Cj are r×k, * so the expansion of ui, j is truncated to its first r terms. * The points are stored implicitly by storing the generator matrices * * Cj in a large two-dimensional array of integers, * with srk elements. * *

* The points * ui are enumerated using the Gray code * technique. * With this technique, the b-ary representation of i, * * ai = (ai, 0,..., ai, k-1), is replaced by a Gray code representation of i, * * gi = (gi, 0,..., gi, k-1). The Gray code * gi * used here is defined by * gi, k-1 = ai, k-1 and * * * gi, ν = (ai, ν - ai, ν+1)mod b for * ν = 0,..., k - 2. * It has the property that * * gi = (gi, 0,..., gi, k-1) and * * gi+1 = (gi+1, 0,..., gi+1, k-1) * differ only in the position of the smallest index * ν such that * * ai, ν < b - 1, and we have * gi+1, ν = (gi, ν +1)mod b * in that position. * *

* This Gray code representation permits a more efficient enumeration * of the points by the iterators. * It changes the order in which the points * ui are enumerated, * but the first bm points remain the same for every integer m. * The ith point of the sequence with the Gray enumeration * is the i'th point of the original enumeration, where i' is the * integer whose b-ary representation * ai' is given by the Gray * code * gi. * To enumerate all the points successively, we never need to compute * the Gray codes explicitly. * It suffices to know the position ν of the Gray code digit * that changes at each step, and this can be found quickly from the * b-ary representation * ai. * The digits of each coordinate j of the current point can be updated by * adding column ν of the generator matrix * Cj to the old digits, * modulo b. * *

* One should avoid using the method {@link #getCoordinate getCoordinate}(i, j) * for arbitrary values of i and j, because this is much * slower than using an iterator to access successive coordinates. * *

* Digital nets can be randomized in various ways. * Several types of randomizations specialized for nets are implemented * directly in this class. * *

* A simple but important randomization is the random digital shift * in base b, defined as follows: replace each digit * ui, j, ν in the third equation above * by * (ui, j, ν + dj, ν)mod b, * where the dj, ν's are i.i.d. uniform over * {0,..., b - 1}. * This is equivalent to applying a single random shift to all the points * in a formal series representation of their coordinates. * In practice, the digital shift is truncated to w digits, * for some integer w >= r. * Applying a digital shift does not change the equidistribution * and (t, m, s)-net properties of a point set. * Moreover, with the random shift, each point is uniformly distributed over * the unit hypercube (but the points are not independent, of course). * *

* A second class of randomizations specialized for digital nets * are the linear matrix scrambles, which multiply the matrices * * Cj * by a random invertible matrix * Mj, modulo b. * There are several variants, depending on how * Mj is generated, and on * whether * Cj is multiplied on the left or on the right. * In our implementation, the linear matrix scrambles are incorporated directly * into the matrices * Cj, so they * do not slow down the enumeration of points. * Methods are available for applying * linear matrix scrambles and for removing these randomizations. * These methods generate the appropriate random numbers and make * the corresponding changes to the * Cj's. * A copy of the original * Cj's is maintained, so the point * set can be returned to its original unscrambled state at any time. * When a new linear matrix scramble is applied, it is always applied to * the original generator matrices. * The method {@link #resetGeneratorMatrices resetGeneratorMatrices} removes the current matrix * scramble by resetting the generator matrices to their original state. * On the other hand, the method {@link #eraseOriginalGeneratorMatrices eraseOriginalGeneratorMatrices} * replaces the original generator matrices by the current * ones, making the changes permanent. * This is useful if one wishes to apply two or more linear matrix * scrambles on top of each other. * *

* Linear matrix scrambles are usually combined with a random digital shift; * this combination is called an affine matrix scramble. * These two randomizations are applied via separate methods. * The linear matrix scrambles are incorporated into the matrices * Cj * whereas the digital random shift is stored and applied separately, * independently of the other scramblings. * *

* Applying a digital shift or a linear matrix scramble to a digital net * invalidates all iterators for that randomized point, * because each iterator uses a * cached copy of the current point, which is updated only when * the current point index of that iterator changes, and the update also * depends on the cached copy of the previous point. * After applying any kind of scrambling, the iterators must be * reinitialized to the initial point by invoking * {@link PointSetIterator#resetCurPointIndex resetCurPointIndex} * or reinstantiated by the {@link #iterator iterator} method * (this is not done automatically). * */ public class DigitalNet extends PointSet { // Variables to be initialized by the constructor subclasses. protected int b = 0; // Base. protected int numCols = 0; // The number of columns in each C_j. (= k) protected int numRows = 0; // The number of rows in each C_j. (= r) protected int outDigits = 0; // Number of output digits (= w) private int[][] originalMat; // Original gen. matrices without randomizat. protected int[][] genMat; // The current generator matrices. // genMat[j*numCols+c][l] contains column c // and row l of C_j. protected int[][] digitalShift; // The digital shift, initially zero (null). // Entry [j][l] is for dimension j, digit l, // for 0 <= l < outDigits. protected double normFactor; // To convert output to (0,1); 1/b^outDigits. protected double[] factor; // Lookup table in ascending order: factor[i] // = 1/b^{i+1} for 0 <= i < outDigits. // primes gives the first index in array FaureFactor // for the prime p. If primes[i] = p, then // FaureFactor[p][j] contains the Faure ordered factors of base p. private int[] primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67}; // Factors on the diagonal corresponding to base b = prime[i] ordered by // increasing Bounds. private int[][] FaureFactor = {{1}, {1, 2}, {2, 3, 1, 4}, { 2, 3, 4, 5, 1, 6}, {3, 4, 7, 8, 2, 5, 6, 9, 1, 10}, { 5, 8, 3, 4, 9, 10, 2, 6, 7, 11, 1, 12}, { 5, 7, 10, 12, 3, 6, 11, 14, 4, 13, 2, 8, 9, 15, 1, 16}, { 7, 8, 11, 12, 4, 5, 14, 15, 3, 6, 13, 16, 2, 9, 10, 17, 1, 18}, { 5, 9, 14, 18, 7, 10, 13, 16, 4, 6, 17, 19, 3, 8, 15, 20, 2, 11, 12, 21, 1, 22}, { 8, 11, 18, 21, 12, 17, 9, 13, 16, 20, 5, 6, 23, 24, 4, 7, 22, 25, 3, 10, 19, 26, 2, 14, 15, 27, 1, 28}, { 12, 13, 18, 19, 11, 14, 17, 20, 7, 9, 22, 24, 4, 8, 23, 27, 5, 6, 25, 26, 3, 10, 21, 28, 2, 15, 16, 29, 1, 30}, { 8, 14, 23, 29, 10, 11, 26, 27, 13, 17, 20, 24, 7, 16, 21, 30, 5, 15, 22, 32, 6, 31, 4, 9, 28, 33, 3, 12, 25, 34, 2, 18, 19, 35, 1, 36}, { 16, 18, 23, 25, 11, 15, 26, 30, 12, 17, 24, 29, 9, 32, 13, 19, 22, 28, 6, 7, 34, 35, 5, 8, 33, 36, 4, 10, 31, 37, 3, 14, 27, 38, 2, 20, 21, 39, 1, 40}, { 12, 18, 25, 31, 9, 19, 24, 34, 8, 16, 27, 35, 10, 13, 30, 33, 15, 20, 23, 28, 5, 17, 26, 38, 6, 7, 36, 37, 4, 11, 32, 39, 3, 14, 29, 40, 2, 21, 22, 41, 1, 42}, { 13, 18, 29, 34, 11, 17, 30, 36, 10, 14, 33, 37, 7, 20, 27, 40, 9, 21, 26, 38, 15, 22, 25, 32, 6, 8, 39, 41, 5, 19, 28, 42, 4, 12, 35, 43, 3, 16, 31, 44, 2, 23, 24, 45, 1, 46}, { 14, 19, 34, 39, 23, 30, 12, 22, 31, 41, 8, 11, 20, 24, 29, 33, 42, 45, 10, 16, 37, 43, 7, 15, 38, 46, 17, 25, 28, 36, 5, 21, 32, 48, 6, 9, 44, 47, 4, 13, 40, 49, 3, 18, 35, 50, 2, 26, 27, 51, 1, 52}, { 25, 26, 33, 34, 18, 23, 36, 41, 14, 21, 38, 45, 24, 27, 32, 35, 11, 16, 43, 48, 9, 13, 46, 50, 8, 22, 37, 51, 7, 17, 42, 52, 19, 28, 31, 40, 6, 10, 49, 53, 5, 12, 47, 54, 4, 15, 44, 55, 3, 20, 39, 56, 2, 29, 30, 57, 1, 58}, { 22, 25, 36, 39, 17, 18, 43, 44, 24, 28, 33, 37, 13, 14, 47, 48, 16, 19, 42, 45, 9, 27, 34, 52, 8, 23, 38, 53, 11, 50, 7, 26, 35, 54, 21, 29, 32, 40, 6, 10, 51, 55, 5, 12, 49, 56, 4, 15, 46, 57, 3, 20, 41, 58, 2, 30, 31, 59, 1, 60}, { 18, 26, 41, 49, 14, 24, 43, 53, 12, 28, 39, 55, 29, 30, 37, 38, 10, 20, 47, 57, 16, 21, 46, 51, 8, 25, 42, 59, 13, 31, 36, 54, 9, 15, 52, 58, 7, 19, 48, 60, 23, 32, 35, 44, 5, 27, 40, 62, 6, 11, 56, 61, 4, 17, 50, 63, 3, 22, 45, 64, 2, 33, 34, 65, 1, 66} }; public double getCoordinate (int i, int j) { // convert i to Gray representation, put digits in gdigit[]. int l, c, sum; int[] bdigit = new int[numCols]; int[] gdigit = new int[numCols]; int idigits = intToDigitsGray (b, i, numCols, bdigit, gdigit); double result = 0; if (digitalShift != null && dimShift < j) addRandomShift (dimShift, j, shiftStream); for (l = 0; l < outDigits; l++) { if (digitalShift == null) sum = 0; else sum = digitalShift[j][l]; if (l < numRows) for (c = 0; c < idigits; c++) sum += genMat[j*numCols+c][l] * gdigit[c]; result += (sum % b) * factor[l]; } if (digitalShift != null) result += EpsilonHalf; return result; } public PointSetIterator iterator() { return new DigitalNetIterator(); } /** * Empty constructor. * */ public DigitalNet () { } /** * Returns ui, j, the coordinate j of point i, the points * being enumerated in the standard order (no Gray code). * * @param i point index * * @param j coordinate index * * @return the value of ui, j * */ public double getCoordinateNoGray (int i, int j) { // convert i to b-ary representation, put digits in bdigit[]. int l, c, sum; int[] bdigit = new int[numCols]; int idigits = 0; for (c = 0; i > 0; c++) { idigits++; bdigit[c] = i % b; i = i / b; } if (digitalShift != null && dimShift < j) addRandomShift (dimShift, j, shiftStream); double result = 0; for (l = 0; l < outDigits; l++) { if (digitalShift == null) sum = 0; else sum = digitalShift[j][l]; if (l < numRows) for (c = 0; c < idigits; c++) sum += genMat[j*numCols+c][l] * bdigit[c]; result += (sum % b) * factor[l]; } if (digitalShift != null) result += EpsilonHalf; return result; } /** * This iterator does not use the Gray code. Thus the points are enumerated * in the order of their first coordinate before randomization. * */ public PointSetIterator iteratorNoGray() { return new DigitalNetIteratorNoGray(); } /** * Adds a random digital 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 vector * (dj, 0,..., dj, k-1) * is generated uniformly over * {0,..., b - 1}k and added modulo b to * the digits of all the points. * After adding a digital shift, all iterators must be reconstructed or * reset to zero. * * @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 (digitalShift == null) { digitalShift = new int[d2][outDigits]; capacityShift = d2; } else if (d2 > capacityShift) { int d3 = Math.max (4, capacityShift); while (d2 > d3) d3 *= 2; int[][] temp = new int[d3][outDigits]; capacityShift = d3; for (int i = 0; i < d1; i++) for (int j = 0; j < outDigits; j++) temp[i][j] = digitalShift[i][j]; digitalShift = temp; } for (int i = d1; i < d2; i++) for (int j = 0; j < outDigits; j++) digitalShift[i][j] = stream.nextInt (0, b - 1); dimShift = d2; shiftStream = stream; } /** * Same as {@link #addRandomShift addRandomShift}(0, dim, stream), * where dim is the dimension of the digital net. * * @param stream random number stream used to generate uniforms * * */ public void addRandomShift (RandomStream stream) { addRandomShift (0, dim, stream); } public void clearRandomShift() { super.clearRandomShift(); digitalShift = null; } public String toString() { StringBuffer sb = new StringBuffer (100); if (b > 0) { sb.append ("Base = "); sb.append (b); sb.append (PrintfFormat.NEWLINE); } sb.append ("Num cols = "); sb.append (numCols); sb.append (PrintfFormat.NEWLINE + "Num rows = "); sb.append (numRows); sb.append (PrintfFormat.NEWLINE + "outDigits = "); sb.append (outDigits); return sb.toString(); } // Print matrices M for dimensions 0 to N-1. private void printMat (int N, int[][][] A, String name) { for (int i = 0; i < N; i++) { System.out.println ("-------------------------------------" + PrintfFormat.NEWLINE + name + " dim = " + i); int l, c; // row l, column c, dimension i for A[i][l][c]. for (l = 0; l < numRows; l++) { for (c = 0; c < numCols; c++) { System.out.print (A[i][l][c] + " "); } System.out.println (""); } } System.out.println (""); } // Print matrix M private void printMat0 (int[][] A, String name) { System.out.println ("-------------------------------------" + PrintfFormat.NEWLINE + name); int l, c; // row l, column c for A[l][c]. for (l = 0; l < numCols; l++) { for (c = 0; c < numCols; c++) { System.out.print (A[l][c] + " "); } System.out.println (""); } System.out.println (""); } // Left-multiplies lower-triangular matrix Mj by original C_j, // where original C_j is in originalMat and result is in genMat. // This implementation is safe only if (numRows*(b-1)^2) is a valid int. private void leftMultiplyMat (int j, int[][] Mj) { int l, c, i, sum; // Dimension j, row l, column c for new C_j. for (l = 0; l < numRows ; l++) { for (c = 0; c < numCols; c++) { // Multiply row l of M_j by column c of C_j. sum = 0; for (i = 0; i <= l; i++) sum += Mj[l][i] * originalMat[j*numCols+c][i]; genMat[j*numCols+c][l] = sum % b; } } } // Left-multiplies diagonal matrix Mj by original C_j, // where original C_j is in originalMat and result is in genMat. // This implementation is safe only if (numRows*(b-1)^2) is a valid int. private void leftMultiplyMatDiag (int j, int[][] Mj) { int l, c, sum; // Dimension j, row l, column c for new C_j. for (l = 0; l < numRows ; l++) { for (c = 0; c < numCols; c++) { // Multiply row l of M_j by column c of C_j. sum = Mj[l][l] * originalMat[j*numCols+c][l]; genMat[j*numCols+c][l] = sum % b; } } } // Right-multiplies original C_j by upper-triangular matrix Mj, // where original C_j is in originalMat and result is in genMat. // This implementation is safe only if (numCols*(b-1)^2) is a valid int. private void rightMultiplyMat (int j, int[][] Mj) { int l, c, i, sum; // Dimension j, row l, column c for new C_j. for (l = 0; l < numRows ; l++) { for (c = 0; c < numCols; c++) { // Multiply row l of C_j by column c of M_j. sum = 0; for (i = 0; i <= c; i++) sum += originalMat[j*numCols+i][l] * Mj[i][c]; genMat[j*numCols+c][l] = sum % b; } } } private int getFaureIndex (String method, int sb, int flag) { // Check for errors in ...FaurePermut. Returns the index ib of the // base b in primes, i.e. b = primes[ib]. if (sb >= b) throw new IllegalArgumentException (PrintfFormat.NEWLINE + " sb >= base in " + method); if (sb < 1) throw new IllegalArgumentException (PrintfFormat.NEWLINE + " sb = 0 in " + method); if ((flag > 2) || (flag < 0)) throw new IllegalArgumentException ( PrintfFormat.NEWLINE + " lowerFlag not in {0, 1, 2} in " + method); // Find index ib of base in array primes int ib = 0; while ((ib < primes.length) && (primes[ib] < b)) ib++; if (ib >= primes.length) throw new IllegalArgumentException ("base too large in " + method); if (b != primes[ib]) throw new IllegalArgumentException ( "Faure factors are not implemented for this base in " + method); return ib; } /** * Applies a linear scramble by multiplying each * Cj on the left * by a w×w nonsingular lower-triangular matrix * Mj, * as suggested by Matoušek and implemented * by Hong and Hickernell. The diagonal entries of * each matrix * Mj are generated uniformly over * * {1,..., b - 1}, the entries below the diagonal are generated uniformly * over * {0,..., b - 1}, and all these entries are generated independently. * This means that in base b = 2, all diagonal elements are equal to 1. * * @param stream random number stream used to generate the randomness * * */ public void leftMatrixScramble (RandomStream stream) { int j, l, c; // dimension j, row l, column c. // If genMat contains the original gen. matrices, copy to originalMat. if (originalMat == null) { originalMat = genMat; genMat = new int[dim * numCols][numRows]; } // Constructs the lower-triangular scrambling matrices M_j, r by r. int[][][] scrambleMat = new int[dim][numRows][numRows]; for (j = 0 ; j < dim; j++) { for (l = 0; l < numRows; l++) { for (c = 0; c < numRows; c++) { if (c == l) // No zero on the diagonal. scrambleMat[j][l][c] = stream.nextInt(1, b - 1) ; else if (c < l) scrambleMat[j][l][c] = stream.nextInt(0, b - 1); else scrambleMat[j][l][c] = 0; // Zeros above the diagonal; } } } // Multiply M_j by the generator matrix C_j for each j. for (j = 0 ; j < dim; j++) leftMultiplyMat (j, scrambleMat[j]); } /** * Similar to {@link #leftMatrixScramble leftMatrixScramble} except that all the * off-diagonal elements of the * Mj are 0. * * @param stream random number stream used to generate the randomness * * */ public void leftMatrixScrambleDiag (RandomStream stream) { int j, l, c; // dimension j, row l, column c. // If genMat contains the original gen. matrices, copy to originalMat. if (originalMat == null) { originalMat = genMat; genMat = new int[dim * numCols][numRows]; } // Constructs the diagonal scrambling matrices M_j, r by r. int[][][] scrambleMat = new int[dim][numRows][numRows]; for (j = 0 ; j < dim; j++) { for (l = 0; l < numRows; l++) { for (c = 0; c < numRows; c++) { if (c == l) // No zero on the diagonal. scrambleMat[j][l][c] = stream.nextInt(1, b - 1) ; else scrambleMat[j][l][c] = 0; // Diagonal matrix; } } } // Multiply M_j by the generator matrix C_j for each j. for (j = 0 ; j < dim; j++) leftMultiplyMatDiag (j, scrambleMat[j]); } private void LMSFaurePermut (String method, RandomStream stream, int sb, int lowerFlag) { /* If \texttt{lowerFlag = 2}, the off-diagonal elements below the diagonal of $\mathbf{M}_j$ are chosen as in \method{leftMatrixScramble}{}. If \texttt{lowerFlag = 1}, the off-diagonal elements below the diagonal of $\mathbf{M}_j$ are also chosen from the restricted set. If \texttt{lowerFlag = 0}, the off-diagonal elements of $\mathbf{M}_j$ are all 0. */ int ib = getFaureIndex (method, sb, lowerFlag); // If genMat contains the original gen. matrices, copy to originalMat. if (originalMat == null) { originalMat = genMat; genMat = new int[dim * numCols][numRows]; } // Constructs the lower-triangular scrambling matrices M_j, r by r. int jb; int j, l, c; // dimension j, row l, column c. int[][][] scrambleMat = new int[dim][numRows][numRows]; for (j = 0 ; j < dim; j++) { for (l = 0; l < numRows; l++) { for (c = 0; c < numRows; c++) { if (c == l) { jb = stream.nextInt(0, sb - 1); scrambleMat[j][l][c] = FaureFactor[ib][jb]; } else if (c < l) { if (lowerFlag == 2) { scrambleMat[j][l][c] = stream.nextInt(0, b - 1); } else if (lowerFlag == 1) { jb = stream.nextInt(0, sb - 1); scrambleMat[j][l][c] = FaureFactor[ib][jb]; } else { // lowerFlag == 0 scrambleMat[j][l][c] = 0; } } else scrambleMat[j][l][c] = 0; // Zeros above the diagonal; } } } // printMat (dim, scrambleMat, method); // Multiply M_j by the generator matrix C_j for each j. if (lowerFlag == 0) for (j = 0 ; j < dim; j++) leftMultiplyMatDiag (j, scrambleMat[j]); else for (j = 0 ; j < dim; j++) leftMultiplyMat (j, scrambleMat[j]); } /** * Similar to {@link #leftMatrixScramble leftMatrixScramble} except that the diagonal elements * of each matrix * Mj are chosen from a restricted set of the best * integers as calculated by Faure. They are generated * uniformly over the first sb elements of array F, where F is * made up of a permutation of the integers * [1..(b - 1)]. These integers are * sorted by increasing order of the upper bounds of the extreme discrepancy * for the given integer. * * @param stream random number stream used to generate the randomness * * @param sb Only the first sb elements of F are used * * */ public void leftMatrixScrambleFaurePermut (RandomStream stream, int sb) { LMSFaurePermut ("leftMatrixScrambleFaurePermut", stream, sb, 2); } /** * Similar to {@link #leftMatrixScrambleFaurePermut leftMatrixScrambleFaurePermut} except that all * off-diagonal elements are 0. * * @param stream random number stream used to generate the randomness * * @param sb Only the first sb elements of F are used * * */ public void leftMatrixScrambleFaurePermutDiag (RandomStream stream, int sb) { LMSFaurePermut ("leftMatrixScrambleFaurePermutDiag", stream, sb, 0); } /** * Similar to {@link #leftMatrixScrambleFaurePermut leftMatrixScrambleFaurePermut} except that the * elements under the diagonal are also * chosen from the same restricted set as the diagonal elements. * * @param stream random number stream used to generate the randomness * * @param sb Only the first sb elements of F are used * * */ public void leftMatrixScrambleFaurePermutAll (RandomStream stream, int sb) { LMSFaurePermut ("leftMatrixScrambleFaurePermutAll", stream, sb, 1); } /** * Applies the i-binomial matrix scramble proposed by Tezuka * . * This multiplies each * Cj on the left * by a w×w nonsingular lower-triangular matrix * Mj as in * {@link #leftMatrixScramble leftMatrixScramble}, but with the additional constraint that * all entries on any given diagonal or subdiagonal of * Mj are identical. * * @param stream random number stream used as generator of the randomness * * */ public void iBinomialMatrixScramble (RandomStream stream) { int j, l, c; // dimension j, row l, column c. int diag; // random entry on the diagonal; int col1; // random entries below the diagonal; // If genMat is original generator matrices, copy it to originalMat. if (originalMat == null) { originalMat = genMat; genMat = new int[dim * numCols][numRows]; } // Constructs the lower-triangular scrambling matrices M_j, r by r. int[][][] scrambleMat = new int[dim][numRows][numRows]; for (j = 0 ; j < dim; j++) { diag = stream.nextInt(1, b - 1); for (l = 0; l < numRows; l++) { // Single random nonzero element on the diagonal. scrambleMat[j][l][l] = diag; for (c = l+1; c < numRows; c++) scrambleMat[j][l][c] = 0; } for (l = 1; l < numRows; l++) { col1 = stream.nextInt(0, b - 1); for (c = 0; l+c < numRows; c++) scrambleMat[j][l+c][c] = col1; } } // printMat (dim, scrambleMat, "iBinomialMatrixScramble"); for (j = 0 ; j < dim; j++) leftMultiplyMat (j, scrambleMat[j]); } private void iBMSFaurePermut (String method, RandomStream stream, int sb, int lowerFlag) { int ib = getFaureIndex (method, sb, lowerFlag); // If genMat is original generator matrices, copy it to originalMat. if (originalMat == null) { originalMat = genMat; genMat = new int[dim * numCols][numRows]; } // Constructs the lower-triangular scrambling matrices M_j, r by r. int j, l, c; // dimension j, row l, column c. int diag; // random entry on the diagonal; int col1; // random entries below the diagonal; int jb; int[][][] scrambleMat = new int[dim][numRows][numRows]; for (j = 0 ; j < dim; j++) { jb = stream.nextInt(0, sb - 1); diag = FaureFactor[ib][jb]; for (l = 0; l < numRows; l++) { // Single random nonzero element on the diagonal. scrambleMat[j][l][l] = diag; for (c = l+1; c < numRows; c++) scrambleMat[j][l][c] = 0; } for (l = 1; l < numRows; l++) { if (lowerFlag == 2) { col1 = stream.nextInt(0, b - 1); } else if (lowerFlag == 1) { jb = stream.nextInt(0, sb - 1); col1 = FaureFactor[ib][jb]; } else { // lowerFlag == 0 col1 = 0; } for (c = 0; l+c < numRows; c++) scrambleMat[j][l+c][c] = col1; } } // printMat (dim, scrambleMat, method); if (lowerFlag > 0) for (j = 0 ; j < dim; j++) leftMultiplyMat (j, scrambleMat[j]); else for (j = 0 ; j < dim; j++) leftMultiplyMatDiag (j, scrambleMat[j]); } /** * Similar to {@link #iBinomialMatrixScramble iBinomialMatrixScramble} except that the diagonal * elements of each matrix * Mj are chosen as in * {@link #leftMatrixScrambleFaurePermut leftMatrixScrambleFaurePermut}. * * @param stream random number stream used to generate the randomness * * @param sb Only the first sb elements of F are used * * */ public void iBinomialMatrixScrambleFaurePermut (RandomStream stream, int sb) { iBMSFaurePermut ("iBinomialMatrixScrambleFaurePermut", stream, sb, 2); } /** * Similar to {@link #iBinomialMatrixScrambleFaurePermut iBinomialMatrixScrambleFaurePermut} except that all the * off-diagonal elements are 0. * * @param stream random number stream used to generate the randomness * * @param sb Only the first sb elements of F are used * * */ public void iBinomialMatrixScrambleFaurePermutDiag (RandomStream stream, int sb) { iBMSFaurePermut ("iBinomialMatrixScrambleFaurePermutDiag", stream, sb, 0); } /** * Similar to {@link #iBinomialMatrixScrambleFaurePermut iBinomialMatrixScrambleFaurePermut} except that the * elements under the diagonal are also * chosen from the same restricted set as the diagonal elements. * * @param stream random number stream used to generate the randomness * * @param sb Only the first sb elements of F are used * * */ public void iBinomialMatrixScrambleFaurePermutAll (RandomStream stream, int sb) { iBMSFaurePermut ("iBinomialMatrixScrambleFaurePermutAll", stream, sb, 1); } /** * Applies the striped matrix scramble proposed by Owen. * It multiplies each * Cj on the left * by a w×w nonsingular lower-triangular matrix * Mj as in * {@link #leftMatrixScramble leftMatrixScramble}, but with the additional constraint that * in any column, all entries below the diagonal are equal to the * diagonal entry, which is generated randomly over * {1,..., b - 1}. * Note that for b = 2, the matrices * Mj become deterministic, with * all entries on and below the diagonal equal to 1. * * @param stream random number stream used as generator of the randomness * * */ public void stripedMatrixScramble (RandomStream stream) { int j, l, c; // dimension j, row l, column c. int diag; // random entry on the diagonal; int col1; // random entries below the diagonal; // If genMat contains original gener. matrices, copy it to originalMat. if (originalMat == null) { originalMat = genMat; genMat = new int[dim * numCols][numRows]; } // Constructs the lower-triangular scrambling matrices M_j, r by r. int[][][] scrambleMat = new int[dim][numRows][numRows]; for (j = 0 ; j < dim; j++) { for (c = 0; c < numRows; c++) { diag = stream.nextInt (1, b - 1); // Random entry in this column. for (l = 0; l < c; l++) scrambleMat[j][l][c] = 0; for (l = c; l < numRows; l++) scrambleMat[j][l][c] = diag; } } // printMat (dim, scrambleMat, "stripedMatrixScramble"); for (j = 0 ; j < dim; j++) leftMultiplyMat (j, scrambleMat[j]); } /** * Similar to {@link #stripedMatrixScramble stripedMatrixScramble} except that the * elements on and under the diagonal of each matrix * Mj are * chosen as in {@link #leftMatrixScrambleFaurePermut leftMatrixScrambleFaurePermut}. * * @param stream random number stream used as generator of the randomness * * @param sb Only the first sb elements of F are used * * */ public void stripedMatrixScrambleFaurePermutAll (RandomStream stream, int sb) { int ib = getFaureIndex ("stripedMatrixScrambleFaurePermutAll", sb, 1); // If genMat contains original gener. matrices, copy it to originalMat. if (originalMat == null) { originalMat = genMat; genMat = new int[dim * numCols][numRows]; } // Constructs the lower-triangular scrambling matrices M_j, r by r. int j, l, c; // dimension j, row l, column c. int diag; // random entry on the diagonal; int col1; // random entries below the diagonal; int jb; int[][][] scrambleMat = new int[dim][numRows][numRows]; for (j = 0 ; j < dim; j++) { for (c = 0; c < numRows; c++) { jb = stream.nextInt(0, sb - 1); diag = FaureFactor[ib][jb]; // Random entry in this column. for (l = 0; l < c; l++) scrambleMat[j][l][c] = 0; for (l = c; l < numRows; l++) scrambleMat[j][l][c] = diag; } } // printMat (dim, scrambleMat, "stripedMatrixScrambleFaurePermutAll"); for (j = 0 ; j < dim; j++) leftMultiplyMat (j, scrambleMat[j]); } /** * Applies a linear scramble by multiplying each * Cj on the right * by a single k×k nonsingular upper-triangular matrix * M, * as suggested by Faure and Tezuka. * The diagonal entries of the matrix * M are generated uniformly over * * {1,..., b - 1}, the entries above the diagonal are generated uniformly * over * {0,..., b - 1}, and all the entries are generated independently. * The effect of this scramble is only to change the order in which the * points are generated. If one computes the average value of a * function over all the points of a given digital net, or over * a number of points that is a power of the basis, then this * scramble makes no difference. * * @param stream random number stream used as generator of the randomness * * */ public void rightMatrixScramble (RandomStream stream) { int j, c, l, i, sum; // dimension j, row l, column c, of genMat. // SaveOriginalMat(); if (originalMat == null) { originalMat = genMat; genMat = new int[dim * numCols][numRows]; } // Generate an upper triangular matrix for Faure-Tezuka right-scramble. // Entry [l][c] is in row l, col c. int[][] scrambleMat = new int[numCols][numCols]; for (c = 0; c < numCols; c++) { for (l = 0; l < c; l++) scrambleMat[l][c] = stream.nextInt (0, b - 1); scrambleMat[c][c] = stream.nextInt (1, b - 1); for (l = c+1; l < numCols; l++) scrambleMat[l][c] = 0; } // printMat0 (scrambleMat, "rightMatrixScramble"); // Right-multiply the generator matrices by the scrambling matrix. for (j = 0 ; j < dim; j++) rightMultiplyMat (j, scrambleMat); } public void unrandomize() { resetGeneratorMatrices(); digitalShift = null; } /** * Restores the original generator matrices. * This removes the current linear matrix scrambles. * */ public void resetGeneratorMatrices() { if (originalMat != null) { genMat = originalMat; originalMat = null; } } /** * Erases the original generator matrices and replaces them by * the current ones. The current linear matrix scrambles thus become * permanent. This is useful if we want to apply several * scrambles in succession to a given digital net. * */ public void eraseOriginalGeneratorMatrices() { originalMat = null; } /** * Prints the generator matrices in standard form for dimensions 1 to s. * */ public void printGeneratorMatrices (int s) { // row l, column c, dimension j. for (int j = 0; j < s; j++) { System.out.println ("dim = " + (j+1) + PrintfFormat.NEWLINE); for (int l = 0; l < numRows; l++) { for (int c = 0; c < numCols; c++) System.out.print (genMat[j*numCols+c][l] + " "); System.out.println (""); } System.out.println ("----------------------------------"); } } // Computes the digital expansion of $i$ in base $b$, and the digits // of the Gray code of $i$. // These digits are placed in arrays \texttt{bary} and \texttt{gray}, // respectively, and the method returns the number of digits in the // expansion. The two arrays are assumed to be of sizes larger or // equal to this new number of digits. protected int intToDigitsGray (int b, int i, int numDigits, int[] bary, int[] gray) { if (i == 0) return 0; int idigits = 0; // Num. of digits in b-ary and Gray repres. int c; // convert i to b-ary representation, put digits in bary[]. for (c = 0; i > 0; c++) { idigits++; bary[c] = i % b; i = i / b; } // convert b-ary representation to Gray code. gray[idigits-1] = bary[idigits-1]; int diff; for (c = 0; c < idigits-1; c++) { diff = bary[c] - bary[c+1]; if (diff < 0) gray[c] = diff + b; else gray[c] = diff; } for (c = idigits; c < numDigits; c++) gray[c] = bary[c] = 0; return idigits; } // ************************************************************************ protected class DigitalNetIterator extends PointSet.DefaultPointSetIterator { protected int idigits; // Num. of digits in current code. protected int[] bdigit; // b-ary code of current point index. protected int[] gdigit; // Gray code of current point index. protected int dimS; // = dim except in the shift iterator // children where it is = dim + 1. protected int[] cachedCurPoint; // Digits of coords of the current point, // with digital shift already applied. // Digit l of coord j is at pos. [j*outDigits + l]. // Has one more dimension for the shift iterators. public DigitalNetIterator() { // EpsilonHalf = 0.5 / Math.pow ((double) b, (double) outDigits); bdigit = new int[numCols]; gdigit = new int[numCols]; dimS = dim; cachedCurPoint = new int[(dim + 1)* outDigits]; init(); // This call is important so that subclasses don't // automatically call 'resetCurPointIndex' at the time // of construction as this may cause a subtle // 'NullPointerException' } public void init() { // See constructor resetCurPointIndex(); } // We want to avoid generating 0 or 1 public double nextDouble() { return nextCoordinate() + EpsilonHalf; } public double nextCoordinate() { if (curPointIndex >= numPoints || curCoordIndex >= dimS) outOfBounds(); int start = outDigits * curCoordIndex++; double sum = 0; // Can always have up to outDigits digits, because of digital shift. for (int k = 0; k < outDigits; k++) sum += cachedCurPoint [start+k] * factor[k]; if (digitalShift != null) sum += EpsilonHalf; return sum; } public void resetCurPointIndex() { if (digitalShift == null) for (int i = 0; i < cachedCurPoint.length; i++) cachedCurPoint[i] = 0; else { if (dimShift < dimS) addRandomShift (dimShift, dimS, shiftStream); for (int j = 0; j < dimS; j++) for (int k = 0; k < outDigits; k++) cachedCurPoint[j*outDigits + k] = digitalShift[j][k]; } for (int i = 0; i < numCols; i++) bdigit[i] = 0; for (int i = 0; i < numCols; i++) gdigit[i] = 0; curPointIndex = 0; curCoordIndex = 0; idigits = 0; } public void setCurPointIndex (int i) { if (i == 0) { resetCurPointIndex(); return; } curPointIndex = i; curCoordIndex = 0; if (digitalShift != null && dimShift < dimS) addRandomShift (dimShift, dimS, shiftStream); // Digits of Gray code, used to reconstruct cachedCurPoint. idigits = intToDigitsGray (b, i, numCols, bdigit, gdigit); int c, j, l, sum; for (j = 0; j < dimS; j++) { for (l = 0; l < outDigits; l++) { if (digitalShift == null) sum = 0; else sum = digitalShift[j][l]; if (l < numRows) for (c = 0; c < idigits; c++) sum += genMat[j*numCols+c][l] * gdigit[c]; cachedCurPoint [j*outDigits+l] = sum % b; } } } public int resetToNextPoint() { // incremental computation. curPointIndex++; curCoordIndex = 0; if (curPointIndex >= numPoints) return curPointIndex; // Update the digital expansion of i in base b, and find the // position of change in the Gray code. Set all digits == b-1 to 0 // and increase the first one after by 1. int pos; // Position of change in the Gray code. for (pos = 0; gdigit[pos] == b-1; pos++) gdigit[pos] = 0; gdigit[pos]++; // Update the cachedCurPoint by adding the column of the gener. // matrix that corresponds to the Gray code digit that has changed. // The digital shift is already incorporated in the cached point. int c, j, l; int lsup = numRows; // Max index l if (outDigits < numRows) lsup = outDigits; for (j = 0; j < dimS; j++) { for (l = 0; l < lsup; l++) { cachedCurPoint[j*outDigits + l] += genMat[j*numCols + pos][l]; cachedCurPoint[j * outDigits + l] %= b; } } return curPointIndex; } } // ************************************************************************ protected class DigitalNetIteratorNoGray extends DigitalNetIterator { public DigitalNetIteratorNoGray() { super(); } public void setCurPointIndex (int i) { if (i == 0) { resetCurPointIndex(); return; } curPointIndex = i; curCoordIndex = 0; if (dimShift < dimS) addRandomShift (dimShift, dimS, shiftStream); // Convert i to b-ary representation, put digits in bdigit. idigits = intToDigitsGray (b, i, numCols, bdigit, gdigit); int c, j, l, sum; for (j = 0; j < dimS; j++) { for (l = 0; l < outDigits; l++) { if (digitalShift == null) sum = 0; else sum = digitalShift[j][l]; if (l < numRows) for (c = 0; c < idigits; c++) sum += genMat[j*numCols+c][l] * bdigit[c]; cachedCurPoint [j*outDigits+l] = sum % b; } } } public int resetToNextPoint() { curPointIndex++; curCoordIndex = 0; if (curPointIndex >= numPoints) return curPointIndex; // Find the position of change in the digits of curPointIndex in base // b. Set all digits = b-1 to 0; increase the first one after by 1. int pos; for (pos = 0; bdigit[pos] == b-1; pos++) bdigit[pos] = 0; bdigit[pos]++; // Update the digital expansion of curPointIndex in base b. // Update the cachedCurPoint by adding 1 unit at the digit pos. // If pos > 0, remove b-1 units in the positions < pos. Since // calculations are mod b, this is equivalent to adding 1 unit. // The digital shift is already incorporated in the cached point. int c, j, l; int lsup = numRows; // Max index l if (outDigits < numRows) lsup = outDigits; for (j = 0; j < dimS; j++) { for (l = 0; l < lsup; l++) { for (c = 0; c <= pos; c++) cachedCurPoint[j*outDigits + l] += genMat[j*numCols + c][l]; cachedCurPoint[j * outDigits + l] %= b; } } return curPointIndex; } } }

Ads help maintain this website.