RTX1200初期設定

自宅用にルータRTX1200を買ってきた 1. 中古で2万円弱だった. GUIで設定できるところはGUIで設定し,残りをCUIで設定した 2. 具体的には,PPPoEとフィルタをGUIで設定し,VPNとDDNSをCUIで設定した. 忘れないように,設定内容をまとめておく. なお,工場出荷状態への初期化は, 前面のmicroSD,USBおよびDOWNLOADのボタンをすべて押下しながら, 電源を入れることで行われる. 工場出荷状態では,LAN1ポートが192.168.100.1/24で初期化され,DHCPが有効になっているので, telnetですぐに接続できる. telnetの他にも,コンソールやhttpで接続できるので,適当に接続する. > show config ess=**:**:**:**:**:** MAC-Address=**:**:**:**:**:** login password encrypted * administrator password encrypted * # デフォルトゲートウェイ ip route default gateway pp 1 # LAN1ポートのIPアドレス ip lan1 address 192.168.100.1/24 # ARPの代理応答 ip lan1 proxyarp on # フィルタ ip lan1 secure filter in 100000 ... # PPPoE pp select 1 description pp PRV/PPPoE/0:*** pp keepalive interval 30 retry-interval=30 count=12 pp always-on on # LAN2ポートを使う pppoe use lan2 pppoe auto disconnect off pp auth accept pap chap # PPPoE接続時のID,パスワード pp auth myname ****@**** **** ppp lcp mru on 1454 ppp ipcp ipaddress on ppp ipcp msext on ppp ccp type none ip pp secure filter in 200003 ....

December 17, 2016

Ansibleのメモ

最近,Ansibleを使うようになった.ちょうどAnsibleの解説本「Ansible完全読本」が,Kindle Unlimitedで公開されていたので読んでみた.インストール方法や使い方は省いて,今後ハマりそうな点だけをメモしておく. 設定ファイルは,YAML形式に準拠して記述する. 配列や連想配列を扱う際は,基本的に一行に一要素を記述する. 配列は- ,連想配列はkey: を接頭辞として,要素をその後ろに続けて書く. 空白文字が入っていないと文法エラーになるので,注意する. 例外として,=を使って,連想配列を定義できるが,文法がバラバラになってしまうので,使わない方が良い. 設定ファイルを編集し,その後デーモンを再起動したい場合は,Handlerを使う. Hanlderによって,デーモンが複数回再起動することを防げる. サーバに依存する値を設定ファイルに埋め込みたい場合は,Jinja2モジュールを利用する. このとき,その設定ファイルの名前に,nginx.conf.j2のように,.j2を付与する. 設定ファイルがAnsibleによって編集されたことを明示するために,設定ファイルの先頭にansible_managedをコメントとして,追加しておくと良い. これは,日付などに置換される. 設定ファイルを編集する際に,backup: trueとしておくと,バックアップファイルを作成できる. また,validate: ...としておくと,設定ファイルの文法エラーによるデーモンの起動失敗を未然に防げる. サーバの一覧は,Inventoryファイルとして管理する. Inventoryファイルには,静的Inventoryファイルと動的Inventoryファイルがあり, ファイルに実行権限が付与されているか否かによって解釈が決定する. 静的Inventoryファイルには,ホスト名をテキストで列挙する. 一方,動的Inventoryファイルはスクリプトとして記述し,実行時にホスト名を決定する. また,タスクによって,柔軟にInventoryを操作することもできる. これは,OpenStackのAPIを叩いて新規VMを作成,その後VMを初期化したい場合などに有用である. ansible-playbookコマンドは,Playbookに明示されたタスクに先立って,暗黙的にsetupタスクを実行する. setupタスクは,OSの種類やホスト名などFactと呼ばれるサーバの情報する. 対象サーバがOpenStackやAWS EC2によって管理されている場合には,Factに付加情報を追加できる. Version2以降では,Taskの一層外側にBlockという概念があり, Blockごとにtry,catchおよびfinaly処理のような例外処理を記述できる. さらに,Blockの外側にRoleという概念がある. 基本的には,サービスごとに独立してRoleを管理するのが良い. また,Roleを集めたAnsible Galaxyと呼ばれるリポジトリがある. 共通する処理を繰り返す場合は,with_itemsなどのwith*命令を利用する. ただ,with*命令は,種類が多いので,その都度検索するのが良いかもしれない. 1つサーバでだけ実行したい処理やローカル実行したい処理には,例外的に,run_onceや local_actionを利用する. SSHの同時接続数は,forksオプションによって設定する(デフォルトは5). Playbookは,step実行や特定tas実行を組み合わせて開発する. もし,既存のモジュールで不十分であれば,Pythonによってモジュールを自作できる. ディレクトリ構造 サービスごとにRoleを作っていき,site.ymlから呼び出すという構成が良い. ディレクトリ構造が複雑になるので,テンプレートをダウンロードすると良いかもしれない. site.yml # Playbookファイル hosts # Inventoryファイル roles/ role_name/ # Role名 tasks/ main.yml # Roleを構成するタスク handlers/ main.yml # ハンドラ vars/ main.yml # 上書きしない変数 defaults/ main.yml # 上書きする変数 meta/ main....

December 12, 2016

NUMAポリシー

