SSJ API Documentation
Stochastic Simulation in Java
Loading...
Searching...
No Matches
HilbertCurveMap.java
1/*
2 * Class: HilbertCurveMap
3 * Description: Map the Hilbert curve in a d-dimensional space [0,1)^d.
4 * Environment: Java
5 * Software: SSJ
6 * Copyright (C) 2014 Pierre L'Ecuyer and Universite de Montreal
7 * Organization: DIRO, Universite de Montreal
8 * @author
9 * @since
10
11 * SSJ is free software: you can redistribute it and/or modify it under
12 * the terms of the GNU General Public License (GPL) as published by the
13 * Free Software Foundation, either version 3 of the License, or
14 * any later version.
15
16 * SSJ is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20
21 * A copy of the GNU General Public License is available at
22 <a href="http://www.gnu.org/licenses">GPL licence site</a>.
23 */
24
25/* IMPORTANT NOTE:
26* Much of this code has been taken (with adaptations) from
27* the hilbert.c code
28* Author: Spencer W. Thomas
29* EECS Dept.
30* University of Michigan
31* Date: Thu Feb 7 1991
32* Copyright (c) 1991, University of Michigan
33*/
34package umontreal.ssj.util.multidimsort;
35
80public class HilbertCurveMap {
81
82 int dimension; // Dimension d of the points used for the sort.
83 int m; // Number of bit retained for each coordinate. Must be <= 31.
84 // int twom; // Number of intervals per coordinate = 2^{m}.
85 // long nCubes; // Total number of subcubes = 2^{dm}. Needed? **********
86 int maxnbits; // Needed ??? It seems this should be = dimension ******
87 int maxlength; // 2^d = (1 << d)
88
89 /*
90 * The following are precomputed tables to simplify calculations. Notation: p#i
91 * means bit i in byte p (high order bit first). p_to_s: Output s is a byte from
92 * input p such that s#i = p#i xor p#(i-1) s_to_p: The inverse of the above.
93 * p_to_J: Output J is "principle position" of input p. The principle position
94 * is the last bit s.t. p#J != p#(n-1) (or n-1 if all bits are equal). bit:
95 * bit[i] == (1 << (n - i)) circshift: circshift[b][i] is a right circular shift
96 * of b by i bits in n bits. parity: Parity[i] is 1 or 0 depending on the parity
97 * of i (1 is odd). bitof: bitof[b][i] is b#i. nbits: The value of n for which
98 * the above tables have been calculated.
99 */
100
101 // int dimForTables = 0; // Dimensions in which tables have been computed.
102 int[] p_to_s;
103 int[] s_to_p;
104 int[] p_to_J;
105 int[] bit;
106 int[] parity;
107 int[][] circshift;
108 int[][] bitof;
109
110 // Precomputes several tables.
111 // This code is from Spencer W. Thomas.
112 void initTables() {
113 p_to_s = new int[maxlength];
114 s_to_p = new int[maxlength];
115 p_to_J = new int[maxlength];
116 parity = new int[maxlength];
117 bit = new int[maxnbits];
118 circshift = new int[maxlength][maxnbits];
119 bitof = new int[maxlength][maxnbits];
120 // It seems that maxnbits should be the dimension d !!!
121
122 int i, b;
123 int n = dimension; // We use n to avoid changing this code.
124 long two_n = 1 << n;
125
126 // if (dimForTables == n )
127 // return; // Tables have been computed already!
128 // dimForTables = n;
129 /* bit array is easy. */
130 for (b = 0; b < n; b++)
131 bit[b] = (int) (1 << (n - b - 1));
132
133 /* Next, do bitof. */
134 for (i = 0; i < two_n; i++)
135 for (b = 0; b < n; b++)
136 bitof[i][b] = (int) ((i & bit[b]) != 0 ? 1 : 0);
137
138 /* circshift is independent of the others. */
139 for (i = 0; i < two_n; i++)
140 for (b = 0; b < n; b++)
141 circshift[i][b] = (int) ((i >> (b)) | ((i << (n - b)) & (two_n - 1)));
142
143 /* So is parity. */
144 parity[0] = 0;
145 for (i = 1, b = 1; i < two_n; i++) {
146 /*
147 * Parity of i is opposite of the number you get when you knock the high order
148 * bit off of i.
149 */
150 if (i == b * 2)
151 b *= 2;
152 parity[i] = (int) (1 - parity[i - b]);
153 }
154
155 /* Now do p_to_s, s_to_p, and p_to_J. */
156 for (i = 0; i < two_n; i++) {
157 int s;
158 s = i & bit[0];
159 for (b = 1; b < n; b++)
160 if ((bitof[i][b] ^ bitof[i][b - 1]) != 0)
161 s |= bit[b];
162 p_to_s[i] = (int) s;
163 s_to_p[s] = (int) i;
164
165 p_to_J[i] = (int) (n - 1);
166 for (b = 0; b < n; b++)
167 if (bitof[i][b] != bitof[i][n - 1])
168 p_to_J[i] = (int) b;
169 }
170 }
171
180 public HilbertCurveMap(int d, int m) {
181 dimension = d;
182 this.m = m;
183 // twom = 1 << m;
184 // nCubes = 1 << d * m;
185
186 maxnbits = m; // ??? ****************
187 maxlength = 1 << dimension; // 2^d
188 this.initTables();
189 }
190
198 public HilbertCurveMap(int d) {
199 this(d, 63 / d);
200 }
201
205 public int dimension() {
206 return dimension;
207 }
208
213 public int getM() {
214 return m;
215 }
216
217 // The following code is adapted from hilbert.c, by Spencer W. Thomas.
218
219 /*****************************************************************
220 * TAG( hilbert_i2c )
221 *
222 * Convert an index into a Hilbert curve to a set of coordinates. Inputs: n:
223 * Number of coordinate axes. (= d) m: Number of bits per axis. r: The index,
224 * contains n*m bits (so n*m must be <= 63). Outputs: a: The list of n
225 * coordinates, each with m bits. Assumptions: n*m < (sizeof r) *
226 * (bits_per_int). Algorithm: From A. R. Butz, "Alternative Algorithm for
227 * Hilbert's Space-Filling Curve", IEEE Trans. Comp., April, 1971, pp 424-426.
228 */
229
236 public void indexToCoordinates(long r, int[] a) {
237 int[] rho = new int[9]; // What is this 9 doing here ??? *******
238 int rh, J, sigma, tau;
239 int sigmaT, tauT;
240 int tauT1 = 0;
241 int omega, omega1 = 0;
242 int[] alpha = new int[9]; // What is this 9 doing here ??? *******
243 int i, b;
244 int Jsum;
245 int n = dimension;
246
247 /* Distribute bits from r into rho. */
248 for (i = m - 1; i >= 0; i--) {
249 rho[i] = (int) (r & ((1 << n) - 1));
250 r >>= n;
251 }
252
253 /* Loop over ints. */
254 Jsum = 0;
255 for (i = 0; i < m; i++) {
256 rh = rho[i];
257 /* J[i] is principle position of rho[i]. */
258 J = p_to_J[rh];
259
260 /* sigma[i] is derived from rho[i] by exclusive-oring adjacent bits. */
261 sigma = p_to_s[rh];
262
263 /*
264 * tau[i] complements low bit of sigma[i], and bit at J[i] if necessary to make
265 * even parity.
266 */
267 tau = (int) (sigma ^ 1);
268 if (parity[tau] != 0)
269 tau ^= bit[J];
270
271 /* sigmaT[i] is circular shift of sigma[i] by sum of J[0..i-1] */
272 /* tauT[i] is same circular shift of tau[i]. */
273 if (Jsum > 0) {
274 sigmaT = circshift[sigma][Jsum];
275 tauT = circshift[tau][Jsum];
276 } else {
277 sigmaT = sigma;
278 tauT = tau;
279 }
280
281 Jsum += J;
282 if (Jsum >= n)
283 Jsum -= n;
284
285 /* omega[i] is xor of omega[i-1] and tauT[i-1]. */
286 if (i == 0)
287 omega = 0;
288 else
289 omega = (int) (omega1 ^ tauT1);
290 omega1 = omega;
291 tauT1 = tauT;
292
293 /* alpha[i] is xor of omega[i] and sigmaT[i] */
294 alpha[i] = (int) (omega ^ sigmaT);
295 }
296
297 /* Build coordinates by taking bits from alphas. */
298 for (b = 0; b < n; b++) {
299 int ab, bt;
300 ab = 0;
301 bt = bit[b];
302 /*
303 * Unroll the loop that stuffs bits into ab. The result is shifted left by 9-m
304 * bits.
305 */
306
307 switch (m) {
308 case 9:
309 if ((alpha[8] & bt) != 0)
310 ab |= 0x01;
311 case 8:
312 if ((alpha[7] & bt) != 0)
313 ab |= 0x02;
314 case 7:
315 if ((alpha[6] & bt) != 0)
316 ab |= 0x04;
317 case 6:
318 if ((alpha[5] & bt) != 0)
319 ab |= 0x08;
320 case 5:
321 if ((alpha[4] & bt) != 0)
322 ab |= 0x10;
323 case 4:
324 if ((alpha[3] & bt) != 0)
325 ab |= 0x20;
326 case 3:
327 if ((alpha[2] & bt) != 0)
328 ab |= 0x40;
329 case 2:
330 if ((alpha[1] & bt) != 0)
331 ab |= 0x80;
332 case 1:
333 if ((alpha[0] & bt) != 0)
334 ab |= 0x100;
335 }
336 a[b] = ab >> (9 - m);
337 }
338 }
339
340 /*****************************************************************
341 * TAG( hilbert_c2i )
342 *
343 * Convert coordinates of a point on a Hilbert curve to its index. Inputs: n:
344 * Number of coordinates. (= d) m: Number of bits/coordinate. a: Array of n
345 * m-bit coordinates. Outputs: r: Output index value. n*m bits. Assumptions: n*m
346 * <= 63. Algorithm: Invert the above.
347 */
348
353 public long coordinatesToIndex(int a[]) {
354 int[] rho = new int[maxnbits];
355 int[] alpha = new int[maxnbits];
356 int J, sigma, tau, sigmaT, tauT, tauT1 = 0, omega, omega1 = 0;
357 int i, b;
358 int Jsum;
359 long rl;
360 int n = dimension;
361
362 // initTables();
363
364 /* Unpack the coordinates into alpha[i]. */
365 /* First, zero out the alphas. */
366 for (i = m; i > 0; --i) {
367 alpha[i - 1] = 0;
368 }
369 for (b = 0; b < n; b++) {
370 long bt = bit[b];
371 long t = a[b];
372 for (i = 1; i <= m; ++i) {
373 if ((t >> (m - i)) != 0) {
374 alpha[i - 1] |= bt;
375 t = t - (1 << (m - i));
376 }
377 }
378 }
379
380 Jsum = 0;
381 for (i = 0; i < m; i++) {
382 /* Compute omega[i] = omega[i-1] xor tauT[i-1]. */
383 if (i == 0)
384 omega = 0;
385 else
386 omega = (int) (omega1 ^ tauT1);
387
388 sigmaT = (int) (alpha[i] ^ omega);
389 /* sigma[i] is the left circular shift of sigmaT[i]. */
390 if (Jsum != 0)
391 sigma = circshift[sigmaT][n - Jsum];
392 else
393 sigma = sigmaT;
394
395 rho[i] = s_to_p[sigma];
396
397 /* Now we can get the principle position. */
398 J = p_to_J[rho[i]];
399
400 /* And compute tau[i] and tauT[i]. */
401 /*
402 * tau[i] complements low bit of sigma[i], and bit at J[i] if necessary to make
403 * even parity.
404 */
405 tau = (int) (sigma ^ 1);
406 if (parity[tau] != 0)
407 tau ^= bit[J];
408
409 /* tauT[i] is right circular shift of tau[i]. */
410 if (Jsum != 0)
411 tauT = circshift[tau][Jsum];
412 else
413 tauT = tau;
414 Jsum += J;
415 if (Jsum >= n)
416 Jsum -= n;
417
418 /* Carry forth the "i-1" values. */
419 tauT1 = tauT;
420 omega1 = omega;
421 }
422
423 /* Pack rho values into r. */
424 rl = 0;
425 for (i = 0; i < m; i++)
426 rl = (rl << n) | rho[i];
427 return rl;
428 }
429
435 public void pointToCoordinates(double[] p, int[] a) {
436 for (int j = 0; j < dimension; ++j)
437 a[j] = (int) (p[j] * (1 << m)); // Multiply by 2^m.
438 }
439
440}
int getM()
Returns the number of bits that is used to divide the axis of each coordinate.
long coordinatesToIndex(int a[])
Takes as input in a[] the integer coordinates of a subcube and returns the corresponding Hilbert inde...
HilbertCurveMap(int d, int m)
Constructs a HilbertCurveMap object that will use the first.
HilbertCurveMap(int d)
This constructor is similar to HilbertCurveMap(int,int), but the parameter .
int dimension()
Returns the dimension of the unit hypercube.
void pointToCoordinates(double[] p, int[] a)
Takes in p[] a point with real-valued coordinates and places in a[] the integer coordinates of the co...
void indexToCoordinates(long r, int[] a)
Takes as input the Hilbert index of a subcube and returns in a[] its integer coordinates.