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

File Contents

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