2008-07-28

実践 Common Lisp

できたらしい!

買っちゃうしかないでしょ

2008-07-19

IPv6の年になる、か?

もうそろそろ梅雨も明けて8月になろうとしてるから、今年「も」IPv6は来ないかもねえ。

自分的にはそろそろ勉強せねばな、と思ってIPv6エッセンシャルズ第2版を読んでみたよ。
技術的なことじゃなくて概要をわかりやすく説明してくれているので、僕のようなネットワーク管理作業員ではなく、マネージャクラスの人が読むといい本だと思った。

ポルトガルのPorto大学の導入事例にある管理者のコメントが印象深い。
「…IPv4はこれら問題をすべて乗り越えてきている。経済的な理由から、開発者や製造業者が問題を解決すべくがんばってきたからだ。同じ理由から、企業や機関はIPv6導入の必要性を感じたら、たとえ導入が複雑であっても、IPv6は急速に標準的なプロトコルとなるだろう。」


ながらくIPv6のキラーアプリを探す試みが続けられてきたけど、結局のところこの経済的理由こそが移行の唯一の強力な動機になるのかも。
もう枯渇が目に見えてるIPv4グローバルアドレスはこれからその価値がどんどん上がっていくのは間違いない。闇市場が形成される可能性だってある。(今現在のルールでは売買は禁止されているはず。)
ゼニは人を動かす強力な要因だしね。

あとはそのIPv6使ったほうがお得じゃんターニングポイントがどこになるのか、だな。
今後この臨界点の読み合いが熱くなってくるのかな。誰が先に得するのか。ギラギラ。

一旦お得となってしまえば、64NATだろうが464NATだろうがいかなる困難も乗り越えていけるだろう。単にIPv6使ったほうがお得だからという理由だけで。かつてIPv4、CIDR、NAPTがそうしたほうがv6移行よりお得だったのと同じように。

2008-07-03

Gaucheでgeohash できた

Gaucheでgeohashする一連の投稿だけど、やっとライブラリが完成した。

モジュール化もやってみたよ。
(use geohash)
で使える。

関数はふたつ。

geohash-encode LATITUDE LONGITUDE (:precision 9)
=> geohash文字列

geohash-decode GEOHASH
=> LATITUDE LONGITUDE LAT下限 LAT上限 LON下限 LON上限

デコードのときはgeohashの文字列の長さで有効桁が長くなるので、返した座標値のほかにその座標値がどれくらいの範囲まで正確なのかの値も返してる。
多値を返せるって便利だなあ。


#!/usr/bin/env gosh
;; Copyright (c) 2008 KOGA Kazuo
;; MIT License
;;
;; Geohash
;; see http://en.wikipedia.org/wiki/Geohash
;;

(define-module geohash
(use srfi-1)
(use gauche.sequence)
(use gauche.collection)
(use gauche.uvector)
(export geohash-encode
geohash-decode))
(select-module geohash)

(define (medium x y) (/ (+ x y) 2))

(define (interval-choice which min max)
(if (= 0 which)
(values min (medium min max))
(values (medium min max) max)))

(define (interval-fold code min max)
(fold2 interval-choice min max
code))

(define (interval-fold-fold codes min max)
(fold2 interval-fold min max
codes))

(define (interval-bit n min max)
(let1 mid (medium min max)
(if (< n mid)
(values 0 min mid)
(values 1 mid max))))