NUMA環境で,スレッドやメモリの配置を明示的に指示する方法を調べたので,メモしておく. 1つの筐体に複数のマルチコアCPUを搭載する環境では,メモリはCPUごとに接続される. このような環境では, バスを介して直接つながったメモリ(ローカルメモリ)とCPUの間で,高速にデータを転送できる. 一方,直接つながっていないメモリ(リモートメモリ)にデータを転送するためには, QPI(QuickPath Interconnect)などのインタコネクトを介して, 他のCPUソケットを経由する必要がある. このようにメモリアクセスの仕組みが複数存在する環境は, NUMA(Nun Uniform Memory Access)と呼ばれる. NUMA環境で,マルチスレッドプログラムをチューイングするためには, スレッドをどのコアに割り当てるか,データをどのメモリに配置するかが重要になる. これらの制御は,numactlコマンドあるいはlibnumaライブラリによって実現できる. numactlによる制御 ソースコードを修正できない状況(あるいは面倒くさい状況)では, numactlコマンドを使って,アフィニティを設定する. --cpubind=<nodemask>オプションでスレッドをどのノードで実行するか指示し, --membind=<nodemask>オプションでデータをどのノードのメモリに配置するかを指示する. <nodemask>には,--membind=0,1のようにノード番号をカンマ区切りで記述する. 他にも, 優先してメモリを割り当てるノードを指示する--preferred=<nodenumber>オプションや 複数のノードにインタリーブでメモリを割り当てる--interleave=<nodemask>オプションがある. ノード番号などハードウェア情報は,--hardwareオプションで確認できる. また,プロセスに割り当てられたポリシーを確認するには,--showオプションを使う. # スレッドをノード0,データをノード0および1に配置 $ numactl --cpubind=0 --membind=0,1 ./a.out # メモリをインタリーブに配置し,numactl --showで確認 $ numactl --interleave=all numactl --show libnumaによる制御 ソースコードを修正できる状況では,libnumaを使う. numactlはプログラム全体のメモリ割付けを制御するが, libnumaは個々のメモリ領域を個別に制御する. libnumaを利用するには,コードにnuma.hをヘッダを追加し, 共有ライブラリをリンクする(-lnuma). ノード番号の集合<nodemask>は,nodemask_t型変数に格納する. メモリの確保では,どのようにメモリを確保するのかに従って, 適切なnuma_alloc_*ファミリの関数を利用する. メモリの解放には,共通してnuma_free関数を利用する. さらに,numa_run_on_nodeあるいはnuma_run_on_node_mask関数を使うことで, スレッドをどのノードで実行するかを明示できる. nodemask_t m; // ノード番号の集合を格納する変数m nodemask_zero(&m); // mを初期化 nodemask_set(&m, 2); // ノード番号2を有効に nodemask_clr(&m, 2); // ノード番号2を無効に nodemask_all_nodes(&m); // すべてのノードを有効に nodemask_no_nodes(&m); // 空集合に nodemask_isset(&m, 2); // ノード番号2がセットされていれば真 size_t s = 4 * 1024; // データサイズ4KB // 2番目のノードに確保 void *mem1 = numa_alloc_onnode(s, 2); // すべてのノードにインタリーブに確保 void *mem2 = numa_alloc_interleaaved(s); // mで示されたノードにインタリーブに確保 void *mem3 = numa_alloc_interleaaved_subset(s, m); // ローカルメモリに確保 void *mem4 = numa_alloc_local(s); // メモリ解放 numa_free(mem1,s); numa_free(mem2,s); numa_free(mem3,s); numa_free(mem4,s); // 現在のスレッドをノード1で実行 numa_run_on_node(1); // 現在のスレッドをmに含まれるどこかのノードで実行 nodemask_zero(&m); nodemask_set(&m,1); nodemask_set(&m,2); numa_run_on_node_mask(m); OpenMPによる制御 OpenMPを使ってマルチスレッドを実現している場合には,環境変数によってアフィニティを制御する. 制御方法は,コンパイラごとに異なり,例えば, PGIコンパイラであればMP_BINDおよびMP_BLISTを設定する....

October 7, 2016

移流方程式の数値解析

簡単のため1次元の波で考える 時刻\(t\)における座標 \(x\) の値を \(f(x-ut)\) とする 例えば,正弦波が速度\(u\)でx軸正方向に進むなら,\(f(x-ut) = sin(x-ut)\) この時,\(\frac{\partial f}{\partial t} + u \frac{\partial f}{\partial x} =0 \)が成り立つ.これが移流方程式 1次風上差分法 直線で近似する 数値解析なので,\(x\)は\(\dots,x_{i-1},x_i,x_{i+1},\dots\)のように離散的 \(x = x_i\)における\(f\)の近似を\(F_i^n(x)\)とする この手法は直線で近似するので,\(F_i^n(x)=a(x-x_i) + f_i^n, a = \frac{f_i^n - f_{i-1}^n}{\Delta x}\) ただし,\(f_i^n\)は\(x = x_i\)において時間ステップを\(n\)回進めた時の値 1時間ステップあたり時間は\(\Delta t\)だけ進む 時間ステップを進めると,$f_i^{n+1} = F_i^n(x_i-u\Delta t) = a(-u \Delta t) + f_i^n= - \frac{u \Delta t}{\Delta x}(f_i^n - f_{i-1}^n) + f_i^n$ プログラムでは,$K=u \frac{\Delta t}{\Delta x}$として以下を繰り返すだけ 図は,矩形波を与えたもの 風下もある for(i=1; i<99; i++) f_new[i] = -K * (f[i]-f[i-1]) + f[i]; for(i=1; i<99; i++) f[i] = f_new[i]; Lax Wendroff法 二次関数で近似する $F_i^n(x) = a(x-x_i)^2 + b(x-x_i) + c$で近似する $a,b,c$3つの定数が必要なので,$x$に適当に値を入れて, $F_i^n(x_{i-1}) = a \Delta x ^2 - b \Delta x + c = f_{i-1}^n$ $F_i^n(x_{i}) = c = f_{i-1}^n$ $F_i^n(x_{i+1}) = a \Delta x ^2 + b \Delta x + c = f_{i+1}^n$ ただし,$x_{i+1} - x_{i} = x_{i} - x_{i-1}=\Delta x$ これを解いて, $$ F_{i}^n(x) = a(x-x_i)^2 + b(x-x_i) + f_i^n, \\ a = \frac{f_{i+1}^n - 2f_{i}^n + f_{i-1}^n}{2\Delta x^2}, b = \frac{f_{i+1}^n - f_{i-1}^n}{2\Delta x} $$ 時間ステップを進めると, $$ f_i^{n+1} = F_i^n(x_i-u\Delta t) = f_i^n - \frac{u\Delta t}{2 \Delta x}(f_{i+1}^n - f_{i-1}^n) + \frac{(u\Delta t)^2}{2 \Delta x ^2}(f_{i+1}^n -2 f_i^n- f_{i-1}^n) $$ プログラムでは,風上差分と同様に$K=u \frac{\Delta t}{\Delta x}$として以下を繰り返すだけ for(i=1; i<99; i++) f_new[i] = f[i] - K*K*(f[i+1]-f[i-1])/2....

