ctypes入門してみた。
ctypesって?
pythonのFFI用のモジュールらしい。
pythonの枠からはみ出た関数をpythonから呼び出すための接触面といった感じのもの.
ドキュメントを見て、動くコードを書いてみた。
やってみたのは以下のこと
- floatの配列を作ってこれをqsort
- python側で構造体を作成してこれをqsort
qsortは関数ポインタを使っているし、だいたいの機能を網羅していると思う。((実際には、bitfieldの利用やunionなど使っていない機能はあるけれど、まぁ必要十分だと思う)
実際のコード
最初、qsortに渡す関数の戻り値をintにしていなくてハマったのはないしょ。
floatの配列をqsort
python側で作成した構造体(Point)をqsort
ldconfigとかpkgconfigなどのコマンドも久しぶりに使ってみてだいぶオプションの内容など忘れている。
seq使うのむずかし。(Seq.skipおそい)
まとめ
- seq式で遊ぼうとした
- combinationsとか生成すれば良さそう。
- 全部seqにすると遅い。
seq式で遊ぼうとした
seq式は値の列を返す計算を返してくれる。
> seq {for x in [1..10] do yield x*x} |> Seq.toList;; val it : int list = [1; 4; 9; 16; 25; 36; 49; 64; 81; 100]
- 要素を結果として与えてくれるyield
- 列をconcatしてくれるyield!
の2つがある。
> seq {yield 1; yield 2; yield 3};; val it : seq<int> = seq [1; 2; 3] > seq {yield! [1;2;3]; yield 4; yield! [5]};; val it : seq<int> = seq [1; 2; 3; 4; ...]
全部seqにすると遅い。
[1..20]までの列から8個取る組み合わせを列挙してみる
$ time ./permtations.exe ...]./permtations.exe 39.82s user 0.81s system 176% cpu 23.075 total
すっごい遅い。
profilerを使ってみる。
monoなので以下のような感じでprofiler使う。
$ mono --profile=default:stat permtations.exe prof counts: total/unmanaged: 2383/1115 1014 42.57 % mono() 349 14.65 % Microsoft.FSharp.Collections.SeqModule/Skip@1428<int>:GenerateNext (System.Collections.Generic.IEnumerable`1<int>&) 267 11.21 % Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase`1<int>:MoveNextImpl () 109 4.58 % Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase`1<int>:System-Collections-IEnumerator-MoveNext () 69 2.90 % (wrapper alloc) object:Alloc (intptr) 60 2.52 % Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase`1<int>:System-Collections-Generic-IEnumerator`1-get_Current () 53 2.23 % Microsoft.FSharp.Core.Operators/OperatorIntrinsics/BaseRangeEnumerator`1<int>:System-Collections-IEnumerator-MoveNext () 43 1.81 % Microsoft.FSharp.Collections.PrivateListHelpers/ListEnumerator`1<int>:System-Collections-IEnumerator-MoveNext () 34 1.43 % (wrapper managed-to-native) object:__icall_wrapper_mono_object_new_fast (intptr) 34 1.43 % Microsoft.FSharp.Collections.SeqModule/Skip@1428<int>:Close ()
Seq.skipが遅い。Seq.skipが遅い。
Seq.skip
Seq.skipはdropみたいなもの。N個飛ばした列を返す
> seq {yield 1; yield 2} |> Seq.skip 1;; val it : seq<int> = seq [2] > [1;2;3] |> List.tail;; val it : int list = [2; 3]
Seq.skip使っている箇所をlistに置き換えてみる。
$ time ./permtations2.exe ...]./permtations2.exe 2.63s user 0.11s system 173% cpu 1.575 total
早くなった。
ちなみに
pythonのitertolsを使った場合はこれくらいの速度([:20]はf#の出力に大体合わせるため)
$ time python -c "import itertools as i; print [x for x in i.combinations(range(20),8)][:20]" [~/sandbox/fsharp] [(0, 1, 2, 3, 4, 5, 6, 7), (0, 1, 2, 3, 4, 5, 6, 8), (0, 1, 2, 3, 4, 5, 6, 9), (0, 1, 2, 3, 4, 5, 6, 10), (0, 1, 2, 3, 4, 5, 6, 11), (0, 1, 2, 3, 4, 5, 6, 12), (0, 1, 2, 3, 4, 5, 6, 13), (0, 1, 2, 3, 4, 5, 6, 14), (0, 1, 2, 3, 4, 5, 6, 15), (0, 1, 2, 3, 4, 5, 6, 16), (0, 1, 2, 3, 4, 5, 6, 17), (0, 1, 2, 3, 4, 5, 6, 18), (0, 1, 2, 3, 4, 5, 6, 19), (0, 1, 2, 3, 4, 5, 7, 8), (0, 1, 2, 3, 4, 5, 7, 9), (0, 1, 2, 3, 4, 5, 7, 10), (0, 1, 2, 3, 4, 5, 7, 11), (0, 1, 2, 3, 4, 5, 7, 12), (0, 1, 2, 3, 4, 5, 7, 13), (0, 1, 2, 3, 4, 5, 7, 14)] python -c 0.07s user 0.01s system 93% cpu 0.086 total
cat
- EntryPointというattributeをつけるとコマンドライン引数を受け取る関数として扱われる
- openでmodule(namespace)のopen
- (System.IO.File.Readlinesは環境が古くて無かったっぽい)
- オーバーロードされたメソッドを利用する時には型注釈必要。
open System let lines (name:string) = seq { use sr = new IO.StreamReader(name) while not sr.EndOfStream do yield sr.ReadLine() } let cat (name:string) = lines name |> Seq.iter (fun (x:string) -> Console.WriteLine x) [<EntryPoint>] let main (args:string[]) = args |> Seq.iter cat 0
$ fsc.exe cat.fs $ cat.exe cat.fs
f#の環境構築(ubuntu)
作業
- f#のインストール
- emacsの環境作成(fsharp-mode)
- F#を利用してみる
f#のインストール
大体はこのURLのページのとおりに作成。
sudo aptitude install mono-devel mono-tools-devel libmono-winforms2.0-cil libmono-system-runtime2.0-cil pwd # /var/project wget http://download.microsoft.com/download/6/B/6/6B6BFB83-3D3A-467C-8080-01F7A953A37F/fsharp.zip unzip fsharp.zip cd FSharp-2.0.0.0/bin echo "export MONO_PATH=`pwd`:\$MONO_PATH" >> ~/.zshrc echo "export PATH=`pwd`:\$PATH" >> ~/.zshrc chmod u+x *.exe
インストールするF#のversionが古かったので、新しい方を利用することにした。
ダウンロードしたzipファイルを展開したディレクトリのREADMEに従う必要は無かった。
emacsの環境作成(fsharp-mode)
以下のリンクから取得する。((sourceforgeからのダウンロードは既に面倒な作業になってきている。(githubなどの方が楽)))
http://sourceforge.net/projects/fsharp-mode/files/latest/download
unzip fsharp-0.3.zip
mv fsharp fsharp-mode
editor fsharp-mode/init.el
fsharp-modeを有効にするための設定を追加(init.el)
;; if current-directory is not found. use `default-directory' (add-to-list 'load-path (current-directory)) (add-to-list 'auto-mode-alist '("\\.fs[iylx]?$" . fsharp-mode)) (autoload 'fsharp-mode "fsharp" "Major mode for editing F# code." t) (autoload 'run-fsharp "inf-fsharp" "Run an inferior F# process." t)
これでemacsの環境は整った。
inverse fizzbuzz
まるであれな感じの汚いこーど。
どう考えても途中でしくじった感がある。
githubにパッケージ挙げる時のディレクトリ構成
悩まなくても良いようにメモ。
作りたいパッケージ(パッケージ名: foo)
ファイル構成(置き場所)
. ├── README.txt ├── docs ├── foo │ ├── __init__.py │ ├── locale │ └── tests ├── setup.cfg ├── setup.py └── tox.ini
シンプルなもの
. ├── README.txt ├── foo │ ├── __init__.py │ └── tests ├── setup.cfg └── setup.py
- 普通にsetup.pyを書く
- setup.pyにextra_requiersを書く(docs,testing)
- setup.cfgにextra_requiresのためのaliasを書く
setup.py,setup.cfg, extra_require (not using pip)
e.g. colander
setup.py
##... snip testing_extras = ['nose', 'coverage'] docs_extras = ['Sphinx'] setup(name='colander', version='0.9.8', ## ... snip install_requires = requires, test_suite="colander", extras_require = { 'testing':testing_extras, 'docs':docs_extras, }, )
setup.cfg
## ... snip [aliases] dev = develop easy_install colander[testing] docs = develop easy_install colander[docs] ## .. snip
how to use
$ python setup.py dev # install package include testing requirements $ python setup.py docs # instapp package for documantation