(define base32-base
#(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7
#\8 #\9 #\b #\c #\d #\e #\f #\g
#\h #\j #\k #\m #\n #\p #\q #\r
#\s #\t #\u #\v #\w #\x #\y #\z))

(define base32-bits
#(#u8(0 0 0 0 0) #u8(0 0 0 0 1) #u8(0 0 0 1 0) #u8(0 0 0 1 1)
#u8(0 0 1 0 0) #u8(0 0 1 0 1) #u8(0 0 1 1 0) #u8(0 0 1 1 1)
#u8(0 1 0 0 0) #u8(0 1 0 0 1) #u8(0 1 0 1 0) #u8(0 1 0 1 1)
#u8(0 1 1 0 0) #u8(0 1 1 0 1) #u8(0 1 1 1 0) #u8(0 1 1 1 1)
#u8(1 0 0 0 0) #u8(1 0 0 0 1) #u8(1 0 0 1 0) #u8(1 0 0 1 1)
#u8(1 0 1 0 0) #u8(1 0 1 0 1) #u8(1 0 1 1 0) #u8(1 0 1 1 1)
#u8(1 1 0 0 0) #u8(1 1 0 0 1) #u8(1 1 0 1 0) #u8(1 1 0 1 1)
#u8(1 1 1 0 0) #u8(1 1 1 0 1) #u8(1 1 1 1 0) #u8(1 1 1 1 1)
))

(define (pos-even?)
(let1 even #f
(lambda (_)
(set! even (not even))
even)))

(define (decode-base32 s)
(map (lambda (c)
(ref base32-bits
(find-index (cut eqv? c <>) base32-base)))
s))

(define (geohash-decode str)
"geohash => latitude longitude latitude-min latitude-max longitude-min longitude-max"
(let ((bits (decode-base32 str))
(pos (pos-even?)))
(let loop ((b bits)
(lon-min -180.0)
(lon-max 180.0)
(lat-min -90.0)
(lat-max 90.0))
(if (null? b)
(values (medium lat-min lat-max)
(medium lon-min lon-max)
lat-min lat-max
lon-min lon-max)
(receive (lon lat)
(partition pos (car b))
(receive (lomin lomax)
(interval-fold lon lon-min lon-max)
(receive (lamin lamax)
(interval-fold lat lat-min lat-max)
(loop (cdr b)
lomin lomax lamin lamax))))))))

(define (bit->number b0 b1 b2 b3 b4)
(+ (* b0 16)
(* b1 8)
(* b2 4)
(* b3 2)
b4))