April 26, 2016

順伝播型ニューラルネットワークでMNISTの手書き数字認識

深層学習を勉強しようと思って,深層学習の本[1]を読んだ. さらに,MNISTデータセット[2]を使って,手書き数字認識プログラムを作った MNISTは,分類器を作る時のHello worldみたいなの 一番簡単な順伝播型ニューラルネットワーク(FFNN)を使う(他はよくわからん) 1章から4章あたりまで読めば実装に必要な情報が揃う 入力層,中間層,出力層の3層だけで構成 行列計算,データセットは既存のパッケージを使う 画像認識プログラムそれ自体は自分で実装する(caffe,TensorFlow等を使わない) この界隈ではPythonがスタンダードらしいので,それに従う ただ,Jupyter(IPython)は準備がめんどくさかったので保留 ソースコードは全部まとめて[3]に置いておく 順伝播型ニューラルネットワークの構築 構造が簡単な順伝播型ニューラルネットワーク(FFNN)を採用 多層パーセプトロンともいう 入力データを,多クラスに分類させる ネットワークは図のように構築する \(L\): 層の数.入力層,中間層,出力層の3層があればよい \(f^{(l)}(u)\): 第\(l\)層における活性化関数 \(f^{(l)}(u) = \frac{1}{1+e^{-u}} \): 出力層以外なら,ロジスティック関数を使う \(u_i^{(l)}\): 第\(l\)層の\(i\)番目のユニットにおける入力 \(z_{i}^{(l)}=f^{(l)}(u_i^{(l)})\): 第\(l\)層の\(i\)番目のユニットにおける出力 \(\mathbf{W}^{(l)}\): 第\(l-1\)層と第\(l\)層の間の重みを要素にもつ行列 各層の入出力を列ベクトルで表す \(\mathbf{u^{(l)}} = [u_0^{(l)} u_1^{(l)} \dots u_i^{(l)} \dots]^{T}\): 第\(l\)層のユニットへの入力を表す列ベクトル \(\mathbf{z^{(l)}} = [z_0^{(l)} z_1^{(l)} \dots z_i^{(l)} \dots]^{T}\): 第\(l\)層のユニットの出力を表す列ベクトル この時,順方向(入力層->中間層->出力層)の伝播は以下のように行列演算で書ける 入力を列ベクトル\(\mathbf{x}\)とすると,\(\mathbf{z}^{(0)} = \mathbf{x}\) 出力を列ベクトル\(\mathbf{y}\)とすると,\(\mathbf{y} = \mathbf{z}^{(L-1)}\) \(\mathbf{u^{(l+1)}} = \mathbf{W}^{(l+1)} \mathbf{z}^{(l)} + \mathbf{b}^{(l+1)}\) \(\mathbf{z^{(l+1)}} = f^{(l+1)}(\mathbf{u^{(l+1)}})\) ただし,\(\mathbf{b}^{(l)}\)は第\(l\)層のバイアス 分類するだけならここで終わり.\(\mathbf{y}\)が分類結果. 学習段階であれば,次に逆方向(出力層->中間層->入力層)の伝播を行う. \(\mathbf{d}\): \(\mathbf{x}\)の正解データ \(\mathbf{\Delta}^{(L-1)} = \mathbf{z}^{(L-1)} - \mathbf{d}\) \(\mathbf{\Delta}^{(l)} = f^{(l)’} ( \mathbf{u^{(l)}} ) \odot \mathbf{W}^{(l+1)T} \mathbf{\Delta}^{(l+1)} \) \(\odot\): 行列の要素同士の積 \(f^{(l)’}(u)\): \(f^{(l)}(u)\)の導関数 \(\mathbf{\Delta}^{(l)}\)が求まれば,それをもとに重みとバイアスを更新する....

April 24, 2016

Macbook Air(13-inch, Mid2012)にdebian 8.0 jessieをインストール

