ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/hilbert.c
Revision: 3.3
Committed: Fri Apr 8 23:23:28 2011 UTC (13 years ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R4, rad5R2, rad4R2P2, rad5R0, rad5R1, rad4R2, rad4R1, rad4R2P1, rad5R3, HEAD
Changes since 3.2: +6 -5 lines
Log Message:
Eliminated calls to drand48()

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: hilbert.c,v 3.2 2011/02/18 18:41:04 greg Exp $";
3 #endif
4 /* See LICENSE below for information on rights to use, modify and distribute
5 this code. */
6
7 /*
8 * hilbert.c - Computes Hilbert space-filling curve coordinates, without
9 * recursion, from integer index, and vice versa, and other Hilbert-related
10 * calculations. Also known as Pi-order or Peano scan.
11 *
12 * Author: Doug Moore
13 * Dept. of Computational and Applied Math
14 * Rice University
15 * http://www.caam.rice.edu/~dougm
16 * Date: Sun Feb 20 2000
17 * Copyright (c) 1998-2000, Rice University
18 *
19 * Acknowledgement:
20 * This implementation is based on the work of A. R. Butz ("Alternative
21 * Algorithm for Hilbert's Space-Filling Curve", IEEE Trans. Comp., April,
22 * 1971, pp 424-426) and its interpretation by Spencer W. Thomas, University
23 * of Michigan (http://www-personal.umich.edu/~spencer/Home.html) in his widely
24 * available C software. While the implementation here differs considerably
25 * from his, the first two interfaces and the style of some comments are very
26 * much derived from his work. */
27
28 #include <stdlib.h>
29 #include "hilbert.h"
30
31 /* implementation of the hilbert functions */
32
33 #define adjust_rotation(rotation,nDims,bits) \
34 do { \
35 /* rotation = (rotation + 1 + ffs(bits)) % nDims; */ \
36 bits &= -bits & nd1Ones; \
37 while (bits) \
38 bits >>= 1, ++rotation; \
39 if ( ++rotation >= nDims ) \
40 rotation -= nDims; \
41 } while (0)
42
43 #define ones(T,k) ((((T)2) << (k-1)) - 1)
44
45 #define rdbit(w,k) (((w) >> (k)) & 1)
46
47 #define rotateRight(arg, nRots, nDims) \
48 ((((arg) >> (nRots)) | ((arg) << ((nDims)-(nRots)))) & ones(bitmask_t,nDims))
49
50 #define rotateLeft(arg, nRots, nDims) \
51 ((((arg) << (nRots)) | ((arg) >> ((nDims)-(nRots)))) & ones(bitmask_t,nDims))
52
53 #define DLOGB_BIT_TRANSPOSE
54 static bitmask_t
55 bitTranspose(unsigned nDims, unsigned nBits, bitmask_t inCoords)
56 #if defined(DLOGB_BIT_TRANSPOSE)
57 {
58 unsigned const nDims1 = nDims-1;
59 unsigned inB = nBits;
60 unsigned utB;
61 bitmask_t inFieldEnds = 1;
62 bitmask_t inMask = ones(bitmask_t,inB);
63 bitmask_t coords = 0;
64
65 while ((utB = inB >> 1))
66 {
67 unsigned const shiftAmt = nDims1 * utB;
68 bitmask_t const utFieldEnds =
69 inFieldEnds | (inFieldEnds << (shiftAmt+utB));
70 bitmask_t const utMask =
71 (utFieldEnds << utB) - utFieldEnds;
72 bitmask_t utCoords = 0;
73 unsigned d;
74 if (inB & 1)
75 {
76 bitmask_t const inFieldStarts = inFieldEnds << (inB-1);
77 unsigned oddShift = 2*shiftAmt;
78 for (d = 0; d < nDims; ++d)
79 {
80 bitmask_t in = inCoords & inMask;
81 inCoords >>= inB;
82 coords |= (in & inFieldStarts) << oddShift++;
83 in &= ~inFieldStarts;
84 in = (in | (in << shiftAmt)) & utMask;
85 utCoords |= in << (d*utB);
86 }
87 }
88 else
89 {
90 for (d = 0; d < nDims; ++d)
91 {
92 bitmask_t in = inCoords & inMask;
93 inCoords >>= inB;
94 in = (in | (in << shiftAmt)) & utMask;
95 utCoords |= in << (d*utB);
96 }
97 }
98 inCoords = utCoords;
99 inB = utB;
100 inFieldEnds = utFieldEnds;
101 inMask = utMask;
102 }
103 coords |= inCoords;
104 return coords;
105 }
106 #else
107 {
108 bitmask_t coords = 0;
109 unsigned d;
110 for (d = 0; d < nDims; ++d)
111 {
112 unsigned b;
113 bitmask_t in = inCoords & ones(bitmask_t,nBits);
114 bitmask_t out = 0;
115 inCoords >>= nBits;
116 for (b = nBits; b--;)
117 {
118 out <<= nDims;
119 out |= rdbit(in, b);
120 }
121 coords |= out << d;
122 }
123 return coords;
124 }
125 #endif
126
127 /*****************************************************************
128 * hilbert_i2c
129 *
130 * Convert an index into a Hilbert curve to a set of coordinates.
131 * Inputs:
132 * nDims: Number of coordinate axes.
133 * nBits: Number of bits per axis.
134 * index: The index, contains nDims*nBits bits
135 * (so nDims*nBits must be <= 8*sizeof(bitmask_t)).
136 * Outputs:
137 * coord: The list of nDims coordinates, each with nBits bits.
138 * Assumptions:
139 * nDims*nBits <= (sizeof index) * (bits_per_byte)
140 */
141 void
142 hilbert_i2c(unsigned nDims, unsigned nBits, bitmask_t index, bitmask_t coord[])
143 {
144 if (nDims > 1)
145 {
146 bitmask_t coords;
147 halfmask_t const nbOnes = ones(halfmask_t,nBits);
148 unsigned d;
149
150 if (nBits > 1)
151 {
152 unsigned const nDimsBits = nDims*nBits;
153 halfmask_t const ndOnes = ones(halfmask_t,nDims);
154 halfmask_t const nd1Ones= ndOnes >> 1; /* for adjust_rotation */
155 unsigned b = nDimsBits;
156 unsigned rotation = 0;
157 halfmask_t flipBit = 0;
158 bitmask_t const nthbits = ones(bitmask_t,nDimsBits) / ndOnes;
159 index ^= (index ^ nthbits) >> 1;
160 coords = 0;
161 do
162 {
163 halfmask_t bits = (index >> (b-=nDims)) & ndOnes;
164 coords <<= nDims;
165 coords |= rotateLeft(bits, rotation, nDims) ^ flipBit;
166 flipBit = (halfmask_t)1 << rotation;
167 adjust_rotation(rotation,nDims,bits);
168 } while (b);
169 for (b = nDims; b < nDimsBits; b *= 2)
170 coords ^= coords >> b;
171 coords = bitTranspose(nBits, nDims, coords);
172 }
173 else
174 coords = index ^ (index >> 1);
175
176 for (d = 0; d < nDims; ++d)
177 {
178 coord[d] = coords & nbOnes;
179 coords >>= nBits;
180 }
181 }
182 else
183 coord[0] = index;
184 }
185
186 /*****************************************************************
187 * hilbert_c2i
188 *
189 * Convert coordinates of a point on a Hilbert curve to its index.
190 * Inputs:
191 * nDims: Number of coordinates.
192 * nBits: Number of bits/coordinate.
193 * coord: Array of n nBits-bit coordinates.
194 * Outputs:
195 * index: Output index value. nDims*nBits bits.
196 * Assumptions:
197 * nDims*nBits <= (sizeof bitmask_t) * (bits_per_byte)
198 */
199 bitmask_t
200 hilbert_c2i(unsigned nDims, unsigned nBits, bitmask_t const coord[])
201 {
202 if (nDims > 1)
203 {
204 unsigned const nDimsBits = nDims*nBits;
205 bitmask_t index;
206 unsigned d;
207 bitmask_t coords = 0;
208 for (d = nDims; d--; )
209 {
210 coords <<= nBits;
211 coords |= coord[d];
212 }
213
214 if (nBits > 1)
215 {
216 halfmask_t const ndOnes = ones(halfmask_t,nDims);
217 halfmask_t const nd1Ones= ndOnes >> 1; /* for adjust_rotation */
218 unsigned b = nDimsBits;
219 unsigned rotation = 0;
220 halfmask_t flipBit = 0;
221 bitmask_t const nthbits = ones(bitmask_t,nDimsBits) / ndOnes;
222 coords = bitTranspose(nDims, nBits, coords);
223 coords ^= coords >> nDims;
224 index = 0;
225 do
226 {
227 halfmask_t bits = (coords >> (b-=nDims)) & ndOnes;
228 bits = rotateRight(flipBit ^ bits, rotation, nDims);
229 index <<= nDims;
230 index |= bits;
231 flipBit = (halfmask_t)1 << rotation;
232 adjust_rotation(rotation,nDims,bits);
233 } while (b);
234 index ^= nthbits >> 1;
235 }
236 else
237 index = coords;
238 for (d = 1; d < nDimsBits; d *= 2)
239 index ^= index >> d;
240 return index;
241 }
242 else
243 return coord[0];
244 }
245
246 /*****************************************************************
247 * Readers and writers of bits
248 */
249
250 typedef bitmask_t (*BitReader) (unsigned nDims, unsigned nBytes,
251 char const* c, unsigned y);
252 typedef void (*BitWriter) (unsigned d, unsigned nBytes,
253 char* c, unsigned y, int fold);
254
255
256 #if defined(sparc)
257 #define __BIG_ENDIAN__
258 #endif
259
260 #if defined(__BIG_ENDIAN__)
261 #define whichByte(nBytes,y) (nBytes-1-y/8)
262 #define setBytes(dst,pos,nBytes,val) \
263 memset(&dst[pos+1],val,nBytes-pos-1)
264 #else
265 #define whichByte(nBytes,y) (y/8)
266 #define setBytes(dst,pos,nBytes,val) \
267 memset(&dst[0],val,pos)
268 #endif
269
270 static bitmask_t
271 getIntBits(unsigned nDims, unsigned nBytes, char const* c, unsigned y)
272 {
273 unsigned const bit = y%8;
274 unsigned const offs = whichByte(nBytes,y);
275 unsigned d;
276 bitmask_t bits = 0;
277 c += offs;
278 for (d = 0; d < nDims; ++d)
279 {
280 bits |= rdbit(*c, bit) << d;
281 c += nBytes;
282 }
283 return bits;
284 }
285
286 #include <string.h>
287 static void
288 propogateIntBits(unsigned d, unsigned nBytes,
289 char* c, unsigned y, int fold)
290 {
291 unsigned const byteId = whichByte(nBytes,y);
292 unsigned const b = y%8;
293 char const bthbit = 1 << b;
294 char* const target = &c[d*nBytes];
295 target[byteId] ^= bthbit;
296 if (!fold)
297 {
298 char notbit = ((target[byteId] >> b) & 1) - 1;
299 if (notbit)
300 target[byteId] |= bthbit-1;
301 else
302 target[byteId] &= -bthbit;
303 setBytes(target,byteId,nBytes,notbit);
304 }
305 }
306
307 /* An IEEE double is treated as a 2100 bit number. In particular, 0 is treated
308 as a 1 followed by 2099 zeroes, and negative 0 as a 0 followed by 2099 ones.
309 Only 53 bits differ between a number and a zero of the same sign, with the
310 position of the 53 determined by the exponent, and the values of the 53 by
311 the significand (with implicit leading 1 bit). Although IEEE 754 uses the
312 maximum exponent for NaN's and infinities, this implementation ignores that
313 decision, so that infinities and NaN's are treated as very large numbers.
314 Note that we do not explicitly construct a 2100 bit bitmask in the IEEE
315 routines below. */
316
317 enum { IEEEexpBits = 11 };
318 enum { IEEEsigBits = 52 };
319 enum { IEEErepBits = (1 << IEEEexpBits) + IEEEsigBits };
320
321 typedef union ieee754_double
322 {
323 double d;
324
325 /* This is the IEEE 754 double-precision format. */
326 struct
327 {
328 #if defined(__BIG_ENDIAN__)
329 unsigned int negative:1;
330 unsigned int exponent:11;
331 /* Together these comprise the mantissa. */
332 unsigned int mantissa0:20;
333 unsigned int mantissa1:32;
334 #else /* Big endian. */
335 /* Together these comprise the mantissa. */
336 unsigned int mantissa1:32;
337 unsigned int mantissa0:20;
338 unsigned int exponent:11;
339 unsigned int negative:1;
340 #endif /* Little endian. */
341 } ieee;
342 } ieee754_double;
343
344 static bitmask_t
345 getIEEESignBits(unsigned nDims, double const* c)
346 {
347 unsigned d;
348 ieee754_double x;
349 bitmask_t bits = 0;
350 for (d = 0; d < nDims; ++d)
351 {
352 x.d = c[d];
353 bits |= x.ieee.negative << d;
354 }
355 return bits;
356 }
357
358 static bitmask_t
359 getIEEEBits(unsigned nDims,
360 unsigned ignoreMe, /* ignored */
361 char const* cP,
362 unsigned y)
363 /* retrieve bits y of elements of double array c, where an expanded IEEE
364 double has 2100 bits. */
365 {
366 unsigned d;
367 double const* c = (double const*) cP;
368 ieee754_double x;
369 bitmask_t bits = 0;
370 for (x.d = c[d=0]; d < nDims; x.d = c[++d])
371 {
372 bitmask_t bit = x.ieee.negative;
373 unsigned normalized = (x.ieee.exponent != 0);
374 unsigned diff = y - (x.ieee.exponent - normalized);
375 if (diff <= 52)
376 bit ^= 1 & ((diff < 32)? x.ieee.mantissa1 >> diff:
377 (diff < 52)? x.ieee.mantissa0 >> (diff - 32):
378 /* else */ normalized);
379 else
380 bit ^= (y == IEEErepBits-1);
381
382 bits |= bit << d;
383 }
384 return bits;
385 }
386
387 static void
388 propogateIEEEBits(unsigned d, unsigned nBytes,
389 char* cP, unsigned y, int fold)
390 {
391 ieee754_double* x = d + (ieee754_double*) cP;
392 unsigned normalized = (x->ieee.exponent != 0);
393 unsigned diff = y - (x->ieee.exponent - normalized);
394 if (diff < 32)
395 {
396 unsigned b = 1 << diff;
397 unsigned bit = x->ieee.mantissa1 & b;
398 x->ieee.mantissa1 &= ~(b-1);
399 x->ieee.mantissa1 |= b;
400 if (bit)
401 --x->ieee.mantissa1;
402 }
403 else if (diff < 52)
404 {
405 unsigned b = 1 << (diff - 32);
406 unsigned bit = x->ieee.mantissa0 & b;
407 x->ieee.mantissa0 &= ~(b-1);
408 x->ieee.mantissa0 |= b;
409 if (bit)
410 --x->ieee.mantissa0;
411 x->ieee.mantissa1 = bit?-1: 0;
412 }
413 else if (diff == 52) /* "flip" the implicit 1 bit */
414 {
415 if (normalized)
416 --x->ieee.exponent;
417 else
418 x->ieee.exponent = 1;
419 x->ieee.mantissa0 = -normalized;
420 x->ieee.mantissa1 = -normalized;
421 }
422 else if (diff < IEEErepBits)
423 {
424 if (y == IEEErepBits-1)
425 {
426 x->ieee.negative ^= 1;
427 x->ieee.exponent = 0;
428 }
429 else
430 x->ieee.exponent = y - 51;
431 x->ieee.mantissa0 = 0;
432 x->ieee.mantissa1 = 0;
433 }
434 }
435
436 static unsigned
437 getIEEEexptMax(unsigned nDims, double const* c)
438 {
439 unsigned max = 0;
440 unsigned d;
441 for (d = 0; d < nDims; ++d)
442 {
443 ieee754_double x;
444 x.d = c[d];
445 if (max < x.ieee.exponent)
446 max = x.ieee.exponent;
447 }
448 if (max) --max;
449 return max;
450 }
451
452 static void
453 getIEEEinitValues(double const* c1,
454 unsigned y,
455 unsigned nDims,
456 unsigned* rotation,
457 bitmask_t* bits,
458 bitmask_t* index)
459 {
460 bitmask_t const one = 1;
461 unsigned d;
462 bitmask_t signBits = getIEEESignBits(nDims, c1);
463 unsigned signParity, leastZeroBit, strayBit;
464
465 /* compute the odd/evenness of the number of sign bits */
466 {
467 bitmask_t signPar = signBits;
468 for (d = 1; d < nDims; d *= 2)
469 signPar ^= signPar >> d;
470 signParity = signPar & 1;
471 }
472
473 /* find the position of the least-order 0 bit in among signBits and adjust it
474 if necessary */
475 for (leastZeroBit = 0; leastZeroBit < nDims; ++leastZeroBit)
476 if (rdbit(signBits, leastZeroBit) == 0)
477 break;
478 strayBit = 0;
479 if (leastZeroBit == nDims-2)
480 strayBit = 1;
481 else if (leastZeroBit == nDims)
482 leastZeroBit = nDims-1;
483
484 if (y % 2 == 1)
485 {
486 *rotation = (IEEErepBits - y + 1 + leastZeroBit) % nDims;
487 if (y < IEEErepBits-1)
488 {
489 *bits = signBits ^ (one << ((*rotation + strayBit) % nDims));
490 *index = signParity;
491 }
492 else /* y == IEEErepBits-1 */
493 {
494 *bits = signBits ^ (ones(bitmask_t,nDims) &~ 1);
495 *index = signParity ^ (nDims&1);
496 }
497 }
498 else /* y % 2 == 0 */
499 if (y < IEEErepBits)
500 {
501 unsigned shift_amt = (IEEErepBits - y + leastZeroBit) % nDims;
502 *rotation = (shift_amt + 2 + strayBit) % nDims;
503 *bits = signBits ^ (one << shift_amt);
504 *index = signParity ^ 1;
505 }
506 else /* y == IEEErepBits */
507 {
508 *rotation = 0;
509 *bits = one << (nDims-1);
510 *index = 1;
511 }
512 }
513
514 /*****************************************************************
515 * hilbert_cmp, hilbert_ieee_cmp
516 *
517 * Determine which of two points lies further along the Hilbert curve
518 * Inputs:
519 * nDims: Number of coordinates.
520 * nBytes: Number of bytes of storage/coordinate (hilbert_cmp only)
521 * nBits: Number of bits/coordinate. (hilbert_cmp only)
522 * coord1: Array of nDims nBytes-byte coordinates (or doubles for ieee_cmp).
523 * coord2: Array of nDims nBytes-byte coordinates (or doubles for ieee_cmp).
524 * Return value:
525 * -1, 0, or 1 according to whether
526 coord1<coord2, coord1==coord2, coord1>coord2
527 * Assumptions:
528 * nBits <= (sizeof bitmask_t) * (bits_per_byte)
529 */
530
531 static int
532 hilbert_cmp_work(unsigned nDims, unsigned nBytes, unsigned nBits,
533 unsigned max, unsigned y,
534 char const* c1, char const* c2,
535 unsigned rotation,
536 bitmask_t bits,
537 bitmask_t index,
538 BitReader getBits)
539 {
540 bitmask_t const one = 1;
541 bitmask_t const nd1Ones = ones(bitmask_t,nDims) >> 1; /* used in adjust_rotation macro */
542 while (y-- > max)
543 {
544 bitmask_t reflection = getBits(nDims, nBytes, c1, y);
545 bitmask_t diff = reflection ^ getBits(nDims, nBytes, c2, y);
546 bits ^= reflection;
547 bits = rotateRight(bits, rotation, nDims);
548 if (diff)
549 {
550 unsigned d;
551 diff = rotateRight(diff, rotation, nDims);
552 for (d = 1; d < nDims; d *= 2)
553 {
554 index ^= index >> d;
555 bits ^= bits >> d;
556 diff ^= diff >> d;
557 }
558 return (((index ^ y ^ nBits) & 1) == (bits < (bits^diff)))? -1: 1;
559 }
560 index ^= bits;
561 reflection ^= one << rotation;
562 adjust_rotation(rotation,nDims,bits);
563 bits = reflection;
564 }
565 return 0;
566 }
567
568 int
569 hilbert_cmp(unsigned nDims, unsigned nBytes, unsigned nBits,
570 void const* c1, void const* c2)
571 {
572 bitmask_t const one = 1;
573 bitmask_t bits = one << (nDims-1);
574 return hilbert_cmp_work(nDims, nBytes, nBits, 0, nBits,
575 (char const*)c1, (char const*)c2,
576 0, bits, bits, getIntBits);
577 }
578
579 int
580 hilbert_ieee_cmp(unsigned nDims, double const* c1, double const* c2)
581 {
582 unsigned rotation, max;
583 bitmask_t bits, index;
584 if (getIEEESignBits(nDims, c1) != getIEEESignBits(nDims, c2))
585 max = 2047;
586 else
587 {
588 unsigned max1 = getIEEEexptMax(nDims, c1);
589 unsigned max2 = getIEEEexptMax(nDims, c2);
590 max = (max1 > max2)? max1: max2;
591 }
592
593 getIEEEinitValues(c1, max+53, nDims, &rotation, &bits, &index);
594 return hilbert_cmp_work(nDims, 8, 64, max, max+53,
595 (char const*)c1, (char const*)c2,
596 rotation, bits, index, getIEEEBits);
597 }
598
599 /*****************************************************************
600 * hilbert_box_vtx
601 *
602 * Determine the first or last vertex of a box to lie on a Hilbert curve
603 * Inputs:
604 * nDims: Number of coordinates.
605 * nBytes: Number of bytes/coordinate.
606 * nBits: Number of bits/coordinate.
607 * findMin: Is it the least vertex sought?
608 * coord1: Array of nDims nBytes-byte coordinates - one corner of box
609 * coord2: Array of nDims nBytes-byte coordinates - opposite corner
610 * Output:
611 * c1 and c2 modified to refer to selected corner
612 * value returned is log2 of size of largest power-of-two-aligned box that
613 * contains the selected corner and no other corners
614 * Assumptions:
615 * nBits <= (sizeof bitmask_t) * (bits_per_byte)
616 */
617
618
619 static unsigned
620 hilbert_box_vtx_work(unsigned nDims, unsigned nBytes, unsigned nBits,
621 int findMin,
622 unsigned max, unsigned y,
623 char* c1, char* c2,
624 unsigned rotation,
625 bitmask_t bits,
626 bitmask_t index,
627 BitReader getBits)
628 {
629 bitmask_t const one = 1;
630 bitmask_t const ndOnes = ones(bitmask_t,nDims);
631 bitmask_t const nd1Ones= ndOnes >> 1;
632 bitmask_t bitsFolded = 0;
633
634 while (y--)
635 {
636 bitmask_t reflection = getBits(nDims, nBytes, c1, y);
637 bitmask_t diff = reflection ^ getBits(nDims, nBytes, c2, y);
638 if (diff)
639 {
640 unsigned d;
641 bitmask_t smear = rotateRight(diff, rotation, nDims) >> 1;
642 bitmask_t digit = rotateRight(bits ^ reflection, rotation, nDims);
643 for (d = 1; d < nDims; d *= 2)
644 {
645 index ^= index >> d;
646 digit ^= (digit >> d) &~ smear;
647 smear |= smear >> d;
648 }
649 index &= 1;
650 if ((index ^ y ^ findMin) & 1)
651 digit ^= smear+1;
652 digit = rotateLeft(digit, rotation, nDims) & diff;
653 reflection ^= digit;
654
655 for (d = 0; d < nDims; ++d)
656 if (rdbit(diff, d))
657 {
658 int way = rdbit(digit, d);
659 char* target = d*nBytes + (way? c1: c2);
660 char* const source = 2*d*nBytes + c1 - target + c2;
661 memcpy(target, source, nBytes);
662 }
663
664 bitsFolded |= diff;
665 if (bitsFolded == ndOnes)
666 return y;
667 }
668
669 bits ^= reflection;
670 bits = rotateRight(bits, rotation, nDims);
671 index ^= bits;
672 reflection ^= one << rotation;
673 adjust_rotation(rotation,nDims,bits);
674 bits = reflection;
675 }
676 return y;
677 }
678
679 unsigned
680 hilbert_box_vtx(unsigned nDims, unsigned nBytes, unsigned nBits,
681 int findMin, void* c1, void* c2)
682 {
683 bitmask_t const one = 1;
684 bitmask_t bits = one << (nDims-1);
685 return hilbert_box_vtx_work(nDims, nBytes, nBits, findMin,
686 0, nBits, (char*)c1, (char*)c2,
687 0, bits, bits, getIntBits);
688 }
689
690 unsigned
691 hilbert_ieee_box_vtx(unsigned nDims,
692 int findMin, double* c1, double* c2)
693 {
694 unsigned rotation, max;
695 bitmask_t bits, index;
696 if (getIEEESignBits(nDims, c1) != getIEEESignBits(nDims, c2))
697 max = 2047;
698 else
699 {
700 unsigned max1 = getIEEEexptMax(nDims, c1);
701 unsigned max2 = getIEEEexptMax(nDims, c2);
702 max = (max1 > max2)? max1: max2;
703 }
704
705 getIEEEinitValues(c1, max+53, nDims, &rotation, &bits, &index);
706
707 return hilbert_box_vtx_work(nDims, 8, 64, findMin,
708 max, max+53, (char *)c1, (char *)c2,
709 rotation, bits, index, getIEEEBits);
710 }
711
712 /*****************************************************************
713 * hilbert_box_pt
714 *
715 * Determine the first or last point of a box to lie on a Hilbert curve
716 * Inputs:
717 * nDims: Number of coordinates.
718 * nBytes: Number of bytes/coordinate.
719 * nBits: Number of bits/coordinate.
720 * findMin: Is it the least vertex sought?
721 * coord1: Array of nDims nBytes-byte coordinates - one corner of box
722 * coord2: Array of nDims nBytes-byte coordinates - opposite corner
723 * Output:
724 * c1 and c2 modified to refer to least point
725 * Assumptions:
726 * nBits <= (sizeof bitmask_t) * (bits_per_byte)
727 */
728 unsigned
729 hilbert_box_pt_work(unsigned nDims, unsigned nBytes, unsigned nBits,
730 int findMin,
731 unsigned max, unsigned y,
732 char* c1, char* c2,
733 unsigned rotation,
734 bitmask_t bits,
735 bitmask_t index,
736 BitReader getBits,
737 BitWriter propogateBits)
738 {
739 bitmask_t const one = 1;
740 bitmask_t const nd1Ones = ones(bitmask_t,nDims) >> 1;
741 bitmask_t fold1 = 0, fold2 = 0;
742 unsigned smearSum = 0;
743
744 while (y-- > max)
745 {
746 bitmask_t reflection = getBits(nDims, nBytes, c1, y);
747 bitmask_t diff = reflection ^ getBits(nDims, nBytes, c2, y);
748 if (diff)
749 {
750 bitmask_t smear = rotateRight(diff, rotation, nDims) >> 1;
751 bitmask_t digit = rotateRight(bits ^ reflection, rotation, nDims);
752 unsigned d;
753 for (d = 1; d < nDims; d *= 2)
754 {
755 index ^= index >> d;
756 digit ^= (digit >> d) &~ smear;
757 smear |= smear >> d;
758 }
759 smearSum += smear;
760 index &= 1;
761 if ((index ^ y ^ findMin) & 1)
762 digit ^= smear+1;
763 digit = rotateLeft(digit, rotation, nDims) & diff;
764 reflection ^= digit;
765
766 for (d = 0; d < nDims; ++d)
767 if (rdbit(diff, d))
768 {
769 int way = rdbit(digit, d);
770 char* c = way? c1: c2;
771 bitmask_t fold = way? fold1: fold2;
772 propogateBits(d, nBytes, c, y, rdbit(fold, d));
773 }
774 diff ^= digit;
775 fold1 |= digit;
776 fold2 |= diff;
777 }
778
779 bits ^= reflection;
780 bits = rotateRight(bits, rotation, nDims);
781 index ^= bits;
782 reflection ^= one << rotation;
783 adjust_rotation(rotation,nDims,bits);
784 bits = reflection;
785 }
786 return smearSum;
787 }
788
789 unsigned
790 hilbert_box_pt(unsigned nDims, unsigned nBytes, unsigned nBits,
791 int findMin, void* c1, void* c2)
792 {
793 bitmask_t const one = 1;
794 bitmask_t bits = one << (nDims-1);
795 return hilbert_box_pt_work(nDims, nBytes, nBits, findMin,
796 0, nBits, (char*)c1, (char*)c2,
797 0, bits, bits,
798 getIntBits, propogateIntBits);
799 }
800
801 unsigned
802 hilbert_ieee_box_pt(unsigned nDims,
803 int findMin, double* c1, double* c2)
804 {
805 unsigned rotation, max;
806 bitmask_t bits, index;
807 bitmask_t c1Signs = getIEEESignBits(nDims, c1);
808 bitmask_t c2Signs = getIEEESignBits(nDims, c2);
809 if (c1Signs != c2Signs)
810 {
811 rotation = 0;
812 bits = (bitmask_t)1 << (nDims-1);
813 index = 1;
814 hilbert_box_pt_work(nDims, 8, 64, findMin,
815 IEEErepBits-1, IEEErepBits, (char *)c1, (char *)c2,
816 rotation, bits, index,
817 getIEEEBits, propogateIEEEBits);
818 }
819
820 /* having put everything in the same orthant, start */
821 {
822 unsigned max1 = getIEEEexptMax(nDims, c1);
823 unsigned max2 = getIEEEexptMax(nDims, c2);
824 max = (max1 > max2)? max1: max2;
825 }
826
827 getIEEEinitValues(c1, max+53, nDims, &rotation, &bits, &index);
828
829 return hilbert_box_pt_work(nDims, 8, 64, findMin,
830 max, max+53, (char *)c1, (char *)c2,
831 rotation, bits, index,
832 getIEEEBits, propogateIEEEBits);
833 }
834
835 /*****************************************************************
836 * hilbert_nextinbox
837 *
838 * Determine the first point of a box after or before a given point to lie on
839 * a Hilbert curve
840 * Inputs:
841 * nDims: Number of coordinates.
842 * nBytes: Number of bytes/coordinate.
843 * nBits: Number of bits/coordinate.
844 * findPrev: Is it a previous point that you want?
845 * coord1: Array of nDims nBytes-byte coordinates - one corner of box
846 * coord2: Array of nDims nBytes-byte coordinates - opposite corner
847 * point: Array of nDims nBytes-byte coordinates - lower bound on point returned
848 *
849 * Output:
850 if returns 1:
851 * c1 and c2 modified to refer to least point after "point" in box
852 else returns 0:
853 arguments unchanged; "point" is beyond the last point of the box
854 * Assumptions:
855 * nBits <= (sizeof bitmask_t) * (bits_per_byte)
856 */
857 int
858 hilbert_nextinbox(unsigned nDims, unsigned nBytes, unsigned nBits,
859 int findPrev, void* c1V, void* c2V, void const* ptV)
860 {
861 bitmask_t const one = 1;
862 unsigned y = nBits;
863 bitmask_t const ndOnes = ones(bitmask_t,nDims);
864 bitmask_t const nd1Ones = ndOnes >> 1;
865 unsigned rotation = 0;
866 bitmask_t bits = 0;
867 bitmask_t index = 0;
868 bitmask_t fold1 = 0, fold2 = 0;
869 bitmask_t valu1 = 0, valu2 = 0;
870 unsigned p_y;
871 bitmask_t p_separator = 0, p_firstSeparator;
872 bitmask_t p_cornerdiff, p_reflection;
873 bitmask_t p_fold1, p_fold2, p_valu1, p_valu2;
874
875 char* c1 = (char*)c1V;
876 char* c2 = (char*)c2V;
877 char const* pt = (const char*)ptV;
878
879 while (y-- > 0)
880 {
881 bitmask_t reflection = getIntBits(nDims, nBytes, pt, y);
882 bitmask_t diff = reflection ^ /* planes that separate box and point */
883 ((getIntBits(nDims, nBytes, c1, y) &~ fold1) | valu1);
884
885 if (diff)
886 /* some coordinate planes separate point from box or
887 dividing box or both; smear the bits of diff to reflect that
888 after the first diff dimension, they might as well all be
889 diffing; adjust the diff to reflect the fact that diffed
890 dimensions don't matter. */
891 {
892 /* compute (the complement of) a "digit" in the integer index of this
893 point */
894 bitmask_t cornerdiff = (diff ^ reflection) ^ /* separate box crnrs */
895 ((getIntBits(nDims, nBytes, c2, y) &~ fold2) | valu2);
896 bitmask_t separator = diff & ~cornerdiff;
897 /* eventually, the most significant separating cutting plane */
898 bitmask_t firstSeparator;
899 /* bits less significant than the msb of separator are irrelevant;
900 for convenience, call them all separators too */
901 bitmask_t rotSep = rotateRight(separator, rotation, nDims);
902 /* compute the (complement of the) digit of the hilbert code
903 assoc with point */
904 bitmask_t digit = rotateRight(bits ^ reflection, rotation, nDims);
905 unsigned d;
906 for (d = 1; d < nDims; d *= 2)
907 {
908 index ^= index >> d;
909 digit ^= digit >> d;
910 rotSep |= rotSep >> d;
911 }
912 index &= 1;
913 digit &= rotSep;
914 if ((index ^ y ^ findPrev) & 1)
915 digit ^= rotSep;
916
917 separator = rotateLeft(rotSep, rotation, nDims);
918 rotSep -= rotSep >> 1;
919 firstSeparator = rotateLeft(rotSep, rotation, nDims);
920 /* forget about all the planes that split the box, except those that
921 are more significant than the most significant separator. */
922 cornerdiff &= ~separator;
923
924 if (cornerdiff && digit)
925 /* some coordinate planes divide the box. Call the part of the
926 box in the same orthant as the point "here" and the part of
927 the box in the next (or previous) orthant "there". Remember
928 what the "there" orthant of the box looks like in case it
929 turns out that the curve doesn't reenter the box "here" after
930 (before) passing thru point. Continue working with the
931 "here" part. If there is no "there" there, skip it */
932 {
933 p_firstSeparator = digit & -digit;
934 p_separator = 2*p_firstSeparator-1;
935 p_separator = rotateLeft(p_separator, rotation, nDims);
936 p_firstSeparator = rotateLeft(p_firstSeparator, rotation, nDims);
937 p_cornerdiff = cornerdiff &~ (p_separator ^ p_firstSeparator);
938 p_y = y;
939 p_reflection = reflection ^ p_firstSeparator;
940 p_fold1 = fold1;
941 p_fold2 = fold2;
942 p_valu1 = valu1;
943 p_valu2 = valu2;
944 }
945
946 if (digit < rotSep)
947
948 /* use next box */
949 {
950 if (!p_separator) return 0; /* no next point */
951 separator = p_separator;
952 firstSeparator = p_firstSeparator;
953 y = p_y;
954 cornerdiff = p_cornerdiff;
955 reflection = p_reflection;
956 fold1 = p_fold1;
957 fold2 = p_fold2;
958 valu1 = p_valu1;
959 valu2 = p_valu2;
960 }
961
962 if (cornerdiff)
963 {
964 /* reduce currbox */
965 bitmask_t corner = diff & cornerdiff;
966 cornerdiff ^= corner;
967 fold1 |= corner;
968 fold2 |= cornerdiff;
969 valu1 |= ~reflection & corner;
970 valu2 |= ~reflection & cornerdiff;
971 }
972
973 separator ^= firstSeparator;
974 if (firstSeparator)
975 /* we have completely separated the point from a part of the box
976 ahead of it on the curve; almost done */
977 {
978 unsigned byteId = whichByte(nBytes,y);
979 bitmask_t bthbit = one << y%8;
980 for (d = 0; d < nDims; ++d)
981 {
982 char lo1, lo2;
983 char* cc1 = &c1[d*nBytes];
984 char* cc2 = &c2[d*nBytes];
985 char const* pnt = &pt[d*nBytes];
986 char hibits = -bthbit;
987 char hipart = pnt[byteId] & hibits;
988 memcpy(cc1, pnt, byteId);
989 memcpy(cc2, pnt, byteId);
990
991 if (rdbit(separator, d))
992 hibits ^= bthbit;
993 if (rdbit(firstSeparator, d))
994 hipart ^= bthbit;
995
996 if (rdbit(fold1, d))
997 {
998 lo1 = -rdbit(valu1, d);
999 setBytes(cc1,byteId,nBytes,lo1);
1000 }
1001 else lo1 = cc1[byteId];
1002 cc1[byteId] = hipart | (lo1 &~ hibits);
1003
1004 if (rdbit(fold2, d))
1005 {
1006 lo2 = -rdbit(valu2, d);
1007 setBytes(cc2,byteId,nBytes,lo2);
1008 }
1009 else lo2 = cc2[byteId];
1010 cc2[byteId] = hipart | (lo2 &~ hibits);
1011 }
1012
1013 hilbert_box_pt(nDims, nBytes, nBits, !findPrev, c1V, c2V);
1014 return 1;
1015 }
1016 }
1017
1018 bits ^= reflection;
1019 bits = rotateRight(bits, rotation, nDims);
1020 index ^= bits;
1021 reflection ^= one << rotation;
1022 adjust_rotation(rotation,nDims,bits);
1023 bits = reflection;
1024 }
1025
1026 /* point is in box */
1027 {
1028 unsigned d;
1029 for (d = 0; d < nDims; ++d)
1030 ((char*)c1)[d] = ((char*)c2)[d] = ((char*)pt)[d];
1031 }
1032 return 1;
1033 }
1034
1035
1036
1037 /*****************************************************************
1038 * hilbert_incr
1039 *
1040 * Advance from one point to its successor on a Hilbert curve
1041 * Inputs:
1042 * nDims: Number of coordinates.
1043 * nBits: Number of bits/coordinate.
1044 * coord: Array of nDims nBits-bit coordinates.
1045 * Output:
1046 * coord: Next point on Hilbert curve
1047 * Assumptions:
1048 * nBits <= (sizeof bitmask_t) * (bits_per_byte)
1049 */
1050
1051 void
1052 hilbert_incr(unsigned nDims, unsigned nBits, bitmask_t coord[])
1053 {
1054 bitmask_t const one = 1;
1055 bitmask_t const ndOnes = ones(bitmask_t,nDims);
1056 bitmask_t const nd1Ones= ndOnes >> 1;
1057 unsigned b, d;
1058 unsigned rotation = 0;
1059 bitmask_t reflection = 0;
1060 bitmask_t index = 0;
1061 unsigned rb = nBits-1;
1062 bitmask_t rd = ndOnes;
1063
1064 for (b = nBits; b--;)
1065 {
1066 bitmask_t bits = reflection;
1067 reflection = 0;
1068 for (d = 0; d < nDims; ++d)
1069 reflection |= rdbit(coord[d], b) << d;
1070 bits ^= reflection;
1071 bits = rotateRight(bits, rotation, nDims);
1072 index ^= bits;
1073 for (d = 1; d < nDims; d *= 2)
1074 index ^= index >> d;
1075 if (index++ != ndOnes)
1076 {
1077 rb = b;
1078 rd = index & -index;
1079 rd = rotateLeft(rd, rotation, nDims);
1080
1081 }
1082 index &= 1;
1083 index <<= nDims-1;
1084
1085 reflection ^= one << rotation;
1086 adjust_rotation(rotation,nDims,bits);
1087 }
1088 for (d = 0; !rdbit(rd, d); ++d) {}
1089 coord[d] ^= (2 << rb) - 1;
1090 }
1091
1092
1093 /* LICENSE
1094 *
1095 * This software is copyrighted by Rice University. It may be freely copied,
1096 * modified, and redistributed, provided that the copyright notice is
1097 * preserved on all copies.
1098 *
1099 * There is no warranty or other guarantee of fitness for this software,
1100 * it is provided solely "as is". Bug reports or fixes may be sent
1101 * to the author, who may or may not act on them as he desires.
1102 *
1103 * You may include this software in a program or other software product,
1104 * but must display the notice:
1105 *
1106 * Hilbert Curve implementation copyright 1998, Rice University
1107 *
1108 * in any place where the end-user would see your own copyright.
1109 *
1110 * If you modify this software, you should include a notice giving the
1111 * name of the person performing the modification, the date of modification,
1112 * and the reason for such modification.
1113 */
1114
1115
1116
1117 /* Revision history:
1118
1119 July 1998: Initial release
1120
1121 Sept 1998: Second release
1122
1123 Dec 1998: Fixed bug in hilbert_c2i that allowed a shift by number of bits in
1124 bitmask to vaporize index, in last bit of the function. Implemented
1125 hilbert_incr.
1126
1127 August 1999: Added argument to hilbert_nextinbox so that you can, optionally,
1128 find the previous point along the curve to intersect the box, rather than the
1129 next point.
1130
1131 Nov 1999: Defined fast bit-transpose function (fast, at least, if the number
1132 of bits is large), and reimplemented i2c and c2i in terms of it. Collapsed
1133 loops in hilbert_cmp, with the intention of reusing the cmp code to compare
1134 more general bitstreams.
1135
1136 Feb 2000: Implemented almost all the floating point versions of cmp, etc, so
1137 that coordinates expressed in terms of double-precision IEEE floating point
1138 can be ordered. Still have to do next-in-box, though.
1139
1140 Oct 2001: Learned that some arbitrary coding choices caused some routines
1141 to fail in one dimension, and changed those choices.
1142
1143 version 2001-10-20-05:34
1144
1145 */
1146
1147 /* What remains is test code that won't be compiled unless you define the
1148 TEST_HILBERT preprocessor symbol */
1149
1150 #ifdef TEST_HILBERT
1151 #include <stdio.h>
1152 #define abs(x) (((x)>=0)?(x):(-(x)))
1153
1154 int main()
1155 {
1156 #define maxDim (8*sizeof(bitmask_t))
1157 bitmask_t coord[maxDim], coordPrev[maxDim];
1158 unsigned nDims, nBits, nPrints, orderCheck, i;
1159 bitmask_t r, r1;
1160
1161 for (;;)
1162 {
1163 printf( "Enter nDims, nBits, nPrints, orderCheck: " );
1164 scanf( "%d", &nDims);
1165 if ( nDims == 0 )
1166 break;
1167 scanf( "%d%d%d", &nBits, &nPrints, &orderCheck);
1168 while ( (i = getchar()) != '\n' && i != EOF )
1169 ;
1170 if ( i == EOF )
1171 break;
1172
1173 if (nDims*nBits > 8*sizeof(r))
1174 {
1175 printf("Product of nDims and nBits not exceed %d.\n", 8*sizeof(r));
1176 break;
1177 }
1178
1179 if (nBits == 0)
1180 {
1181 printf("nBits must be positive.\n");
1182 break;
1183 }
1184
1185 if (nPrints > (1ULL << (nDims*nBits)))
1186 nPrints = 1ULL << (nDims*nBits);
1187
1188 for (r = 0; r < nPrints; ++r)
1189 {
1190 bitmask_t coord1[maxDim];
1191 int miscount = 0;
1192 hilbert_i2c( nDims, nBits, r, coord );
1193 printf("%d: ", (unsigned)r);
1194 for (i = 0; i < nDims; ++i)
1195 {
1196 int diff = (int)(coord[i] - coordPrev[i]);
1197 miscount += abs(diff);
1198 coordPrev[i] = coord[i];
1199 printf(" %d", (unsigned)coord[i]);
1200 }
1201 if (r > 0 && miscount != 1)
1202 printf(".....error");
1203 printf("\n");
1204 r1 = hilbert_c2i( nDims, nBits, coord );
1205 if ( r != r1 )
1206 printf( "r = 0x%x; r1 = 0x%x\n", (unsigned)r, (unsigned)r1);
1207 for (i = 0; i < nDims; ++i)
1208 coord[i] = coordPrev[i];
1209
1210 if (! orderCheck)
1211 continue;
1212
1213 for (r1 = 0; r1 < r; ++r1 )
1214 {
1215 unsigned ans;
1216 hilbert_i2c( nDims, nBits, r1, coord1 );
1217 ans = hilbert_cmp( nDims, sizeof(coord[0]), nBits, coord, coord1);
1218 if (ans != 1)
1219 {
1220 int width = (nDims*nBits + 3) / 4;
1221 printf( "cmp r = 0x%0*x; r1 = 0x%0*x, ans = %2d\n",
1222 width, (unsigned)r,
1223 width, (unsigned)r1, ans );
1224 }
1225 }
1226 hilbert_i2c( nDims, nBits, r1, coord1 );
1227 if (hilbert_cmp( nDims, sizeof(coord[0]), nBits, coord, coord1) != 0)
1228 printf( "cmp r = 0x%0*x; r1 = 0x%0*x\n", (nDims*nBits+3)/4, (unsigned)r,
1229 (nDims*nBits+3)/4, (unsigned)r1 );
1230
1231 }
1232 }
1233 return 0;
1234 }
1235
1236 #endif
1237
1238 #ifdef TEST_IEEE
1239 #include <stdio.h>
1240 #include <stdlib.h>
1241 #include <math.h>
1242
1243 int cmp(const void* xv, const void* yv)
1244 {
1245 double const* x = xv;
1246 double const* y = yv;
1247 /* return hilbert_cmp(2, 8, 64, x, y); */
1248 return hilbert_ieee_cmp(2, x, y);
1249 }
1250
1251 int main()
1252 {
1253 double *a;
1254 unsigned i;
1255 unsigned n;
1256 printf("How many points? ");
1257 scanf("%d", &n);
1258 a = (double*) malloc(2*n*sizeof(double));
1259 for (i = 0; i < n; ++i) {
1260 a[2*i] = rand()*(1./RAND_MAX) - 0.5;
1261 a[2*i+1] = rand()*(1./RAND_MAX) - 0.5;
1262 }
1263 qsort(a, n, 2*sizeof(double), cmp);
1264
1265 for (i = 0; i < n; ++i)
1266 printf("%8g %8g\n", a[2*i], a[2*i+1]);
1267 free(a);
1268 return 0;
1269 }
1270
1271 #endif
1272
1273 #ifdef TEST_CMP
1274 #include <stdio.h>
1275
1276 #define maxDim (8*sizeof(bitmask_t))
1277 int main()
1278 {
1279 double coord[maxDim];
1280 unsigned nDims, i, k;
1281
1282 printf( "Enter nDims: " );
1283 scanf( "%d", &nDims);
1284 if ( nDims == 0 )
1285 return 0;
1286 while ( (i = getchar()) != '\n' && i != EOF )
1287 ;
1288 if ( i == EOF )
1289 return 0;
1290
1291 for (k = 0; k < (1<<nDims); ++k)
1292 {
1293 printf("Orth %2d\n", k);
1294 for (i = 0; i < nDims; ++i)
1295 coord[i] = ((k>>i)&1)? -1.: 1.;
1296
1297
1298 hilbert_ieee_cmp( nDims, coord, coord);
1299 }
1300 return 0;
1301 }
1302
1303 #endif
1304
1305 #ifdef TEST_VTX
1306 #include <stdio.h>
1307 #include <stdlib.h>
1308
1309 #define maxDim (8*sizeof(bitmask_t))
1310
1311 unsigned g_nDims;
1312
1313 int cmp(void const* c1p, void const* c2p)
1314 {
1315 return hilbert_cmp(g_nDims, sizeof(unsigned), 8*sizeof(unsigned), c1p, c2p);
1316 }
1317
1318 int main()
1319 {
1320 unsigned corner0[maxDim], corner1[maxDim];
1321 unsigned cornerlo[maxDim], cornerhi[maxDim], work[maxDim];
1322 typedef unsigned array_t[maxDim];
1323 array_t* array;
1324
1325 unsigned nDims, i, k;
1326
1327 printf( "Enter nDims: " );
1328 scanf( "%d", &nDims);
1329 if ( nDims == 0 )
1330 return 0;
1331 while ( (i = getchar()) != '\n' && i != EOF )
1332 ;
1333 if ( i == EOF )
1334 return 0;
1335
1336 printf("Enter one corner (%d coordinates): ", nDims);
1337 for (k = 0; k < nDims; ++k)
1338 scanf("%d", &corner0[k]);
1339
1340 printf("Enter other corner (%d coordinates): ", nDims);
1341 for (k = 0; k < nDims; ++k)
1342 scanf("%d", &corner1[k]);
1343
1344
1345 /* find first corner */
1346 for (k = 0; k < nDims; ++k)
1347 {
1348 cornerlo[k] = corner0[k];
1349 work[k] = corner1[k];
1350 }
1351
1352 hilbert_box_vtx(nDims, sizeof(unsigned), 8*sizeof(unsigned),
1353 1, cornerlo, work);
1354 printf("Predicted lo corner: ");
1355 for (k = 0; k < nDims; ++k)
1356 printf("%4u", cornerlo[k]);
1357 printf("\n");
1358
1359
1360 /* find last corner */
1361 for (k = 0; k < nDims; ++k)
1362 {
1363 work[k] = corner0[k];
1364 cornerhi[k] = corner1[k];
1365 }
1366
1367 hilbert_box_vtx(nDims, sizeof(unsigned), 8*sizeof(unsigned),
1368 0, work, cornerhi);
1369 printf("Predicted hi corner: ");
1370 for (k = 0; k < nDims; ++k)
1371 printf("%4u", cornerhi[k]);
1372 printf("\n");
1373
1374 array = (array_t*) malloc(maxDim*sizeof(unsigned) << nDims);
1375 for (k = 0; k < (1<<nDims); ++k)
1376 {
1377 unsigned j;
1378 unsigned* eltk = &array[k][0];
1379 for (j = 0; j < nDims; ++j)
1380 {
1381 unsigned* src = ((k>>j)&1)? corner1: corner0;
1382 eltk[j] = src[j];
1383 }
1384 }
1385
1386 g_nDims = nDims;
1387 qsort(array, (1<<nDims), maxDim*sizeof(unsigned), cmp);
1388
1389 printf("Result of sort\n");
1390 for (k = 0; k < (1<<nDims); k += (1 << nDims) - 1)
1391 {
1392 unsigned j;
1393 unsigned* eltk = &array[k][0];
1394 for (j = 0; j < nDims; ++j)
1395 printf("%4u", eltk[j]);
1396 printf("\n");
1397 }
1398 free((char*)array);
1399 return 0;
1400 }
1401
1402 #endif
1403
1404 #ifdef TEST_IEEE_VTX
1405 #include <stdio.h>
1406 #include <stdlib.h>
1407 #include <assert.h>
1408
1409 #define maxDim (8*sizeof(bitmask_t))
1410 typedef double key_t;
1411
1412 unsigned g_nDims;
1413
1414 int cmp(void const* c1p, void const* c2p)
1415 {
1416 return hilbert_ieee_cmp(g_nDims, c1p, c2p);
1417 }
1418
1419 int main()
1420 {
1421 key_t corner0[maxDim], corner1[maxDim];
1422 key_t cornerlo[maxDim], cornerhi[maxDim], work[maxDim];
1423 typedef key_t array_t[maxDim];
1424 array_t* array;
1425
1426 unsigned nDims, i, k;
1427
1428 printf( "Enter nDims: " );
1429 scanf( "%d", &nDims);
1430 if ( nDims == 0 )
1431 return 0;
1432
1433 for (i = 0; i < 10000; ++i)
1434 {
1435 for (k = 0; k < nDims; ++k)
1436 {
1437 corner0[k] = 2.*drand48() - 1.;
1438 corner1[k] = 2.*drand48() - 1.;
1439 }
1440
1441 /* find first corner */
1442 for (k = 0; k < nDims; ++k)
1443 {
1444 cornerlo[k] = corner0[k];
1445 work[k] = corner1[k];
1446 }
1447
1448 hilbert_ieee_box_vtx(nDims, 1, cornerlo, work);
1449
1450 /* find last corner */
1451 for (k = 0; k < nDims; ++k)
1452 {
1453 work[k] = corner0[k];
1454 cornerhi[k] = corner1[k];
1455 }
1456
1457 hilbert_ieee_box_vtx(nDims, 0, work, cornerhi);
1458
1459 array = (array_t*) malloc(maxDim*sizeof(key_t) << nDims);
1460 for (k = 0; k < (1<<nDims); ++k)
1461 {
1462 unsigned j;
1463 key_t* eltk = &array[k][0];
1464 for (j = 0; j < nDims; ++j)
1465 {
1466 key_t* src = ((k>>j)&1)? corner1: corner0;
1467 eltk[j] = src[j];
1468 }
1469 }
1470
1471 g_nDims = nDims;
1472 qsort(array, (1<<nDims), maxDim*sizeof(key_t), cmp);
1473
1474 for (k = 0; k < (1<<nDims); k += (1 << nDims) - 1)
1475 {
1476 unsigned j;
1477 int mismatch = 0;
1478 key_t* eltk = &array[k][0];
1479 for (j = 0; j < nDims & !mismatch; ++j)
1480 {
1481 mismatch = (eltk[j] != ((k==0)? cornerlo: cornerhi)[j]);
1482 }
1483 assert (!mismatch);
1484 }
1485 free((char*)array);
1486 }
1487 return 0;
1488 }
1489
1490 #endif
1491
1492 #ifdef TEST_PT
1493 #include <stdio.h>
1494 #include <stdlib.h>
1495
1496 #define maxDim (8*sizeof(bitmask_t))
1497
1498 unsigned g_nDims;
1499
1500 int cmp(void const* c1p, void const* c2p)
1501 {
1502 return hilbert_cmp(g_nDims, sizeof(unsigned), 8*sizeof(unsigned), c1p, c2p);
1503 }
1504
1505 int main()
1506 {
1507 unsigned point0[maxDim], point1[maxDim];
1508 unsigned pointlo[maxDim], pointhi[maxDim], work[maxDim];
1509 typedef unsigned array_t[maxDim];
1510 array_t* array;
1511
1512 unsigned nDims, i, k, outvolume = 1, involume = 1;
1513 unsigned nextItem;
1514
1515 printf( "Enter nDims: " );
1516 scanf( "%d", &nDims);
1517 if ( nDims == 0 )
1518 return 0;
1519 while ( (i = getchar()) != '\n' && i != EOF )
1520 ;
1521 if ( i == EOF )
1522 return 0;
1523
1524 printf("Enter one point (%d coordinates): ", nDims);
1525 for (k = 0; k < nDims; ++k)
1526 scanf("%d", &point0[k]);
1527
1528 printf("Enter other point (%d coordinates, strictly greater): ", nDims);
1529 for (k = 0; k < nDims; ++k)
1530 {
1531 unsigned diff;
1532 scanf("%d", &point1[k]);
1533 diff = point1[k] - point0[k];
1534 outvolume *= diff + 1;
1535 involume *= diff - 1;
1536 }
1537
1538
1539 /* find first point */
1540 for (k = 0; k < nDims; ++k)
1541 {
1542 pointlo[k] = point0[k];
1543 work[k] = point1[k];
1544 }
1545
1546 hilbert_box_pt(nDims, sizeof(unsigned), 8*sizeof(unsigned),
1547 1, pointlo, work);
1548 printf("Predicted lo point: ");
1549 for (k = 0; k < nDims; ++k)
1550 printf("%4u", pointlo[k]);
1551 printf("\n");
1552
1553
1554 /* find last point */
1555 for (k = 0; k < nDims; ++k)
1556 {
1557 work[k] = point0[k];
1558 pointhi[k] = point1[k];
1559 }
1560
1561 hilbert_box_pt(nDims, sizeof(unsigned), 8*sizeof(unsigned),
1562 0, work, pointhi);
1563 printf("Predicted hi point: ");
1564 for (k = 0; k < nDims; ++k)
1565 printf("%4u", pointhi[k]);
1566 printf("\n");
1567
1568
1569
1570 array = (array_t*) malloc(maxDim*sizeof(unsigned) * (outvolume-involume));
1571 if (array == 0)
1572 {
1573 fprintf(stderr, "Out of memory.\n");
1574 exit(-1);
1575 }
1576 nextItem = 0;
1577 for (k = 0; k < outvolume; ++k)
1578 {
1579 unsigned kk = k;
1580 unsigned j;
1581 unsigned* eltk = &array[nextItem][0];
1582 int boundary = 0;
1583
1584 for (j = 0; j < nDims; ++j)
1585 {
1586 unsigned diff1 = point1[j] - point0[j] + 1;
1587 unsigned pos = point0[j] + (kk % diff1);
1588 boundary |= (point0[j] == pos || pos == point1[j]);
1589 eltk[j] = pos;
1590 kk /= diff1;
1591 }
1592 if (boundary)
1593 ++nextItem;
1594 }
1595
1596 g_nDims = nDims;
1597 qsort(array, outvolume-involume, maxDim*sizeof(unsigned), cmp);
1598
1599 printf("Result of sort\n");
1600 for (k = 0; k < outvolume-involume; k += outvolume-involume-1)
1601 {
1602 unsigned j;
1603 unsigned* eltk = &array[k][0];
1604 for (j = 0; j < nDims; ++j)
1605 printf("%4u", eltk[j]);
1606 printf("\n");
1607 }
1608 free((char*)array);
1609 return 0;
1610 }
1611
1612 #endif
1613
1614 #ifdef TEST_IEEE_PT
1615 #include <stdio.h>
1616 #include <stdlib.h>
1617
1618 #define maxDim (8*sizeof(bitmask_t))
1619
1620 int main()
1621 {
1622 double point0[maxDim], point1[maxDim];
1623 double pointlo[maxDim], pointhi[maxDim], work[maxDim];
1624
1625 unsigned nDims, k, i;
1626
1627 printf( "Enter nDims: " );
1628 scanf( "%d", &nDims);
1629 if ( nDims == 0 )
1630 return 0;
1631 while ( (i = getchar()) != '\n' && i != EOF )
1632 ;
1633 if ( i == EOF )
1634 return 0;
1635
1636 printf("Enter one point (%d coordinates): ", nDims);
1637 for (k = 0; k < nDims; ++k)
1638 scanf("%lf", &point0[k]);
1639
1640 printf("Enter other point (%d coordinates, strictly greater): ", nDims);
1641 for (k = 0; k < nDims; ++k)
1642 scanf("%lf", &point1[k]);
1643
1644 /* find last point */
1645 for (k = 0; k < nDims; ++k)
1646 {
1647 work[k] = point0[k];
1648 pointhi[k] = point1[k];
1649 }
1650
1651 hilbert_ieee_box_pt(nDims, 0, work, pointhi);
1652 printf("Predicted hi point: ");
1653 for (k = 0; k < nDims; ++k)
1654 printf("%10lg", pointhi[k]);
1655 printf("\n");
1656
1657 /* find first point */
1658 for (k = 0; k < nDims; ++k)
1659 {
1660 pointlo[k] = point0[k];
1661 work[k] = point1[k];
1662 }
1663
1664 hilbert_ieee_box_pt(nDims, 1, pointlo, work);
1665 printf("Predicted lo point: ");
1666 for (k = 0; k < nDims; ++k)
1667 printf("%10lg", pointlo[k]);
1668 printf("\n");
1669
1670 /* validate by sorting random boundary points */
1671 #define nPts 1000000
1672 assert(hilbert_ieee_cmp(nDims, pointlo, pointhi) < 0);
1673 for (i = 0; i < nPts; ++i)
1674 {
1675 double pt1[maxDim], pt2[maxDim];
1676 for (k = 0; k < nDims; ++k)
1677 {
1678 if (i % nDims == k)
1679 pt1[k] = point0[k];
1680 else
1681 pt1[k] = point0[k] + drand48()*(point1[k]-point0[k]);
1682 }
1683 for (k = 0; k < nDims; ++k)
1684 {
1685 if (i % nDims == k)
1686 pt2[k] = point1[k];
1687 else
1688 pt2[k] = point0[k] + drand48()*(point1[k]-point0[k]);
1689 }
1690 if (hilbert_ieee_cmp(nDims, pt1, pt2) < 0)
1691 {
1692 if (hilbert_ieee_cmp(nDims, pt1, pointlo) < 0)
1693 memcpy(pointlo, pt1, maxDim*sizeof(double));
1694 if (hilbert_ieee_cmp(nDims, pointhi, pt2) < 0)
1695 memcpy(pointhi, pt2, maxDim*sizeof(double));
1696 }
1697 else
1698 {
1699 if (hilbert_ieee_cmp(nDims, pt2, pointlo) < 0)
1700 memcpy(pointlo, pt2, maxDim*sizeof(double));
1701 if (hilbert_ieee_cmp(nDims, pointhi, pt1) < 0)
1702 memcpy(pointhi, pt1, maxDim*sizeof(double));
1703 }
1704 }
1705
1706 printf("Sorted hi and lo:\n");
1707 for (k = 0; k < nDims; ++k)
1708 printf("%10lg", pointhi[k]);
1709 printf("\n");
1710 for (k = 0; k < nDims; ++k)
1711 printf("%10lg", pointlo[k]);
1712 printf("\n");
1713
1714 return 0;
1715 }
1716
1717 #endif
1718
1719 #ifdef TEST_NEXT
1720 #include <stdio.h>
1721
1722 int main()
1723 {
1724 unsigned i;
1725 unsigned c1[100], c2[100], pt[100];
1726 unsigned nDims, nBytes = 4;
1727 int stat, findPrev;
1728 printf("Enter nDims: " );
1729 scanf("%u", &nDims);
1730
1731 printf("Enter 1st box corner: ");
1732 for (i = 0; i < nDims; ++i)
1733 scanf("%u", &c1[i]);
1734 printf("Enter 2nd box corner: ");
1735 for (i = 0; i < nDims; ++i)
1736 scanf("%u", &c2[i]);
1737 printf("Enter point: ");
1738 for (i = 0; i < nDims; ++i)
1739 scanf("%u", &pt[i]);
1740 printf("Find prev?: ");
1741 scanf("%d", &findPrev);
1742
1743 stat = hilbert_nextinbox(nDims, nBytes, 8*nBytes, findPrev, c1, c2, pt);
1744
1745 if (stat)
1746 for (i = 0; i < nDims; ++i)
1747 printf("%u ", c1[i]);
1748 else
1749 printf("No such point");
1750
1751 printf("\n");
1752 return 0;
1753 }
1754 #endif