ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/hilbert.c
Revision: 3.2
Committed: Fri Feb 18 18:41:04 2011 UTC (13 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 3.1: +3 -0 lines
Log Message:
Added missing RCS tags

File Contents

# User Rev Content
1 greg 3.2 #ifndef lint
2     static const char RCSid[] = "$Id$";
3     #endif
4 greg 3.1 /* 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    
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] = drand48()-0.5, a[2*i+1] = drand48()-0.5;
1261    
1262     qsort(a, n, 2*sizeof(double), cmp);
1263    
1264     for (i = 0; i < n; ++i)
1265     printf("%8g %8g\n", a[2*i], a[2*i+1]);
1266     free(a);
1267     return 0;
1268     }
1269    
1270     #endif
1271    
1272     #ifdef TEST_CMP
1273     #include <stdio.h>
1274    
1275     #define maxDim (8*sizeof(bitmask_t))
1276     int main()
1277     {
1278     double coord[maxDim];
1279     unsigned nDims, i, k;
1280    
1281     printf( "Enter nDims: " );
1282     scanf( "%d", &nDims);
1283     if ( nDims == 0 )
1284     return 0;
1285     while ( (i = getchar()) != '\n' && i != EOF )
1286     ;
1287     if ( i == EOF )
1288     return 0;
1289    
1290     for (k = 0; k < (1<<nDims); ++k)
1291     {
1292     printf("Orth %2d\n", k);
1293     for (i = 0; i < nDims; ++i)
1294     coord[i] = ((k>>i)&1)? -1.: 1.;
1295    
1296    
1297     hilbert_ieee_cmp( nDims, coord, coord);
1298     }
1299     return 0;
1300     }
1301    
1302     #endif
1303    
1304     #ifdef TEST_VTX
1305     #include <stdio.h>
1306     #include <stdlib.h>
1307    
1308     #define maxDim (8*sizeof(bitmask_t))
1309    
1310     unsigned g_nDims;
1311    
1312     int cmp(void const* c1p, void const* c2p)
1313     {
1314     return hilbert_cmp(g_nDims, sizeof(unsigned), 8*sizeof(unsigned), c1p, c2p);
1315     }
1316    
1317     int main()
1318     {
1319     unsigned corner0[maxDim], corner1[maxDim];
1320     unsigned cornerlo[maxDim], cornerhi[maxDim], work[maxDim];
1321     typedef unsigned array_t[maxDim];
1322     array_t* array;
1323    
1324     unsigned nDims, i, k;
1325    
1326     printf( "Enter nDims: " );
1327     scanf( "%d", &nDims);
1328     if ( nDims == 0 )
1329     return 0;
1330     while ( (i = getchar()) != '\n' && i != EOF )
1331     ;
1332     if ( i == EOF )
1333     return 0;
1334    
1335     printf("Enter one corner (%d coordinates): ", nDims);
1336     for (k = 0; k < nDims; ++k)
1337     scanf("%d", &corner0[k]);
1338    
1339     printf("Enter other corner (%d coordinates): ", nDims);
1340     for (k = 0; k < nDims; ++k)
1341     scanf("%d", &corner1[k]);
1342    
1343    
1344     /* find first corner */
1345     for (k = 0; k < nDims; ++k)
1346     {
1347     cornerlo[k] = corner0[k];
1348     work[k] = corner1[k];
1349     }
1350    
1351     hilbert_box_vtx(nDims, sizeof(unsigned), 8*sizeof(unsigned),
1352     1, cornerlo, work);
1353     printf("Predicted lo corner: ");
1354     for (k = 0; k < nDims; ++k)
1355     printf("%4u", cornerlo[k]);
1356     printf("\n");
1357    
1358    
1359     /* find last corner */
1360     for (k = 0; k < nDims; ++k)
1361     {
1362     work[k] = corner0[k];
1363     cornerhi[k] = corner1[k];
1364     }
1365    
1366     hilbert_box_vtx(nDims, sizeof(unsigned), 8*sizeof(unsigned),
1367     0, work, cornerhi);
1368     printf("Predicted hi corner: ");
1369     for (k = 0; k < nDims; ++k)
1370     printf("%4u", cornerhi[k]);
1371     printf("\n");
1372    
1373     array = (array_t*) malloc(maxDim*sizeof(unsigned) << nDims);
1374     for (k = 0; k < (1<<nDims); ++k)
1375     {
1376     unsigned j;
1377     unsigned* eltk = &array[k][0];
1378     for (j = 0; j < nDims; ++j)
1379     {
1380     unsigned* src = ((k>>j)&1)? corner1: corner0;
1381     eltk[j] = src[j];
1382     }
1383     }
1384    
1385     g_nDims = nDims;
1386     qsort(array, (1<<nDims), maxDim*sizeof(unsigned), cmp);
1387    
1388     printf("Result of sort\n");
1389     for (k = 0; k < (1<<nDims); k += (1 << nDims) - 1)
1390     {
1391     unsigned j;
1392     unsigned* eltk = &array[k][0];
1393     for (j = 0; j < nDims; ++j)
1394     printf("%4u", eltk[j]);
1395     printf("\n");
1396     }
1397     free((char*)array);
1398     return 0;
1399     }
1400    
1401     #endif
1402    
1403     #ifdef TEST_IEEE_VTX
1404     #include <stdio.h>
1405     #include <stdlib.h>
1406     #include <assert.h>
1407    
1408     #define maxDim (8*sizeof(bitmask_t))
1409     typedef double key_t;
1410    
1411     unsigned g_nDims;
1412    
1413     int cmp(void const* c1p, void const* c2p)
1414     {
1415     return hilbert_ieee_cmp(g_nDims, c1p, c2p);
1416     }
1417    
1418     int main()
1419     {
1420     key_t corner0[maxDim], corner1[maxDim];
1421     key_t cornerlo[maxDim], cornerhi[maxDim], work[maxDim];
1422     typedef key_t array_t[maxDim];
1423     array_t* array;
1424    
1425     unsigned nDims, i, k;
1426    
1427     printf( "Enter nDims: " );
1428     scanf( "%d", &nDims);
1429     if ( nDims == 0 )
1430     return 0;
1431    
1432     for (i = 0; i < 10000; ++i)
1433     {
1434     for (k = 0; k < nDims; ++k)
1435     {
1436     corner0[k] = 2.*drand48() - 1.;
1437     corner1[k] = 2.*drand48() - 1.;
1438     }
1439    
1440     /* find first corner */
1441     for (k = 0; k < nDims; ++k)
1442     {
1443     cornerlo[k] = corner0[k];
1444     work[k] = corner1[k];
1445     }
1446    
1447     hilbert_ieee_box_vtx(nDims, 1, cornerlo, work);
1448    
1449     /* find last corner */
1450     for (k = 0; k < nDims; ++k)
1451     {
1452     work[k] = corner0[k];
1453     cornerhi[k] = corner1[k];
1454     }
1455    
1456     hilbert_ieee_box_vtx(nDims, 0, work, cornerhi);
1457    
1458     array = (array_t*) malloc(maxDim*sizeof(key_t) << nDims);
1459     for (k = 0; k < (1<<nDims); ++k)
1460     {
1461     unsigned j;
1462     key_t* eltk = &array[k][0];
1463     for (j = 0; j < nDims; ++j)
1464     {
1465     key_t* src = ((k>>j)&1)? corner1: corner0;
1466     eltk[j] = src[j];
1467     }
1468     }
1469    
1470     g_nDims = nDims;
1471     qsort(array, (1<<nDims), maxDim*sizeof(key_t), cmp);
1472    
1473     for (k = 0; k < (1<<nDims); k += (1 << nDims) - 1)
1474     {
1475     unsigned j;
1476     int mismatch = 0;
1477     key_t* eltk = &array[k][0];
1478     for (j = 0; j < nDims & !mismatch; ++j)
1479     {
1480     mismatch = (eltk[j] != ((k==0)? cornerlo: cornerhi)[j]);
1481     }
1482     assert (!mismatch);
1483     }
1484     free((char*)array);
1485     }
1486     return 0;
1487     }
1488    
1489     #endif
1490    
1491     #ifdef TEST_PT
1492     #include <stdio.h>
1493     #include <stdlib.h>
1494    
1495     #define maxDim (8*sizeof(bitmask_t))
1496    
1497     unsigned g_nDims;
1498    
1499     int cmp(void const* c1p, void const* c2p)
1500     {
1501     return hilbert_cmp(g_nDims, sizeof(unsigned), 8*sizeof(unsigned), c1p, c2p);
1502     }
1503    
1504     int main()
1505     {
1506     unsigned point0[maxDim], point1[maxDim];
1507     unsigned pointlo[maxDim], pointhi[maxDim], work[maxDim];
1508     typedef unsigned array_t[maxDim];
1509     array_t* array;
1510    
1511     unsigned nDims, i, k, outvolume = 1, involume = 1;
1512     unsigned nextItem;
1513    
1514     printf( "Enter nDims: " );
1515     scanf( "%d", &nDims);
1516     if ( nDims == 0 )
1517     return 0;
1518     while ( (i = getchar()) != '\n' && i != EOF )
1519     ;
1520     if ( i == EOF )
1521     return 0;
1522    
1523     printf("Enter one point (%d coordinates): ", nDims);
1524     for (k = 0; k < nDims; ++k)
1525     scanf("%d", &point0[k]);
1526    
1527     printf("Enter other point (%d coordinates, strictly greater): ", nDims);
1528     for (k = 0; k < nDims; ++k)
1529     {
1530     unsigned diff;
1531     scanf("%d", &point1[k]);
1532     diff = point1[k] - point0[k];
1533     outvolume *= diff + 1;
1534     involume *= diff - 1;
1535     }
1536    
1537    
1538     /* find first point */
1539     for (k = 0; k < nDims; ++k)
1540     {
1541     pointlo[k] = point0[k];
1542     work[k] = point1[k];
1543     }
1544    
1545     hilbert_box_pt(nDims, sizeof(unsigned), 8*sizeof(unsigned),
1546     1, pointlo, work);
1547     printf("Predicted lo point: ");
1548     for (k = 0; k < nDims; ++k)
1549     printf("%4u", pointlo[k]);
1550     printf("\n");
1551    
1552    
1553     /* find last point */
1554     for (k = 0; k < nDims; ++k)
1555     {
1556     work[k] = point0[k];
1557     pointhi[k] = point1[k];
1558     }
1559    
1560     hilbert_box_pt(nDims, sizeof(unsigned), 8*sizeof(unsigned),
1561     0, work, pointhi);
1562     printf("Predicted hi point: ");
1563     for (k = 0; k < nDims; ++k)
1564     printf("%4u", pointhi[k]);
1565     printf("\n");
1566    
1567    
1568    
1569     array = (array_t*) malloc(maxDim*sizeof(unsigned) * (outvolume-involume));
1570     if (array == 0)
1571     {
1572     fprintf(stderr, "Out of memory.\n");
1573     exit(-1);
1574     }
1575     nextItem = 0;
1576     for (k = 0; k < outvolume; ++k)
1577     {
1578     unsigned kk = k;
1579     unsigned j;
1580     unsigned* eltk = &array[nextItem][0];
1581     int boundary = 0;
1582    
1583     for (j = 0; j < nDims; ++j)
1584     {
1585     unsigned diff1 = point1[j] - point0[j] + 1;
1586     unsigned pos = point0[j] + (kk % diff1);
1587     boundary |= (point0[j] == pos || pos == point1[j]);
1588     eltk[j] = pos;
1589     kk /= diff1;
1590     }
1591     if (boundary)
1592     ++nextItem;
1593     }
1594    
1595     g_nDims = nDims;
1596     qsort(array, outvolume-involume, maxDim*sizeof(unsigned), cmp);
1597    
1598     printf("Result of sort\n");
1599     for (k = 0; k < outvolume-involume; k += outvolume-involume-1)
1600     {
1601     unsigned j;
1602     unsigned* eltk = &array[k][0];
1603     for (j = 0; j < nDims; ++j)
1604     printf("%4u", eltk[j]);
1605     printf("\n");
1606     }
1607     free((char*)array);
1608     return 0;
1609     }
1610    
1611     #endif
1612    
1613     #ifdef TEST_IEEE_PT
1614     #include <stdio.h>
1615     #include <stdlib.h>
1616    
1617     #define maxDim (8*sizeof(bitmask_t))
1618    
1619     int main()
1620     {
1621     double point0[maxDim], point1[maxDim];
1622     double pointlo[maxDim], pointhi[maxDim], work[maxDim];
1623    
1624     unsigned nDims, k, i;
1625    
1626     printf( "Enter nDims: " );
1627     scanf( "%d", &nDims);
1628     if ( nDims == 0 )
1629     return 0;
1630     while ( (i = getchar()) != '\n' && i != EOF )
1631     ;
1632     if ( i == EOF )
1633     return 0;
1634    
1635     printf("Enter one point (%d coordinates): ", nDims);
1636     for (k = 0; k < nDims; ++k)
1637     scanf("%lf", &point0[k]);
1638    
1639     printf("Enter other point (%d coordinates, strictly greater): ", nDims);
1640     for (k = 0; k < nDims; ++k)
1641     scanf("%lf", &point1[k]);
1642    
1643     /* find last point */
1644     for (k = 0; k < nDims; ++k)
1645     {
1646     work[k] = point0[k];
1647     pointhi[k] = point1[k];
1648     }
1649    
1650     hilbert_ieee_box_pt(nDims, 0, work, pointhi);
1651     printf("Predicted hi point: ");
1652     for (k = 0; k < nDims; ++k)
1653     printf("%10lg", pointhi[k]);
1654     printf("\n");
1655    
1656     /* find first point */
1657     for (k = 0; k < nDims; ++k)
1658     {
1659     pointlo[k] = point0[k];
1660     work[k] = point1[k];
1661     }
1662    
1663     hilbert_ieee_box_pt(nDims, 1, pointlo, work);
1664     printf("Predicted lo point: ");
1665     for (k = 0; k < nDims; ++k)
1666     printf("%10lg", pointlo[k]);
1667     printf("\n");
1668    
1669     /* validate by sorting random boundary points */
1670     #define nPts 1000000
1671     assert(hilbert_ieee_cmp(nDims, pointlo, pointhi) < 0);
1672     for (i = 0; i < nPts; ++i)
1673     {
1674     double pt1[maxDim], pt2[maxDim];
1675     for (k = 0; k < nDims; ++k)
1676     {
1677     if (i % nDims == k)
1678     pt1[k] = point0[k];
1679     else
1680     pt1[k] = point0[k] + drand48()*(point1[k]-point0[k]);
1681     }
1682     for (k = 0; k < nDims; ++k)
1683     {
1684     if (i % nDims == k)
1685     pt2[k] = point1[k];
1686     else
1687     pt2[k] = point0[k] + drand48()*(point1[k]-point0[k]);
1688     }
1689     if (hilbert_ieee_cmp(nDims, pt1, pt2) < 0)
1690     {
1691     if (hilbert_ieee_cmp(nDims, pt1, pointlo) < 0)
1692     memcpy(pointlo, pt1, maxDim*sizeof(double));
1693     if (hilbert_ieee_cmp(nDims, pointhi, pt2) < 0)
1694     memcpy(pointhi, pt2, maxDim*sizeof(double));
1695     }
1696     else
1697     {
1698     if (hilbert_ieee_cmp(nDims, pt2, pointlo) < 0)
1699     memcpy(pointlo, pt2, maxDim*sizeof(double));
1700     if (hilbert_ieee_cmp(nDims, pointhi, pt1) < 0)
1701     memcpy(pointhi, pt1, maxDim*sizeof(double));
1702     }
1703     }
1704    
1705     printf("Sorted hi and lo:\n");
1706     for (k = 0; k < nDims; ++k)
1707     printf("%10lg", pointhi[k]);
1708     printf("\n");
1709     for (k = 0; k < nDims; ++k)
1710     printf("%10lg", pointlo[k]);
1711     printf("\n");
1712    
1713     return 0;
1714     }
1715    
1716     #endif
1717    
1718     #ifdef TEST_NEXT
1719     #include <stdio.h>
1720    
1721     int main()
1722     {
1723     unsigned i;
1724     unsigned c1[100], c2[100], pt[100];
1725     unsigned nDims, nBytes = 4;
1726     int stat, findPrev;
1727     printf("Enter nDims: " );
1728     scanf("%u", &nDims);
1729    
1730     printf("Enter 1st box corner: ");
1731     for (i = 0; i < nDims; ++i)
1732     scanf("%u", &c1[i]);
1733     printf("Enter 2nd box corner: ");
1734     for (i = 0; i < nDims; ++i)
1735     scanf("%u", &c2[i]);
1736     printf("Enter point: ");
1737     for (i = 0; i < nDims; ++i)
1738     scanf("%u", &pt[i]);
1739     printf("Find prev?: ");
1740     scanf("%d", &findPrev);
1741    
1742     stat = hilbert_nextinbox(nDims, nBytes, 8*nBytes, findPrev, c1, c2, pt);
1743    
1744     if (stat)
1745     for (i = 0; i < nDims; ++i)
1746     printf("%u ", c1[i]);
1747     else
1748     printf("No such point");
1749    
1750     printf("\n");
1751     return 0;
1752     }
1753     #endif