(define (encode longitude latitude precision)
(define (req-bits n)
(receive (q r) (quotient&remainder n 2)
(+ (* n 2) q r)))
(define (morton-bits num min max count)
(let loop ((i 0)
(min min)
(max max)
(ret '()))
(if (< i count)
(receive (bit min max) (interval-bit num min max)
(loop (+ i 1) min max (cons bit ret)))
(reverse! ret))))
(define (composer a b)
(values (bit->number (ref a 0) (ref b 0)
(ref a 1) (ref b 1)
(ref a 2))
(drop a 3) (drop b 2)))

(let* ((need-bits (req-bits precision))
(lon-bits (morton-bits longitude -180 180 need-bits))
(lat-bits (morton-bits latitude -90 90 need-bits)))
(let loop ((lon lon-bits)
(lat lat-bits)
(even #t)
(ret '()))
(if (null? lon)
(map-to <string>
(lambda (e)
(ref base32-base e))
(reverse! ret))
(receive (n a b)
(if even
(composer lon lat)
(composer lat lon))
(if even
(loop a b (not even) (cons n ret))
(loop b a (not even) (cons n ret))))))))

(define (geohash-encode latitude longitude . opts)
"latitude longitude => geohash"
(unless (and (<= -90 latitude 90)
(<= -180 longitude 180))
(error "geohash-encode: bad domain: latitude or longitude"))
(let-keywords opts ((precision 9))
(encode longitude latitude precision)))

(provide "geohash")

Gaucheでgeohash つづき

デコードだけじゃなくエンコードも欲しい。ね。

とりあえずできた。コードをぺたり。

でもなんか geohash.orgと精度の扱いが違うなあ。
アルゴリズムを根本的に勘違いしてるのかもしれん。


#!/usr/bin/env gosh
;; Copyright (c) 2008 KOGA Kazuo
;; MIT License
;;
;; Geohash
;; see http://en.wikipedia.org/wiki/Geohash
;;

(use srfi-1)
(use gauche.sequence)
(use gauche.collection)
(use gauche.uvector)

(define (medium x y) (/ (+ x y) 2))

(define (interval-choice which min max)
(if (= 0 which)
(values min (medium min max))
(values (medium min max) max)))

(define (interval-fold code min max)
(fold2 interval-choice min max
code))

(define (interval-fold-fold codes min max)
(fold2 interval-fold min max
codes))

(define (interval-bit n min max)
(let1 mid (medium min max)
(if (< n mid)
(values 0 min mid)
(values 1 mid max))))

(define base32-base
#(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7
#\8 #\9 #\b #\c #\d #\e #\f #\g
#\h #\j #\k #\m #\n #\p #\q #\r
#\s #\t #\u #\v #\w #\x #\y #\z))

(define base32-bits
#( #u8(0 0 0 0 0) #u8(0 0 0 0 1) #u8(0 0 0 1 0) #u8(0 0 0 1 1)
#u8(0 0 1 0 0) #u8(0 0 1 0 1) #u8(0 0 1 1 0) #u8(0 0 1 1 1)
#u8(0 1 0 0 0) #u8(0 1 0 0 1) #u8(0 1 0 1 0) #u8(0 1 0 1 1)
#u8(0 1 1 0 0) #u8(0 1 1 0 1) #u8(0 1 1 1 0) #u8(0 1 1 1 1)
#u8(1 0 0 0 0) #u8(1 0 0 0 1) #u8(1 0 0 1 0) #u8(1 0 0 1 1)
#u8(1 0 1 0 0) #u8(1 0 1 0 1) #u8(1 0 1 1 0) #u8(1 0 1 1 1)
#u8(1 1 0 0 0) #u8(1 1 0 0 1) #u8(1 1 0 1 0) #u8(1 1 0 1 1)
#u8(1 1 1 0 0) #u8(1 1 1 0 1) #u8(1 1 1 1 0) #u8(1 1 1 1 1)
))

(define (pos-even?)
(let1 even #f
(lambda (_)
(set! even (not even))
even)))

(define (decode-base32 s)
(map (lambda (c)
(ref base32-bits
(find-index (cut eqv? c <>) base32-base)))
s))

(define (geohash-decode str)
"geohash => latitude longitude"
(let ((bits (decode-base32 str))
(pos (pos-even?)))
(let loop ((b bits)
(lon-min -180.0)
(lon-max 180.0)
(lat-min -90.0)
(lat-max 90.0))
(if (null? b)
(values (medium lat-min lat-max)
(medium lon-min lon-max))
(receive (lon lat)
(partition pos (car b))
(receive (lomin lomax)
(interval-fold lon lon-min lon-max)
(receive (lamin lamax)
(interval-fold lat lat-min lat-max)
(loop (cdr b)
lomin lomax lamin lamax))))))))

(define (bit->number b0 b1 b2 b3 b4)
(+ (* b0 16)
(* b1 8)
(* b2 4)
(* b3 2)
b4))

(define (encode longitude latitude precision)
(define (req-bits n)
(receive (q r) (quotient&remainder n 2)
(+ (* n 2) q r)))
(define (morton-bits num min max count)
(let loop ((i 0)
(min min)
(max max)
(ret '()))
(if (< i count)
(receive (bit min max) (interval-bit num min max)
(loop (+ i 1) min max (cons bit ret)))
(reverse! ret))))
(define (composer a b)
(values (bit->number (ref a 0) (ref b 0)
(ref a 1) (ref b 1)
(ref a 2))
(drop a 3) (drop b 2)))

(let* ((need-bits (req-bits precision))
(lon-bits (morton-bits longitude -180 180 need-bits))
(lat-bits (morton-bits latitude -90 90 need-bits)))
(let loop ((lon lon-bits)
(lat lat-bits)
(even #t)
(ret '()))
(if (null? lon)
(map-to <string>
(lambda (e)
(ref base32-base e))
(reverse! ret))
(receive (n a b)
(if even
(composer lon lat)
(composer lat lon))
(if even
(loop a b (not even) (cons n ret))
(loop b a (not even) (cons n ret))))))))

(define (geohash-encode latitude longitude . opts)
"latitude longitude => geohash"
(unless (and (<= -90 latitude 90)
(<= -180 longitude 180))
(error "geohash-encode: bad domain: latitude or longitude"))
(let-keywords opts ((precision 8))
(encode longitude latitude precision)))

#?=
(geohash-decode "ezs42")
#?=
(geohash-encode 42.6 -5.6 :precision 64)
#?=
(geohash-decode "s00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
#?=
(geohash-encode 89.99999999999999999999999999999 0)

2008-07-02

Gaucheでgeohash

Gauchegeohashデコードする。

一応動くようになった。
ちゃんとモジュールにするのはまだ勉強してない。これからやる。
てか、ブロッガってtarのアップロードできないのね。。。
ソースべたで張るよ。


#!/usr/bin/env gosh
;; Copyright (c) 2008 KOGA Kazuo
;; MIT License
;;
;; Geohash
;; see http://en.wikipedia.org/wiki/Geohash
;;

(use gauche.sequence)
(use gauche.collection)
(use gauche.uvector)

(define (medium x y) (/ (+ x y) 2))

(define (interval-choice which min max)
(if (= 0 which)
(values min (medium min max))
(values (medium min max) max)))

(define (interval-fold code min max)
(fold2 interval-choice min max
code))

(define (interval-fold-fold codes min max)
(fold2 interval-fold min max
codes))

(define base32-base
#(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7
#\8 #\9 #\b #\c #\d #\e #\f #\g
#\h #\j #\k #\m #\n #\p #\q #\r
#\s #\t #\u #\v #\w #\x #\y #\z))
(define base32-bits
#( #u8(0 0 0 0 0) #u8(0 0 0 0 1) #u8(0 0 0 1 0) #u8(0 0 0 1 1)
#u8(0 0 1 0 0) #u8(0 0 1 0 1) #u8(0 0 1 1 0) #u8(0 0 1 1 1)
#u8(0 1 0 0 0) #u8(0 1 0 0 1) #u8(0 1 0 1 0) #u8(0 1 0 1 1)
#u8(0 1 1 0 0) #u8(0 1 1 0 1) #u8(0 1 1 1 0) #u8(0 1 1 1 1)
#u8(1 0 0 0 0) #u8(1 0 0 0 1) #u8(1 0 0 1 0) #u8(1 0 0 1 1)
#u8(1 0 1 0 0) #u8(1 0 1 0 1) #u8(1 0 1 1 0) #u8(1 0 1 1 1)
#u8(1 1 0 0 0) #u8(1 1 0 0 1) #u8(1 1 0 1 0) #u8(1 1 0 1 1)
#u8(1 1 1 0 0) #u8(1 1 1 0 1) #u8(1 1 1 1 0) #u8(1 1 1 1 1)
))

(define (pos-even?)
(let1 even #f
(lambda (_)
(set! even (not even))
even)))

(define (decode-base32 s)
(map (lambda (c)
(ref base32-bits
(find-index (cut eqv? c <>) base32-base)))
s))

(define (geohash-decode str)
"geohash => longitude latitude"
(let ((bits (decode-base32 str))
(pos (pos-even?)))
(let loop ((b bits)
(lon-min -180.0)
(lon-max 180.0)
(lat-min -90.0)
(lat-max 90.0))
(if (null? b)
(values (medium lon-min lon-max)
(medium lat-min lat-max))
(receive (lon lat)
(partition pos (car b))
(receive (lomin lomax)
(interval-fold lon lon-min lon-max)
(receive (lamin lamax)
(interval-fold lat lat-min lat-max)
(loop (cdr b)
lomin lomax lamin lamax))))))))
#?=
(geohash-decode "ezs42")