Gauche

2010年02月20日

shiroさんに教わったのでメモっておきます

;;; from shiro
(defun gauche-info-index (topic)
  (interactive
   (list (read-string
	  (concat "Gauche help topic : ")
          (current-word))))
  (switch-to-buffer-other-window (get-buffer-create "*info*"))
  (info "/usr/share/info/gauche-refe.info.gz")
;;(info "/usr/local/share/info/gauche-refe.info.gz") ;;うちは/usr/local/

  (Info-index topic))

;;(define-key global-map "\C-xH" 'gauche-info-index) ;; original
(define-key global-map "\C-x\C-j" 'gauche-info-index) ;; naoya_t

キーバインドは C-x H だとシフト押すのが面倒なので、うちでは C-x C-j に移しました。(キーバインドは皆さんのお好みで!)

調べたい関数名の後でC-x C-jするとinfoが引けます。これは便利。



(20:05) Φ

2010年02月09日

gistに貼ってるだけだと忘れそうなのでここにもメモっとく。

「プログラミングErlang」の§12.2 に、ErlangからCの関数を利用する方法があるので、同等なインターフェイスを書けば

(define (twice x) (* 2 x))
(define (sum x y) (+ x y))

のようなScheme(Gauche)の関数も呼び出せる。

Eshell V5.7.4  (abort with ^G)
1> c(example1).
{ok,example1}
2> example1:start().
<0.39.0>
3> example1:twice(48). 
96
4> example1:sum(17,25).
42
...
続きを読む

(20:45) Φ

2010年01月25日

Schemeでも写経してみたの巻。C++編はこちら

#;'(べ、べつにS式で書かないと理解できないわけじゃないんだからね)

(define (lg x) (integer-length (- x 1)))

(define (interpolative-encode L L-length lo hi)
  (define (binary-encode x low high result)
    (let* ([range (+ (- high low) 1)]
           [bnum (lg range)]
           [enc (- x low)])
      (let loop ((i (- bnum 1)) (result result))
        (if (< i 0) result
            (loop (- i 1) (cons (if (logbit? i enc) 1 0) result))))))
  (define (iter f lo hi left right result)
    (cond [(= f 0) result]
          [(= f 1) (binary-encode (vector-ref L left) lo hi result)]
          [else
           (let* ([h (quotient f 2)]
                  [m (vector-ref L (+ left h))]
                  [f1 h]
                  [f2 (- f h 1)])
             (iter f2 (+ m 1) hi (+ left h 1) right
                   (iter f1 lo (- m 1) left (+ left h)
                         (binary-encode m (+ lo f1) (- hi f2) result))))]))
  (let1 L-length (vector-length L)
  (reverse! (iter L-length lo hi 0 L-length '())))


(define (interpolative-decode L L-length lo hi input-stream)
  (define (binary-decode low high iter)
    (let* ([range (+ (- high low) 1)]
           [bnum (lg range)])
      (let loop ((i 0) (dec 0) (iter iter))
        (if (= i bnum)
            (values (+ low dec) iter)
            (let1 b (car iter)
              (loop (+ i 1) (+ (* dec 2) (car iter)) (cdr iter)))))))
  (define (iter f lo hi left right input-stream)
    (cond [(= f 0) input-stream]
          [(= f 1)
           (receive (m stream) (binary-decode lo hi input-stream)
             (vector-set! L left m)
             stream)]
          [else
           (let* ([h (quotient f 2)]
                  [f1 h]
                  [f2 (- f h 1)])
             (receive (m stream) (binary-decode (+ lo f1) (- hi f2) input-stream)
               (vector-set! L (+ left h) m)
               (iter f2 (+ m 1) hi (+ left h 1) right
                     (iter f1 lo (- m 1) left (+ left h) stream))))]))
  (iter L-length lo hi 0 L-length input-stream))

(define (main args)
  (let* ([L #(3 8 9 11 12 13 17)]
         [lo 1]
         [hi 20]
         [L-length (vector-length L)]
         [Ldec (make-vector L-length)]) ; 結果格納用vec
    (print "original: " L)
    (let1 encoded-bitstream (interpolative-encode L L-length lo hi)
      (format #t "encoded (~d bits): ~a\n" (length encoded-bitstream) encoded-bitstream)
      (interpolative-decode Ldec L-length lo hi encoded-bitstream)
      (print "decoded: " Ldec))))

結果

original: #(3 8 9 11 12 13 17)
encoded (17 bits): (0 1 1 1 1 1 0 0 1 0 0 0 0 0 0 1 1)
decoded: #(3 8 9 11 12 13 17)

17bitに圧縮後、ちゃんと復号できて一安心。



(19:30) Φ

2010年01月21日

こんな便利なものがあるなんて知らずに生きていた(恥)

Function: info symbol

Gaucheのinfoドキュメント中から、 symbolで指定される手続きか構文要素の定義を含んでいるページを表示します。 infoドキュメントは、もし環境変数INFOPATHが定義されていればそこに示されるディレクトリ中から探され、そうでなければgoshのライブラリディレクトリから推測されるディレクトリ中から探されます。infoドキュメントが見付からなかったり、見付かってもsymbolがIndexページ中に無かった場合はエラーとなります。つまり、この手続きはinfoファイルがインストールされていないと動作しません。

現在の出力ポートが端末である場合、infoドキュメントの該当ページはページングプログラムを用いて表示されます。環境変数PAGERが指定されていればそれを用い、そうでなければコマンドサーチパスからless及びmoreをこの順で探します。いずれも見付からなかった場合や、出力ポートが端末ではない場合には、単にページがそのまま出力されます。

この手続きのセッション中での最初の呼び出しは、infoファイルをパーズするために多少時間がかかります。

info - gauche.interactive

unfoldの引数の順番に迷った時とか、REPLから

gosh> (info 'unfold)

と打てば

10.2.5 List fold, unfold & map
------------------------------

...
... (foldとかreduceとかの定義) 
...

 -- Function: unfold p f g seed &optional tail-gen
     [SRFI-1] Fundamental recursive list constructor.  Defined by the
     following recursion.

          (unfold p f g seed tail-gen) ==
             (if (p seed)
                 (tail-gen seed)
                 (cons (f seed)
                       (unfold p f g (g seed))))
     That is, P determines where to stop, G is used to generate
     successive seed value from the current seed value, and F is used
     to map each seed value to a list element.
...

qを打てばまたREPLに戻って来られる。これは便利。



(10:52) Φ

2010年01月20日

久々にMeCabを使いたくなったのでGauche-mecabをインストールしたい(が少しはまった)のでメモ。

1. ビルドはGauche-0.9でもSnow Leopardでも行けるっぽい。

  • CFLAGS='-arch i386' LDFLAGS='-arch i386' ./configure とかしなくても可か

2. ビルドはできるが make check で失敗する。

  • /usr/lib/にある、Snow Leopardに元々入ってる?MeCabを見に行ってしまうため。
mecab-lib.$(SOEXT): $(srcdir)/mecab-lib.scm
    $(GENCOMP) --ext-module=text/mecab.scm $(srcdir)/mecab-lib.scm
    $(GAUCHE_PACKAGE) compile \
      --local=$(LOCAL_PATHS) --ldflags='-L/usr/local/lib' --libs='-lmecab' --verbose mecab-lib mecab-lib.c

のようにldflagsでなんとかすれば良いレベル。



(21:22) Φ

2010年01月19日

やったこと

  • 同じスクリプトをGaucheでもmoshでも動かそうと試行錯誤
    • cond-expandを使うにはmoshではimport文が先に必要
    • とりあえず、Gaucheで動かしたい時には最初のimportをコメントアウト、な方式で行きます
  • 途中で2つの大きな壁
    • moshをSnow Leopardで動かす →前編参照
    • c-wrapperをSnow Leopardで動かす →c-wrapperは32bitでならビルドする方法が見つかった。後述。
  • 小さな壁
    • ncurseswが文字化け → LC_ALL の値が環境依存?とりあえず6を0にしたらMacでは直ったっぽい
続きを読む

(23:37) Φ

2009年09月12日

【C.M.ビショップ「パターン認識と機械学習(PRML)」読書会の情報はこちら

入出力に複素数を与えても行けるという話をどこかで読んだので、先日実装したニューラルネットワークに放り込んで試してみたら本当に行けたの巻。

1) 入力:実数×2、出力:複素数×1

(x, y) を与えて x+yi を返す関数の学習。

(define nn (make-neural-network 0.04 tanh identity 2 8 1))
(dotimes (i 3000)
  ([nn'learn] '(0 0) '(0))
  ([nn'learn] '(1 0) '(1))
  ([nn'learn] '(1 1) '(1+i))
  ([nn'learn] '(0 1) '(0+i))
  ([nn'learn] '(-1 1) '(-1+i))
  ([nn'learn] '(-1 0) '(-1))
  ([nn'learn] '(-1 -1) '(-1-i))
  ([nn'learn] '(0 -1) '(0-i))
  ([nn'learn] '(1 -1) '(1-i)))

2) 入力:複素数x1、出力:複素数x1

x+yi を与えて -y+xi を返す(90度回転!)関数

(define nn (make-neural-network 0.04 tanh identity 1 5 1))
(dotimes (i 1000)
  (for-each (lambda (ab) ([nn'learn] (list (car ab)) (list (cadr ab))))
			'((1    0+i)
			  (1+i  -1+i)
			  (0+i  -1)
			  (-1+i -1-i)
			  (-1   0-i)
			  (-1-i 1-i)
			  (0-i  1)
			  (1-i  1+i)
			  (0 0)) ))

45度回転

(define nn (make-neural-network 0.04 tanh identity 1 5 1))
(dotimes (i 1000)
  (for-each (lambda (th) ([nn'learn] (list (make-polar 1.0 th))
                                     (list (make-polar 1.0 (+ th pi/4)))))
            (map (cut * <> pi/180) (iota 12 0 30))))


githubにコード一式を置いてます。



(00:52) Φ

2009年09月06日

【C.M.ビショップ「パターン認識と機械学習(PRML)」読書会の情報はこちら

以前Rを参考にして書いた、Gaucheで行列演算を記述するためのオレオレライブラリを用いて実装したらやはり遅かったので、S式でグラフを組み上げてみたら百倍単位で速くなったとかそういう話。

続きを読む

(00:47) Φ

2009年08月23日

未来の自分のために、今日Schemeを書いててはまった事をメモっておきます。(srfi-1 の iota 関数的な例に書き換えてあります)

与えられた n に対し、リスト (0 1 ... n-1) を返す関数を named let で書くなら例えば

(define (foo n)
  (let loop ((i (- n 1)) (res '()))
    (if (< i 0) res
        (loop (- i 1) (cons i res)))))

srfi-1のiota関数はオプショナルパラメータでstart,stepを指定できるので、これは簡略版ということで。

(foo 1) => (0)

(foo 2) => (0 1)

(foo 3) => (0 1 2)

(foo 4) => (0 1 2 3)

(foo 5) => (0 1 2 3 4)

(foo 6) => (0 1 2 3 4 5)

...

逆順に積んで行って最後にreverseしても当然同じ結果です:

(define (bar n)
  (let loop ((i 0) (res '()))
    (if (= i n) (reverse res)
        (loop (+ i 1) (cons i res)))))

(bar 1) => (0)

(bar 2) => (0 1)

(bar 3) => (0 1 2)

(bar 4) => (0 1 2 3)

(bar 5) => (0 1 2 3 4)

(bar 6) => (0 1 2 3 4 5)

...

reverse! の方が速いかな?とか思ったりして

(define (bar! n)
  (let loop ((i 0) (res '()))
    (if (= i n) (reverse! res)
        (loop (+ i 1) (cons i res)))))

と書いてもまあ同じ結果が得られます。

(bar! 1) => (0)

(bar! 2) => (0 1)

(bar! 3) => (0 1 2)

(bar! 4) => (0 1 2 3)

(bar! 5) => (0 1 2 3 4)

(bar! 6) => (0 1 2 3 4 5)

...

例えば、(0 1 2 ... n-1) ではなく、先頭に 'A を付けた (A 0 1 2 ... n-1) のようなリストを(何らかの理由で)得たいとします。

(define (baz! n)
  (let loop ((i 0) (res '(A)))
    (if (= i n) (reverse! res)
        (loop (+ i 1) (cons i res)))))

と書いても同じになりそうなものなのですが、

(baz! 1) => (A 0)

(baz! 2) => (0 A 0 1)

(baz! 3) => (1 0 A 0 1 2)

(baz! 4) => (2 1 0 A 0 1 2 3)

(baz! 5) => (3 2 1 0 A 0 1 2 3 4)

(baz! 6) => (4 3 2 1 0 A 0 1 2 3 4 5)

...

のような結果に。

reverse! が let loop 環境のresを破壊し、baz!を再度呼び出した時にも(初期化されず)そのままなのが原因です。これはSchemeの仕様としては仕方のないことでしょうかね。ですが、それならその前のbar!もおかしくなっても良い気が…baz!との違いはresの初期値だけなので…

(ちなみにmit-schemeとかchickenとかでやってみたら同様の結果が出ました)

続きを読む

(22:58) Φ

2009年08月22日

こないだPRMLのコード書いてて発見した浮動小数点演算関連のバグが直ってた件。
shiroさんどうもありがとうございます (Mahalo nui loa!)。
// Changelog
// たぶんreproduceableはreproducible
2009-08-21 Shiro Kawai <shiro@acm.org>
  • src/number.c (MAX_EXPONENT): Changed to 325, since the least absolute value of denormalized number (expt 2.0 -1024) would be printed to 5.0e-324, so we do need to handle exponent -324 to keep read/write invariance. (iexpt10): handle cases where e is larger than pre-computed table size. It can happen in legitimate input, although rarely.

  • src/vm.c (Scm_VMFlushFPStack): Fixed a bug that forgot to scan ARGP of in-stack continuation when flonum registers are flushed. (Thanks to naoya_t for finding and providing reproduceable test case.)
Gauche:Bugsにレポートした再現コードが test/number.scm に入ってた!!
PRML読んでてよかったw

【PR】次回PRML読書会は8/29開催!5章前半を読みます【ML】
http://atnd.org/events/1279

(15:43) Φ