Macbook Air(13-inch, Mid2012)にdebian 8.0 jessieをインストールするメモ. SDカードにインストール まず,インストール対象のSDカード以外に適当なメディア(/dev/diskX )を用意し, /dev/diskXにdebian 8.0 jessieのLive install imageを焼く. 焼けたら,commandキーを押しながら再起動して,/dev/diskXからdebianを起動する. $ diskutil unmount /dev/diskX $ dd if=debian-live-8.3.0-amd64-lxde-desktop.iso of=/dev/diskX 次に,SDカード(/dev/diskY)に2つのパーティションを作る. パーティション方式はGUIDパーティションテーブル(GPT)を使う. 1つ目のパーティションをFAT32,2つ目のパーティションをext4等でフォーマットする. $ diskutil list (略) /dev/diskY #: TYPE NAME SIZE IDENTIFIER 0: GUID_partition_scheme *7.8 GB diskY 1: Microsoft Basic Data EFI 1.0 GB diskYs1 2: Microsoft Basic Data 6.7 GB diskYs2 フォーマットが終わり次第,1つめのパーティション(diskYs1)に,UEFIブートマネージャのrEFIndをインストールする. $ mount -t msdoc /dev/diskYs1 /Volumes/EFI $ ./refind-install --ownhfs /Volumes/EFI --alldrivers $ cp /Volumes/EFI/System/Library/CoreServices/refind_x64.efi \ /Volumes/EFI/System/Library/CoreServices/boot....

March 15, 2016

2015年総括

明けましておめでとうございます. 今年もよろしくお願いします. 去年を出来事を簡単にまとめてみます. 研究 M1になった. 卒論や修論など明確な〆切がないので,あまり焦りやプレッシャーを感じず, のんびり過ごしていた. 研究内容を簡単に紹介すると,CPU向け逐次コードをGPU向けコードへ自動変換するというものである. 10月くらいまでは,出力すべきGPU向けコードをチューニングしていた. 以後,自動変換ブログラムの実装に取り掛かっている. B4の頃よりも発表や聴講の機会は増えた. 1/26-1/27 ACSI2015@つくば 2/20 卒論発表会@研究科 3/2-2/3 HPC148@別府 5/19-20 HPCS2015@東京 8/4-8/6 SWoPP2015@別府 9/18 GTCJapan2015@東京 12/16-12/17 HPC152@札幌 バイト 去年と同じ職場でアルバイトと外注の仕事をしていた. しゃちほこ 去年に引き続き,チームしゃちほこのライブやイベントに参加していた. 今年は多くのメンバーが卒業するので,活動がより活発になるかもしれない. 1/3 鯱詣@愛知県体育館:確かプロレスをイメージしたポスタと円形ステージだった気がする.乙女英語verをお披露目. 3/28 『天才バカボン』発売記念フリーなイベント@札幌ファクトリー:ミルクス,たこ虹もいた.ライブ前にGTR(ラジオ)公開収録. 4/18 『天才バカボン』発売記念フリーなイベント@大阪城野外音楽堂:4月にも関わらず,きつい日差し.ぽんさんは足をけがしてて車いす.いけいけハリウッドを初披露. 5/9-5/10 幕張HOLLYWOOD@幕張メッセ:爆発の演出でビビる.鯱本を購入. 5/17 『天才バカボン』発売記念フリーなイベント@名古屋オアシス21:まだまだ新曲についていけない. 7/14 「鯱本」1万冊突破記念「行くぜ、しゃちサマ」トークイベント@梅田ブルク7:咲良さん,坂本さん,店長と編集の津田くん.案の定ふたりとも読んでない. 7/26 CBCラジオ夏祭り2015@名古屋久屋広場:アンセム推しすぎな気がする.Silent Sirenも見た. 8/28 しゃちサマ@蒲郡ラグーナテンボス:ほのかが永遠のトリニティーをカバー.終盤は花火が上がってた.しゃちほこーるが公開されたのもこの辺. 9/30 ホールツアー2015さきどりハロウィンパーティー@名古屋国際会議場:ぽんさんとなおちゃん以外の4人は色を変えて登場.魔法にかけられた設定. 10/17 ホールツアー2015さきどりハロウィンパーティー@長崎チトセピアホール:3人で運転を交代しつつ車で移動.コアなひとが多くて楽しい. 10/18 第61回名古屋まつり@名古屋久屋広場:長崎からそのまま移動.5曲くらいだったけど楽しい. 10/29 「ええじゃないか」発売を記念したイベント@梅田タワレコ:付き添い. 11/15 「ええじゃないか」特典会@ポートメッセ名古屋:秋本さん誕生日. 12/10 年末大感謝祭ソロライブ@名古屋ELL:ほのテルで銀河鉄道999をカバー.弱虫ペダル推しまくってた. アプガ 体力があるグループで,2時間くらいノンストップで歌とダンスで盛り上がる. 10/16 全国47都道府県ツアー@徳島club GRINDHOUSE:初めて見に行った. 11/29 ハイスパートRAVE FESTIVAL@京都FANJ:2時間ワントラックのノンストップライブ. バイク オイル,ブレーキフルード,スロットルワイヤを交換した. あとは,タイヤとグリップヒーターをなんとかしたい. 秋頃に大自二をとった....

January 3, 2016

省エネサーバを作ってみた

