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