Algorithm Search⌘K

Proofs: Geohash

These are the human proofs of Geohash, at full length.

Geohash encodes the interleaved bits of the cell that holds the point full

This proof shows: correctness, termination.

We use the names of the pseudocode GEOHASH-ENCODE(φ,λ,p)(\varphi, \lambda, p), with φ∈[−90,90]\varphi \in [-90, 90] and λ∈[−180,180]\lambda \in [-180, 180]. Let tt be the number of passes of the loop of line L3 so far, so t=5∣s∣+bitst = 5|s| + bits. Write a(t)=⌈t/2⌉a(t) = \lceil t/2 \rceil and e(t)=⌊t/2⌋e(t) = \lfloor t/2 \rfloor for the numbers of longitude and latitude bits among the first tt bits. For an integer m≥0m \ge 0 and a value zz in a range [L,H][L, H], let

idx⁡m(z)=min⁡ ⁣(⌊z−LH−L 2m⌋, 2m−1),\operatorname{idx}_m(z) = \min\!\Big(\Big\lfloor \frac{z - L}{H - L}\, 2^m \Big\rfloor,\ 2^m - 1\Big),

the index of the part of [L,H][L, H] that holds zz when the range is cut into 2m2^m equal parts, with the top value z=Hz = H in the top part. Write Xt=idx⁡a(t)(λ)X_t = \operatorname{idx}_{a(t)}(\lambda) over [−180,180][-180, 180] and Yt=idx⁡e(t)(φ)Y_t = \operatorname{idx}_{e(t)}(\varphi) over [−90,90][-90, 90].

Claim. The output ss has pp characters, and its 5p5p bits are b1…b5pb_1 \ldots b_{5p}, where the subsequence b1b3b5…b_1 b_3 b_5 \ldots is the binary form of X5pX_{5p} with a(5p)a(5p) digits and b2b4…b_2 b_4 \ldots is the binary form of Y5pY_{5p} with e(5p)e(5p) digits. The point lies in the cell given by the final intervals.

Invariant. At the test of line L3, after tt passes:

  1. λlo=−180+360 Xt/2a(t)\lambda_{lo} = -180 + 360\, X_t / 2^{a(t)} and λhi=λlo+360/2a(t)\lambda_{hi} = \lambda_{lo} + 360 / 2^{a(t)}, and λlo≤λ≤λhi\lambda_{lo} \le \lambda \le \lambda_{hi}, with λ<λhi\lambda < \lambda_{hi} unless λhi=180\lambda_{hi} = 180.
  2. The same holds for φ\varphi, with −90-90, 180180, e(t)e(t) and YtY_t.
  3. The longitude bits produced so far, in order, are the binary form of XtX_t with a(t)a(t) digits, and the latitude bits are the binary form of YtY_t with e(t)e(t) digits.
  4. chch is the number whose binary form is the last bitsbits bits produced, 0≤bits≤40 \le bits \le 4, and ss holds the first 5∣s∣5|s| bits, five per character, as the indices of its characters in Σ\Sigma.
  5. eveneven is true exactly when tt is even.

Initialization. At t=0t = 0, line L1 sets the full ranges, a(0)=e(0)=0a(0) = e(0) = 0 and X0=Y0=0X_0 = Y_0 = 0, so parts 1 and 2 hold, with λ<180\lambda < 180 or λhi=180\lambda_{hi} = 180. No bits exist, so part 3 holds. Line L2 sets ss empty, bits=0bits = 0, ch=0ch = 0 and eveneven true, so parts 4 and 5 hold.

Maintenance. Take a pass with tt even, so by part 5 line L4 runs and cuts the longitude interval; the odd case is the same with line L5 and the latitude. The pass makes bit bt+1b_{t+1}, an odd position, and a(t+1)=a(t)+1a(t+1) = a(t) + 1, e(t+1)=e(t)e(t+1) = e(t). Let w=360/2a(t)w = 360 / 2^{a(t)} and mid=λlo+w/2mid = \lambda_{lo} + w/2.

  • If λ≥mid\lambda \ge mid, the bit is 1 and the new interval is [mid,λhi][mid, \lambda_{hi}]. Then (λ−(−180))/360⋅2a(t)+1(\lambda - (-180))/360 \cdot 2^{a(t)+1} lies in [2Xt+1,2Xt+2][2X_t + 1, 2X_t + 2], and it equals 2Xt+22X_t + 2 only when λ=λhi\lambda = \lambda_{hi}, which by part 1 happens only when λhi=180\lambda_{hi} = 180, where the minimum in idx⁡\operatorname{idx} caps the index. So Xt+1=2Xt+1X_{t+1} = 2X_t + 1.
  • If λ<mid\lambda < mid, the bit is 0, the new interval is [λlo,mid][\lambda_{lo}, mid], and the same computation gives a value in [2Xt,2Xt+1)[2X_t, 2X_t + 1), so Xt+1=2XtX_{t+1} = 2X_t, and λ\lambda is strictly below the new upper end.

In both cases the new interval has the form of part 1 for Xt+1X_{t+1} and a(t+1)a(t+1), it holds λ\lambda, and the upper end stays strict unless it is 180180. The latitude is not changed and ee is not changed, so part 2 holds. Appending a bit β\beta to the binary form of XtX_t gives 2Xt+β=Xt+12X_t + \beta = X_{t+1}, so part 3 holds. Line L4 sets ch←2ch+βch \leftarrow 2ch + \beta, which appends the bit to the binary form of chch, and line L6 adds 1 to bitsbits. If bitsbits becomes 5, line L7 appends the character of index chch, which holds the last five bits, and resets bitsbits and chch to 0. So part 4 holds. Line L6 flips eveneven, and t+1t + 1 is odd, so part 5 holds.

Termination. Each pass adds 1 to t=5∣s∣+bitst = 5|s| + bits. Since bits≤4bits \le 4 by part 4, ∣s∣|s| grows by one every five passes, so after exactly 5p5p passes ∣s∣=p|s| = p and the loop stops. At that point bits=0bits = 0, so all 5p5p bits are in ss. By part 3 they are the bits of the claim, and by parts 1 and 2 the point lies in the final intervals. ■\blacksquare

Prefix property. The bits of a pass do not depend on pp: the loop for length pp runs the same passes as the loop for length q<pq < p and then more. So the geohash of length qq is the prefix of length qq of the geohash of length pp, and the cell of the longer string lies inside the cell of the shorter one, since each pass keeps half of an interval.

Back to Geohash