さくらVPSの1Gプランのインスタンスをウェブサーバやストレージとして動かしているが,いくつか不満なところがある. ストレージが自宅とVPSでバラバラ どうせ自宅でPCつけっぱなし そこで,自宅にサーバを置くことにした. 条件はありきたりだが,こんな感じ. PCIスロットあり PCIeは特に使わないが,あったらよい 静音(ファンレス,スピンレス) 安い(全部で上限4万) 省電力 SATA2つ以上 ちょっと調べてみて,DN2820FYKH(15,000円)というNUC(Next Unit of Computing)を使おうと思った. NUC本体に加えて,メモリとストレージだけ買ってくれば完成するので簡単だし, 値段,静音性,消費電力の条件を満たしている. 注意点は, メモリには1.35Vの省電力メモリ(DDR3L 1333/1600)を使うこと, 最大メモリ容量は8GBであること, ドライブは2.5インチであることくらい. あと,SATAのスロットは1つだけで,PCIeはひとつもないので拡張は全く出来ない. よく考えてみると拡張出来ないのは痛いから,多少高くつくが部品ごとバラバラに買うことにした. CentOS x86_64 サーバー構築・運用 - System House ACT 公式ブログや 静音化:SST-ML05Bケースに、玄人志向のACアダプタKRPW-AC120Wを載せる | Atom Fusion に同じマザーボードを使って構成した人がいるので参考にした. GA-J1900N-D3Vは少し古くてSATA 3.0がなくメモリの周波数もちょっと気になるが,PCIスロットがありNICが2つありということで,妥協した. 実際に動かしてみると,HDDのシーク音がうるさいのが気になった. 他のHDDと比べてもうるさいので,選択を間違ったかハズレを引いたんだろう. マザーボード GA-J1900N-D3V 13,000円 Mini ITX ATX電源 PCIスロットあり Mini PCI Expressスロットあり(PCIe 2.0相当) Celeron Quad-Core J1900(Bay Trail-D,2.0GHz,4コア,TDP 10W) DDR3/DDR3L-1333(PC3-10600) 2ソケット(最大8GB,1.5Vでも1.35Vでもどちらでもok(ここは日本語,英語マニュアル間で差があるもよう)) SATA 2.0(3Gbps)が2本 SATA 3.0(6Gbps)はなし GbEが2つ ケース SST-ML05B 6,000円 Mini ITX 2.0インチドライブを4台 3....

July 20, 2015

Codeforces Round 308 (Div.2), ARC040

ちょっと競技プロをやってみた. Codeforces #308 (Div.2) Codeforcesに初参加. 結局A-Eの5問中,Aしか解けなかった. Aは,実装するだけという感じだったので,そんなに時間がかからず解けた. Bは,ヒストグラムを作れば解けたと思うが,それに気づくのが遅かった. Cは,4番目のpretestで失敗. D,Eは手を付けてない. それと,pretestに失敗した時は,「My contest submissions」から テストケースの詳細が見れるのを知らなかった. ARC040 4問中3問解けた. 問題DはDPかなんかで計算量下げるんだろうなと思ったが, 全探索以外の手法が思いつかず終了. 精進します.

June 15, 2015

5五将棋 AI制作のメモ

本将棋のサブセットである「5五将棋」のAIを ちょろちょろ書いている, 気づいたことをメモしておく. データ構造 それぞれの駒をビットボードで管理している. 例えば先手の歩が7番目の位置に存在すれば,bitboard[B_PAWN] = 0x40 のように表す. 飛車および角の効きはAVX2の_pext_u32命令を使い導出する[5]. 探索方針 基本はアルファベータ法で探索する. それに加えて,合法手をソーティングしつつ,反復深化させる. また,同一局面が現れた場合は,置換表を用いてalpha-betaのウィンドウ幅を狭める. Null-Window(PVS)探索も試してみたが,対して速くならなかった.むしろ遅い場合もある. 多分ソーティング方法が悪い. 評価関数 単純に駒の損得だけで評価している. 改善が必須. USI(Universal Shogi Interface)プロトコル 将棋GUIソフト[8]とAIを接続するプロトコルの1つがUSIである[6,7]. AIは,GUIソフトから局面や持ち時間を受け取り,決定した指し手を返す. とりあえず対応させた. OpenMPによる並列化 探索はOpenMPを使って並列化している. 与えられた局面の合法手をそれぞれ並列に探索する. 出来るだけ静的にリンクしたいので,ちょっと調べてみた. visual c++ 構成プロパティ - C/C++ - 言語 - OpenMPのサポートを「はい」にする 構成プロパティ - C/C++ - コード生成 - ランタイムライブラリを「マルチスレッド(/MT)」にする VCOMP{90,100,110,120}.dllに依存する VCOMP{90,100,110,120}.dllは,/MTを設定しても動的にリンクされるため, どこかで配布されているものを使ってみようかな[1,2]. gcc libcompに依存するが,静的リンクする方法はあるみたい[4]. intel compiler libiomp5m.libを静的リンクすることができるらしい[2]. 静的リンクは非推奨らしいが,-openmp-link staticオプションを付けると良いみたい(icpc -openmp -openmp-link static hello.cpp)[3]. 参考 [1] Stack Overflow, Is there a way to load in omp....

May 29, 2015

どうぶつしょうぎの完全解析

(7/10追記) 完全解析の結果を利用するAIをdobutsu-shogi.jar(17MB)に置いておきます.対戦してみてください. 今更な感じですが,どうぶつしょうぎの完全解析をしてみました. やり方はすでに公開されてますので,不明点はそちらを参考にしてください(「どうぶつしょうぎの完全解析」, 田中哲朗). 私の実装もそちらを参考にしています. 解析のゴールは,後手の場合は78手で確実に勝ち,先手の場合は出来るだけ負けにくい手(負けまでの手数が最も長い手)を指すAIを完成させることです. 以下2つのステップにより,完全解析を目指します. 1つ目は,初期局面から開始し,ありうる全ての局面を展開することです. やり方は単純で,ある局面の合法手を全て展開していくだけです. 計算時間は数十分程度ですか,メモリを多く使います. そこで,駒を左右入れ替えて配置し直しても同じ局面と見なし(全ての駒の動きは左右対称であるから),局面数を減らします. 解析結果all-stateは,今後の利用のためソーティングしておくと良いです. all-stateは,1局面64bit x 246,803,167 = 1.9 GBくらいになります. コードはこちら. // // q: 未解析局面のキュー,初期値は初期局面のみが格納されたキュー // h: 解析済み局面のマップ,初期値は空マップ // all_state: 解析済み局面のベクタ,初期値は空ベクタ // while(!q.empty()) { if (i>=MAX_BOARD_NUM) { break; } b = q.front(); q.pop_front(); iter = h.find(b); if (iter == h.end()) { all_state.push_back(b); h.insert(b); i++; // 終わった盤面からは解析しない if (!is_win_state(b) && !is_lose_state(b)) { next_boards.clear(); get_next_board(next_boards, b); n = next_boards.size(); for (j=0; j<n; j++) { // ちゃんと正規化して,手番を合わせて保存 b = get_reverse(next_boards[j]); b = regulate(b); q....

