Download - Boost.勉強会#4 Boost.Proto
僕はどうして Boost.Proto をぺろぺろしようとしたのか。
Boost.勉強会 #4 2011/02/26
ふじた のりひさ/@fjnli id:fjnl
1
2
とある Twitter の会話履歴 (ログ) ...
最初の発表だれがいいですかhttp://atnd.org/events/11551
3
最初の発表だれがいいですかhttp://atnd.org/events/11551
Protoのどんな所がききたいですか。
3
最初の発表だれがいいですかhttp://atnd.org/events/11551
Protoのどんな所がききたいですか。
Lambda, Spirit, uBLASがあるいま、Protoで 何を作るのか 。
3
僕はどうして Boost.Proto をぺろぺろしようとしたのか。
4
5
Boost.勉強会#4の発表に「なぜ僕はProtoをぺろぺろするのか(仮)」というタイトルがありますが、ぺろぺろする理由とか全く聞きたいと思わないので Protoのことについて話してください。
Agenda
•はじめに
• Boost.Proto のお話
•僕がぺろぺろした理由
•まとめ + 質疑応答
6
Agenda
•はじめに
• Boost.Proto のお話
•僕がぺろぺろした理由
•まとめ + 質疑応答
6
いまここ
Agenda
•はじめに
• Boost.Proto のお話
•僕がぺろぺろした理由
•まとめ + 質疑応答
前半15分ぐらい
後半5分ぐらい
6
いまここ
Agenda
• Boost.Proto のお話
• Boost.Proto は縁の下の力持ち
• Expression Template (ET) の型
• Boost.Proto の拡張方法
7
Agenda
•僕がぺろぺろした理由
•数値計算に Boost.Proto を使う
• Boost.uBLAS では満足できない理由
•General Purpose computing on GPU (GPGPU)について少し
• ET → 関数呼び出しの列への変換
8
自己紹介
•ふじた のりひさ (藤田 典久)
• @fjnli, id:fjnl•東京都の端の大学 → 山奥の大学院 (見込)
•Ariel Networks バイト
•研究テーマ: GPU を用いた数値計算
9
自己紹介
•ふじた のりひさ (藤田 典久)
• @fjnli, id:fjnl•東京都の端の大学 → 山奥の大学院 (見込)
•Ariel Networks バイト
•研究テーマ: GPU を用いた数値計算
9
Hatena IDに i はいりません
自己紹介
•ふじた のりひさ (藤田 典久)
• @fjnli, id:fjnl•東京都の端の大学 → 山奥の大学院 (見込)
•Ariel Networks バイト
•研究テーマ: GPU を用いた数値計算
9
Hatena IDに i はいりません※ 本人も間違えました
自己紹介
•ふじた のりひさ (藤田 典久)
• @fjnli, id:fjnl•東京都の端の大学 → 山奥の大学院 (見込)
•Ariel Networks バイト
•研究テーマ: GPU を用いた数値計算
10
前半.begin();
11
Proto 概要
• Expression Template (ET) の構築を補助するライブラリ
• a + b * c → plus<A, multiply<B, C>>
• Boost 1.37 で導入された
•Headers only
12
Proto は縁の下の力持ち
• Boost.Proto は単体で利用して嬉しいライブラリではない
• Boost 中の Boost.Proto ユーザ:
• Boost.Spirit (Qi, Karma, Lex)
• Boost.Phoenix v3 (in the future)
• Boost.MSM.eUML (experimental, 1.44)
• Boost.Xpressive
13
ETの型
•割と重要
•エラーメッセージで頻出
•一般的におそろしく長い (´・ω・`)
•Qi で Proto 関係の部分でエラーを出すと遭遇する
14
15
namespace proto = boost::proto;using namespace boost::proto;using boost::proto::argsns_::list2,using boost::proto::exprns_::expr;using boost::proto::exprns_::term;
紙面の都合で、以降、特に断りがない場合、以下に示す using 宣言を暗黙に行なっています。
a[b] + (c * d)
16
構文木 (Syntax Tree) で表すと:
a[b] + (c * d)
16
(+)
(*)
c d
([])
a b
構文木 (Syntax Tree) で表すと:
a[b] + (c * d)
17
expr<tag::plus, list2< expr<tag::subscript, list2<, expr<tag::terminal, term<int>, 0>&, expr<tag::terminal, term<int>, 0>& >, 2 > const&, expr<tag::multiplies, list2< expr<tag::terminal, term<int> 0>&, expr<tag::terminal, term<int> 0>& >, 2 > const& >, 2> const
a[b] + (c * d)
18
expr<tag::plus, list2< expr<tag::subscript, list2<, expr<tag::terminal, term<int>, 0>&, expr<tag::terminal, term<int>, 0>& >, 2 > const&, expr<tag::multiplies, list2< expr<tag::terminal, term<int> 0>&, expr<tag::terminal, term<int> 0>& >, 2 > const& >, 2> const
式を表す型 exprns_::expr
a[b] + (c * d)
19
expr<tag::plus, list2< expr<tag::subscript, list2<, expr<tag::terminal, term<int>, 0>&, expr<tag::terminal, term<int>, 0>& >, 2 > const&, expr<tag::multiplies, list2< expr<tag::terminal, term<int> 0>&, expr<tag::terminal, term<int> 0>& >, 2 > const& >, 2> const
式の種類を表すタグplus → +
multiplies → *subscript → []
など…
a[b] + (c * d)
20
expr<tag::plus, list2< expr<tag::subscript, list2<, expr<tag::terminal, term<int>, 0>&, expr<tag::terminal, term<int>, 0>& >, 2 > const&, expr<tag::multiplies, list2< expr<tag::terminal, term<int> 0>&, expr<tag::terminal, term<int> 0>& >, 2 > const& >, 2> const
子ノードを表す argsns_::listN
a[b] + (c * d)
21
expr<tag::plus, list2< expr<tag::subscript, list2<, expr<tag::terminal, term<int>, 0>&, expr<tag::terminal, term<int>, 0>& >, 2 > const&, expr<tag::multiplies, list2< expr<tag::terminal, term<int> 0>&, expr<tag::terminal, term<int> 0>& >, 2 > const& >, 2> const
終端記号を表す型
exprns_::term
a[b] + (c * d)
22
expr<tag::plus, list2< expr<tag::subscript, list2<, expr<tag::terminal, term<int>, 0>&, expr<tag::terminal, term<int>, 0>& >, 2 > const&, expr<tag::multiplies, list2< expr<tag::terminal, term<int> 0>&, expr<tag::terminal, term<int> 0>& >, 2 > const& >, 2> const
とりあえず使ってみる
23
default_context const ctx;std::cout << eval(lit(1) + 2 + 3, ctx) << std::endl;
コード:
実行結果:
6
24
とりあえず使ってみる
default_context const ctx;std::cout << eval(lit(1) + 2 + 3, ctx) << std::endl;
コード:
この式を、このコンテキストで評価する。
とりあえず使ってみる
25
式をどのように評価するかは、コンテキストが知っている。
default_context → C++の標準セマンティックnull_context → 何もしない
+ を - とするコンテキスト
•x + y という式を x - y というセマンティックで評価するコンテキストを作る
•話を簡単にするために、int型以外の終端記号と + 以外の演算子の挙動は定義しない
•→ コンパイルエラー
26
+ を - とするコンテキスト
27
struct my_context { template < class Expr, class Enable = void > struct eval;};
eval時にmy_context::eval<Expr>()(expr, ctx)の形で呼ばれる
+ を - とするコンテキスト
27
struct my_context { template < class Expr, class Enable = void > struct eval;};
eval時にmy_context::eval<Expr>()(expr, ctx)の形で呼ばれる
SFINAE用。なくても構わない。
SFINAE
• SFINAE (すふぃねー?)
• Substitution Failure Is Not An Error
•置き換え失敗はエラーに非ず
• boost::enable_ifなど
•template <class T>typename enable_if<is_const<T>>::type foo();
• SFINAEを用いて eval を分岐する。
28
+ を - とするコンテキスト
29
template <class Expr>struct eval< Expr, typename boost::enable_if< matches<Expr, terminal<int>> >::type> { typedef int result_type;
result_type operator ()(Expr& e, my_context const&) const { return value(e); }}
+ を - とするコンテキスト
30
template <class Expr>struct eval< Expr, typename boost::enable_if< matches<Expr, terminal<int>> >::type> { typedef int result_type;
result_type operator ()(Expr& e, my_context const&) const { return value(e); }}
proto式パターンマッチ:
Expr が terminal<int> にマッチするならば、メタ true
+ を - とするコンテキスト
31
template <class Expr>struct eval< Expr, typename boost::enable_if< matches<Expr, terminal<int>> >::type> { typedef int result_type;
result_type operator ()(Expr& e, my_context const&) const { return value(e); }}
評価した結果の型。C++0xならdecltypeで書ける。
+ を - とするコンテキスト
32
template <class Expr>struct eval< Expr, typename boost::enable_if< matches<Expr, terminal<int>> >::type> { typedef int result_type;
result_type operator ()(Expr& e, my_context const&) const { return value(e); }}
終端記号の値を取る
+ を - とするコンテキスト
33
template <class Expr>struct eval< Expr, typename boost::enable_if< matches<Expr, terminal<int>> >::type> { typedef int result_type;
result_type operator ()(Expr& e, my_context const&) const { return value(e); }}
+ を - とするコンテキスト
34
template <class Expr>struct eval< Expr, typename boost::enable_if< matches<Expr, plus<_, _>> >::type> { typedef int result_type;
result_type operator ()(Expr& e, my_context const& ctx) const { return proto::eval(left(e), ctx) - proto::eval(right(e), ctx); }}
+ を - とするコンテキスト
35
template <class Expr>struct eval< Expr, typename boost::enable_if< matches<Expr, plus<_, _>> >::type> { typedef int result_type;
result_type operator ()(Expr& e, my_context const& ctx) const { return proto::eval(left(e), ctx) - proto::eval(right(e), ctx); }}
_ は何にでもマッチする(wildcard)
+ を - とするコンテキスト
36
template <class Expr>struct eval< Expr, typename boost::enable_if< matches<Expr, plus<_, _>> >::type> { typedef int result_type;
result_type operator ()(Expr& e, my_context const& ctx) const { return proto::eval(left(e), ctx) - proto::eval(right(e), ctx); }}
left: 1番目の子ノードを得るright: 2番目の子ノードを得る
+ を - とするコンテキスト
37
template <class Expr>struct eval< Expr, typename boost::enable_if< matches<Expr, plus<_, _>> >::type> { typedef int result_type;
result_type operator ()(Expr& e, my_context const& ctx) const { return proto::eval(left(e), ctx) - proto::eval(right(e), ctx); }}
足すのではなく、引く
+ を - とするコンテキスト
38
template <class Expr>struct eval< Expr, typename boost::enable_if< matches<Expr, plus<_, _>> >::type> { typedef int result_type;
result_type operator ()(Expr& e, my_context const& ctx) const { return proto::eval(left(e), ctx) - proto::eval(right(e), ctx); }}
とりあえず使ってみる その2
39
my_context const ctx;std::cout << eval(lit(1) + 2 + 3, ctx) << std::endl;
コード:
実行結果:
-4
実行時/コンパイル時
•実行時関数:
• proto::left, proto::right
•コンパイル時の返り値型:
• proto::result_of::left, proto::result_of::right
•C++0xでは若干いらない子
40
その他の拡張•Context
•評価に関する情報の提供
•Domain
•式の生成手段の提供
• Extends
•式を表す型を自分で提供する
•Grammer
•文法を定義する。演算子オーバーロードの制御41
その他の拡張
42
入りきらないので参考文献:
1.User’s Guide
http://www.boost.org/doc/libs/1_46_0/doc/html/proto/users_guide.html
2. 自ブログ (C++ Advent Calender JP 2010; 16日目)
http://d.hatena.ne.jp/fjnl/20101222/
前半.end();
後半.begin();
43
Proto を数値計算に使う
• ET と数値計算は相性がいい
•「アルゴリズム」と「計算実装」を分離できる
•組み合わせの爆発を抑制
•見た目が良い (+ が加算を表す)
• (僕のやっている分野では)
単純な計算の組み合わせで表現できる
• Basic Linear Algebra Subprograms (BLAS)
44
Boost.uBLAS ではだめなのか
• Boost.uBLAS は可読性を重視している
• Boost.uBLAS は遅い
• Boost.uBLAS は拡張できない
45
Boost.uBLAS ではだめなのか
•アルゴリズムは CPU, GPU 共通
•コードを共有したい→バグが減る
•計算実装は CPU と GPU で異なり、内部実装が多種多様
•例:
•密行列の実装、疎行列の実装
• CPU: オリジナル, ATLAS, GotoBLAS, OpenCL
• GPU: オリジナル, CUBLAS, OpenCL
46
ET → 関数呼び出し列
47
Backend::scalar a;Backend::vector b, x, y;y = a * x + b;
Backend::eval< multiply, scalar, vector>()(y, a, x);Backend::eval< plus, vector, vector>()(y, y, b);
最適化
48
[a * x + y]plus<multiply<scalar, vector>, vector>
axpy<scalar, vector, vector>
積和演算の最適化をコンパイル時に行う。積和演算を一気に、かつ高速に行なえる
アーキテクチャが存在する。(Cell, GPU など)
49
ご清聴ありがとうございました。
そして
質疑応答