ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/hilbert.c
Revision: 3.1
Committed: Fri Feb 18 00:40:25 2011 UTC (13 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Major code reorg, moving mgflib to common and introducing BSDF material

File Contents

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