May 28, 2015

4clojureのススメ

clojureの学習サイトの1つに,4clojureがある. 難易度がElementary,Easy,Medium,Hardと分かれているので, これから始める人にちょうど良いかなと. 無限遅延シーケンスとかはclojure独自なものだし,普段のコーディングで あんまり意識しないので面白い. とりあえず先ほど全完してきた.

May 16, 2015

2014年総括

最近記事を書いてないからちょっとまとめて書いておく. 覚えている限りで書いてるから忘れてるものもたくさんありそう. こうみるとただただ遊んでるだけの時間が長かった. しゃちほこ 3/29 ZEPP FINAL! 2014@zeppなんば 4/19 ZEPP FINAL! 2014@zepp名古屋 4/26 いいくらし発売記念Free Event Tour@京都新風館 8/28 しゃちサマ@武道館 途中新幹線使っちゃったような ほのかがとんでた,たんま 11/02 カラオケワンダーランドツアー@浜松アクトシティホール 近鉄,名鉄,JRを組み合わせて行った さわやか 11/24 シャンプーハット発売記念FreeなLive@千里セルシー 握手を2回 11/30 カラオケワンダーランドツアー@大阪オリックス劇場 車で連れてってもらった 3階席 いいじゃないの〜,出会っちゃったやで−(ほのか),アンパンマン,スベッカム(ゆずき) 研究室 無事希望の研究室へ. 1月中にポスタ提出,2月に卒論発表.これから忙しくなるぞ. 院試 あれ,まだ過去問作ってないような… バイク 院試前後で,免許を取得. 近くのバイク屋に探してもらってたが結局別のところで買うことになった. メール,電話でかなり親身に探してくれた. lisp これに関してはあんまり進展してないような… ガンバ 残ればいいくらいのつもりだっけど三冠やっちゃったもんな 3/1 ガンバ 0-1 浦和@万博 槙野に混戦から失点 3/19 ガンバ 2-0 神戸@万博 リンス初ゴール 4/12 セレッソ 2-2 ガンバ@長居 フォルラン二発やられるも阿部ちゃんがやり返す 4/29 ガンバ 1-2 柏@万博 田中順也のコントロールシュートに,最後フリーキック 15位 千中で寄せ鍋 8/2 ガンバ 2-0 マリノス@万博 院試筆記が終わって直ぐに行った. 遠藤-パトのホットライン 2点目も遠藤 8/16 ガンバ 0-1 名古屋@万博 5連勝が途切れた 審判がちょっとあれだった ファールスローもとらないなんて... 10/09 ガンバ 3-1 川崎@万博 11/29 ガンバ 3-1 神戸@万博 バイト 普通のバイトをしつつ、外注で2件仕事をもらってた 片方はまだ終わってないや...

January 2, 2015

clojureのクラスリロード

前回もクラスローダのあたりを書いたがあんまりしっくりしないのでもうちょっと調べてみる. JavaのClassLoaderの仕組みが分かっていなかった. まずStack OverflowのHow does clojure class reloading work?から. 質問 私はclojureでクラスのリロードの仕組みについてコードやドキュメントを 調べてきました. 多くのwebサイト,例えばhttp://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html によると,クラスのロードは本質的に どんなデータ構造であれバイト列を得ることでそれを defineClassによりclassClassのインスタンスに変換し, resolveClassによりそのclassをresolve(link)することであるということでした. (defineClassは暗黙的にresolveClassを呼んでいるのでしょうか?) どんなclassloaderでもclassのリンクは一度だけに限定されています. もし既存のclassへリンクしようとした場合でも何も行われないようです. これでは新しいclassインスタンスをリンクできないという問題があり, classをリロードする際は毎度classloaderのインスタンスを作る必要があります. clojureに注目してみると,clojureには複数のクラス定義方法があります. 匿名クラス: reify proxy 名前付きクラス: deftype defrecord(内部ではdeftypeを使っている) gen-class これらに関するコードは最終的にclojure/src/jvm/clojure/lang/DynamicClassLoader.java へたどり着きます. DynamicClassLoader/defineClassではclassインスタンスを作り,キャッシュしておきます. クラスをロードし利用する場合はforNameを呼び,またそれはDynamicClassLoader/findClassを 呼びます. DynamicClassLoader/findClassは,キャッシュを検索しその後基底クラスを検索します. (通常のclassloaderでは逆に基底クラスを先に検索するようです.) 混乱の元になっているのは, forNameはclassをリンクする前に返す(returnする)とドキュメントにある これは既存のDynamicClassLoaderではclassのリロードが行えない 代わりに新しくDynamicClassLoaderのインスタンスを作らねばならないがそのコードが見つからない ということです. proxyやreifyは匿名クラスなのでクラス名が異なっていても問題ありません. しかし,名前付きクラスの場合はそうはいきません. DynamicClassLoaderの仕組みを教えてください. 最終的にはjavacでコンパイルされた.classファイルをロード,リロードさせたいのです. 回答 以下全てが同じ技術を使っているわけではありません. proxy proxyマクロは基底クラスやインタフェースから名付けられたクラスを作ります. それぞれのメソッドはインスタンス内でclojureのfnとして扱われるため, マクロの内部が同じか否かに依らず, 同じインタフェースが継承される場合は同じproxyのクラスが使われます. 実際にクラスのリロードは行われません. reify reifyの場合は,メソッド本体が直接classの中にコンパイルされるため, proxyのトリックは使えません. 代わりに,formがコンパイルされる度に新たなクラスができるため, もし本体を編集してリロードしたとしても完全に新たなクラス(新しい名前)が作られます. これも実際のクラスのリロードは行われません. gen-class gen-classではクラス名を指定するため,proxyやreifyとは異なります. gen-classマクロは枠組み(spec)のみを持ち,メソッド本体は持ちません. つまりproxyと似て,clojureのfnを参照するということです. しかしproxyと違いクラス名が枠組み(spec)と結びつくため,本体を修正しリロード ということは出来ません. 従ってgen-classはAOTでのみ利用可能でJVMの再起動が必要です. deftypeとdefrecord これらでは実際に動的なクラスのリロードが行われます. そのクラスを含むコードをコンパイル場合やforNameが呼ばれた場合など クラス名を解決する必要があるときは,DynamicClassLoader/findClass が呼ばれます....

