{"id":947,"date":"2009-08-14T16:00:06","date_gmt":"2009-08-15T00:00:06","guid":{"rendered":"https:\/\/www.reenigne.org\/blog\/?p=947"},"modified":"2011-08-08T13:44:05","modified_gmt":"2011-08-08T20:44:05","slug":"improved-geohashing-algorithm","status":"publish","type":"post","link":"https:\/\/www.reenigne.org\/blog\/improved-geohashing-algorithm\/","title":{"rendered":"Improved geohashing algorithm"},"content":{"rendered":"<p><a href=\"http:\/\/wiki.xkcd.com\/geohashing\/Main_Page\">Geohashing<\/a> is an awesome idea (though I've never actually gone to any of the hash points). However, it does suffer from some problems - often the chosen location will be too far away, or in an inaccessible area. It is also slightly biased towards the poles (though because few people live in the polar regions this isn't a particularly big deal for most people). It would be nice to have an improved algorithm which solves these problems.<\/p>\n<p>We'll start the same way, by hashing the date and that date's DOW opening to get a set of 128 random bits <img src='https:\/\/s0.wp.com\/latex.php?latex=R&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='R' title='R' class='latex' \/>.<\/p>\n<p>Given any area A we want to find a function (which we'll call <img src='https:\/\/s0.wp.com\/latex.php?latex=f%28A%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='f(A)' title='f(A)' class='latex' \/>) mapping a set of bits <img src='https:\/\/s0.wp.com\/latex.php?latex=R&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='R' title='R' class='latex' \/> onto a point <img src='https:\/\/s0.wp.com\/latex.php?latex=x&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='x' title='x' class='latex' \/>, <img src='https:\/\/s0.wp.com\/latex.php?latex=%28f%28A%29%29%28R%29+%3D+x&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='(f(A))(R) = x' title='(f(A))(R) = x' class='latex' \/>. We would also like to have the property that if <img src='https:\/\/s0.wp.com\/latex.php?latex=B&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='B' title='B' class='latex' \/> is a subset of <img src='https:\/\/s0.wp.com\/latex.php?latex=A&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='A' title='A' class='latex' \/> containing <img src='https:\/\/s0.wp.com\/latex.php?latex=x&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='x' title='x' class='latex' \/> and if <img src='https:\/\/s0.wp.com\/latex.php?latex=%28f%28A%29%29%28R%29+%3D+x&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='(f(A))(R) = x' title='(f(A))(R) = x' class='latex' \/> then <img src='https:\/\/s0.wp.com\/latex.php?latex=%28f%28B%29%29%28R%29+%3D+x&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='(f(B))(R) = x' title='(f(B))(R) = x' class='latex' \/>. So if the New York State meetup happened to be in New York City, all the people who were just going to the New York City meetup would be there too. Another desirable property would be if the points <img src='https:\/\/s0.wp.com\/latex.php?latex=%28f%28A%29%29%28R%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='(f(A))(R)' title='(f(A))(R)' class='latex' \/> were evenly spread throughout <img src='https:\/\/s0.wp.com\/latex.php?latex=A&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='A' title='A' class='latex' \/>.<\/p>\n<p>Here is an algorithm that I think fulfills both properties.<\/p>\n<p>First, use <img src='https:\/\/s0.wp.com\/latex.php?latex=R&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='R' title='R' class='latex' \/> to pick a random point on the globe, taking 64-bit random floating point fractions <img src='https:\/\/s0.wp.com\/latex.php?latex=u&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='u' title='u' class='latex' \/> and <img src='https:\/\/s0.wp.com\/latex.php?latex=v&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='v' title='v' class='latex' \/> in <img src='https:\/\/s0.wp.com\/latex.php?latex=%5B0%2C1%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='[0,1)' title='[0,1)' class='latex' \/> from <img src='https:\/\/s0.wp.com\/latex.php?latex=R&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='R' title='R' class='latex' \/> in the usual way and then transforming them into longitude and latitude as:<br \/>\n<img src='https:\/\/s0.wp.com\/latex.php?latex=%5Cdisplaystyle+long+%3D+360frac%28u%2Ba%28N%29%29-180&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='\\displaystyle long = 360frac(u+a(N))-180' title='\\displaystyle long = 360frac(u+a(N))-180' class='latex' \/><br \/>\n<img src='https:\/\/s0.wp.com\/latex.php?latex=%5Cdisplaystyle+lat+%3D+%5Cfrac%7B180%7D%7B%5Cpi%7Dcos%5E%7B-1%7D%282frac%28v%2Bb%28N%29%29-1%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='\\displaystyle lat = \\frac{180}{\\pi}cos^{-1}(2frac(v+b(N))-1)' title='\\displaystyle lat = \\frac{180}{\\pi}cos^{-1}(2frac(v+b(N))-1)' class='latex' \/><br \/>\nWhere <img src='https:\/\/s0.wp.com\/latex.php?latex=frac&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='frac' title='frac' class='latex' \/> takes the fractional part, leaving a number between 0 and 1 (one could also use XOR instead of add and <img src='https:\/\/s0.wp.com\/latex.php?latex=frac&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='frac' title='frac' class='latex' \/>) and <img src='https:\/\/s0.wp.com\/latex.php?latex=N&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='N' title='N' class='latex' \/> is the smallest integer <img src='https:\/\/s0.wp.com\/latex.php?latex=%3E+0&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='&gt; 0' title='&gt; 0' class='latex' \/> that causes the resulting coordinates to end up inside <img src='https:\/\/s0.wp.com\/latex.php?latex=A&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='A' title='A' class='latex' \/>.<\/p>\n<p><img src='https:\/\/s0.wp.com\/latex.php?latex=a&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='a' title='a' class='latex' \/> and <img src='https:\/\/s0.wp.com\/latex.php?latex=b&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='b' title='b' class='latex' \/> are functions that find points that are furthest away from any tried so far. They have binary expansions as follows:<\/p>\n<pre>\r\nN  a(N)  b(N)  c(N)     d(N)\r\n0  0.000 0.000 0.000000 0.000000\r\n1  0.100 0.100 0.110000 0.100000\r\n2  0.100 0.000 0.010000 0.010000\r\n3  0.000 0.100 0.100000 0.110000\r\n4  0.010 0.010 0.001100 0.001000\r\n5  0.110 0.110 0.111100 0.101000\r\n6  0.110 0.010 0.011100 0.011000\r\n7  0.010 0.110 0.101100 0.111000\r\n8  0.010 0.000 0.000100 0.000100\r\n9  0.110 0.100 0.110100 0.100100\r\n10 0.110 0.000 0.010100 0.010100\r\n11 0.010 0.100 0.100100 0.110100\r\n12 0.000 0.010 0.001000 0.001100\r\n13 0.100 0.110 0.111000 0.101100\r\n14 0.100 0.010 0.011000 0.011100\r\n15 0.000 0.110 0.101000 0.111100\r\n16 0.001 0.001 0.000011 0.000010\r\n<\/pre>\n<p>And so on, to as many binary places as you need. If you interleave the bits of <img src='https:\/\/s0.wp.com\/latex.php?latex=a%28N%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='a(N)' title='a(N)' class='latex' \/> and <img src='https:\/\/s0.wp.com\/latex.php?latex=b%28N%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='b(N)' title='b(N)' class='latex' \/> you get <img src='https:\/\/s0.wp.com\/latex.php?latex=c%28N%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='c(N)' title='c(N)' class='latex' \/>, which looks like <img src='https:\/\/s0.wp.com\/latex.php?latex=d%28N%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='d(N)' title='d(N)' class='latex' \/> but with each even bit XORed with the bit to its left. <img src='https:\/\/s0.wp.com\/latex.php?latex=d%28N%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='d(N)' title='d(N)' class='latex' \/> is the binary expansion of the integers but with the bits in the reverse order (and flipped to the other side of the binary point).<\/p>\n<p>The sequences <img src='https:\/\/s0.wp.com\/latex.php?latex=a&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='a' title='a' class='latex' \/> and <img src='https:\/\/s0.wp.com\/latex.php?latex=b&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='b' title='b' class='latex' \/> together are related to the Bayer matrix which describe a 2D ordered dither. If you want 65 shades of grey but only have a grid of 8x8 pixels, each of which can only be black or white, the most regular patterns with n black bits are described by those that have <img src='https:\/\/s0.wp.com\/latex.php?latex=8a%28N%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='8a(N)' title='8a(N)' class='latex' \/> and <img src='https:\/\/s0.wp.com\/latex.php?latex=8b%28N%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='8b(N)' title='8b(N)' class='latex' \/> black if <img src='https:\/\/s0.wp.com\/latex.php?latex&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='' title='' class='latex' \/>N<n[\/latex] and white otherwise.\n\n<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Geohashing is an awesome idea (though I've never actually gone to any of the hash points). However, it does suffer from some problems - often the chosen location will be too far away, or in an inaccessible area. It is also slightly biased towards the poles (though because few people live in the polar regions [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[40],"tags":[],"class_list":["post-947","post","type-post","status-publish","format-standard","hentry","category-random"],"_links":{"self":[{"href":"https:\/\/www.reenigne.org\/blog\/wp-json\/wp\/v2\/posts\/947","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.reenigne.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.reenigne.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.reenigne.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.reenigne.org\/blog\/wp-json\/wp\/v2\/comments?post=947"}],"version-history":[{"count":7,"href":"https:\/\/www.reenigne.org\/blog\/wp-json\/wp\/v2\/posts\/947\/revisions"}],"predecessor-version":[{"id":1348,"href":"https:\/\/www.reenigne.org\/blog\/wp-json\/wp\/v2\/posts\/947\/revisions\/1348"}],"wp:attachment":[{"href":"https:\/\/www.reenigne.org\/blog\/wp-json\/wp\/v2\/media?parent=947"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.reenigne.org\/blog\/wp-json\/wp\/v2\/categories?post=947"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.reenigne.org\/blog\/wp-json\/wp\/v2\/tags?post=947"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}