May 20, 2014

clojureバイトコードと名前空間のロード

clojureが*.cljをコンパイルしたときに,どのようなバイトコードが 生成されるのかを調べてみる. まずは,単純な例: (ns example.hello)から始めてみる. 気をつけること コンパイル単位は名前空間 名前空間ごとにクラスローダ"namespace__init.class"が作られる http://clojure.org/compilationに詳細あり コンパイル時は(コンパイル対象のclojureコード)ソースディレクトリをクラスパスに含める 実行時はコンパイルされたクラスファイルの他にclojure.jarをクラスパスに含める コンパイル leiningenを使わず,生のclojureでコンパイルしていく. 以下のように3つのクラスファイルが作られる hello__init.class hello$fn__4.class hello$loading__4958__auto__.class $ mkdir clojure-work ; cd clojure-work $ wget http://central.maven.org/maven2/org/clojure/clojure/1.6.0/clojure-1.6.0.jar $ mkdir -p src/example $ vim src/example/hello.clj (ns example.hello) $ mkdir classes $ tree . ├── classes ├── clojure-1.6.0.jar └── src └── example └── hello.clj $ java -cp ./src:./classes:clojure-1.6.0.jar clojure.main user=> (compile 'example.hello) $ tree classes classes └── example ├── hello$fn__4.class ├── hello__init.class └── hello$loading__4958__auto__....

May 15, 2014

Debianのlivecdの作り方

livecdの作り方が気になったのでやってみた. livecdを作っておくとデモとか楽になるかもしれない. 1. ツール群インストール # aptitude -y install xorriso live-build syslinux squashfs-tools 2. debootstrap 適当にworkディレクトリ(~/livework)を切って,debootstrapで新しい環境作りをする. これで,~/livework/chroot以下にbin, etc, varなどの構造が作られる. # mkdir ~/livework && cd ~/livework # debootstrap --arch=amd64 sid chroot 3. chroot chrootを使い,debootstrapで作った新環境に潜る. proc等をマウントし,カーネルイメージとlive-bootをインストールする. # chroot chroot # export HOME=/root # export LC_ALL=C # export PS1="(chroot) $PS1" # mount -t proc none /proc # mount -t sysfs none /sys # mount -t devpts none /dev/pts # aptitude -y install linux-image-amd64 live-boot # passwd # aptitude clean # rm -rf /tmp/* # umount /proc /sys /dev/pts # exit 4....

April 7, 2014

Gentoo install on Virtualbox

Gentooをインストールしたことがなかったので, Gentooハンドブック通りにやってみる. 日本語版が更新されてないのがよく分かった. 環境 uname -a: Linux debian 3.13-1-amd64 #1 SMP Debian 3.13.7-1 (2014-03-25)x86_64 GNU/Linux Virtualbox 4.3.6 1. Gentoo Linuxのインストールについて シンプル,先進的なメタディストリビューション システム全体をスクラッチからでも,コンパイル済みからでも, 半分だけでもおk 2. 適切なインストールメディアの選択 http://mirrors.stuhome.net/gentoo/releases/x86/autobuilds/current-iso/install-x86-minimal-20140401.isoを使った GentooインストールCDは独立したGentoo環境を含むブート可能CD install-x86-minimal-<release>.iso ディスク容量が104MBしか使わない 必ずネットワーク上環境が必要 stage3 tarball 本マニュアルの対象 現在でもstage1, stage2は配布している ドキュメントもある 書き込んでブートする http://www.gentoo.org/main/en/mirrors.xmlから取ってくる releases/x86/autobuilds/current-iso パラメータを指定する 例えばgentooカーネルにカーネルパラメータdopcmciaを指定するなら, boot: gentoo dopcmciaみたいにする 普通に boot: gentooってやった すぐにキーボードを変更する. 22 JPにする 3. ネットワーク設定 勝手につながってたので飛ばす proxyの設定はこのタイミングで net-setup, pppoe-setup, pptpを使う net-setupが一般的 もし,カーネルモジュール(ドライバ)に不足があれば 手動でやる ls /lib/modules3.12.13-gentoo/kernel/drivers/net/ から見つけて modprode pcnet32とする 無線の場合はiwconfigでチェック iwconfig eth0 essid hogehogeman iwconfig eth0 key 1234hoehogeman 4....

April 6, 2014

scheme REPLとガベージコレクション

REPL 普通のREPL. 相変わらずパイプで繋いでる. トップレベルにS式を打ち込む度に流し込んでやるとできた. 逆アセンブル (disasm ..)とかいう命令を追加した. こんな感じで逆アセンブルした結果を確認できる. >>(disasm (+ 1 2 3)) === code === 0 0x12000002 ;FRAME 1 0x0000003c ;15 2 0x25000002 ;CONSTNUM 3 0x0000000c ;3 4 0x13000002 ;ARGUMEMT 5 0x25000002 ;CONSTNUM 6 0x00000008 ;2 7 0x13000002 ;ARGUMEMT 8 0x25000002 ;CONSTNUM 9 0x00000004 ;1 10 0x13000002 ;ARGUMEMT 11 0x03000002 ;REFER_GLOBAL 12 0x094bf2f3 ;+ 13 0x15000002 ;APPLY 14 0x0000000c ;3 15 0x27000002 ;DISASM 16 0x00000002 ;HALT ガベージコレクション cheneyのcopy gcを実装して埋め込んだ. 同じ大きさのFrom空間とTo空間という二つの領域を確保しておいて, From空間にallocateしていく. From空間が満タンになれば,ルートオブジェクト(レジスタとかシンボルテーブルとか)から たどれるオブジェクトをすべてTo空間にコピーする. 全部のコピーが終われば,From空間とTo空間を交換する. 単純なアルゴリズムともいえるけど,ルートを忘れやすいので注意が必要. ヒープの効率が悪くなったり,保守的GCじゃないなどデメリットがある. まあヒープは現状問題ないだろうし,スタックやレジスタの要素がオブジェクトかプリミティブ かは判定できるのでexactなGCで問題ない. メリットは,フラグメンテーションが起こらない,キャッシュと相性がよいなど素晴らしい. ここまでは,copy gcの話....

March 7, 2014

scheme VMをCで書く

オブジェクトの表現 二つの型(vm_data型とvm_obj構造体)を使っている. vm_data型にはprimitiveな型や定数,そしてオブジェクトへの参照を入れる. 保守的なGCとか大変そうなので,1ワードの中にタグを含めることにした. 下位ビットで判定する. 単純にtypedef intptr_t vm_data;としている. 整数 ....00 上位30bitで符号付き整数を表現 文字 .00000 上位8bitで表現 true .00101 false .01001 nil .01101 undefined .10101 ボックス ....10 vm_dataへの参照 vm_obj ....11 vm_objへの参照 vm_obj構造体は,その他もろもろのオブジェクトを入れる. こんな感じで,文字列,シンボル,クロージャ,ペア,スタックオブジェクト を表現する. struct vm_obj { unsigned char tag; union{ char *string; char *symbol; vm_data *closure; struct { vm_data *p; int size; } stack; struct { vm_data *car; vm_data *cdr; } pair; } u; }; 実行 コンパイラまでは,以前と同じものを使う. とりあえず,パイプで受け渡しするようにしている. compile.scmはschemeで書いたscheme->バイトコードのコンパイラ, vmはCで書いたVM. 不格好だが,こんな感じで実行する. replはまだない....

February 28, 2014

3imp 伝統的マクロとバイトコードの変換

伝統的マクロ VMの方は触らずに,コンパイラの方だけを修正した. マクロ展開時と定義時にマクロテーブルに追加したり,参照したりするようにしている. トップレベル変数とは名前空間が違うけど,これでいいよな… ということで以下のようにletとかbeginとかいろいろ自由に拡張できるようになった. また時間があれば他のマクロシステムも増やしたい. (define-macro let (lambda (binds . bodies) (cons (append (list 'lambda (map (lambda (x) (car x)) binds)) bodies) (map (lambda (x) (cadr x)) binds)))) (let ((a 10)) (+ a 1)) バイトコードをかっこよく 今までのバイトコードは下のような感じで,次の命令を繋げていく構造だった. schemeで扱うには適しているようなだけど,後々VMをCで書きたいのでもっと線形な感じにしたい. (frame (halt) (constant 2 (argument (constant 1 (argument (close 0 (refer-local 1 (return 2)) (apply))))))) こんな感じにした. これでCとのインターフェイスも簡単にかけそう. 0 frame 9 戻り番地を9にしてフレームを作る 1 constant 2 定数2をaccumulatorにロード 2 argument スタックにつむ 3 constant 1 定数1をaccumulatorにロード 4 argument スタックにつむ 5 close 0 7 8 7番地から8番地を本体にするclosureオブジェクトをaccumulatorにロード 6 apply そのclosureオブジェクトを適用 7 refer-local 1 2つめのローカル変数をロード 8 return 2 レジスタからローカル変数2つ取り除いて復元 9 halt おわり この作業はなかなか大変だった. 問題点はclosureだった. closureをトップレベル変数に束縛しない限りは,そのclosureに対応するバイトコードが存在するから, closureオブジェクトには単純に,#(開始番地 終了番地)を入れておけばいい. しかし,トップレベル変数に束縛した場合は,呼び出し時には開始番地や終了番地が分かったところでそのバイトコードの自体がないので,呼び出せない. 色々考えてみる...

February 18, 2014