2007年9月21日金曜日

初投稿 PageRankの計算 C++でどう書く?

最近 どう書く?.org への参戦を始めました。
プログラミングのお題が与えられて、「あなたならどう書く?」と、いったとこでしょうか。
今ではすっかり、次のお題がいつ来るのか、気になって気になって...

中には、似たような投稿が既に出てたり、題意に沿わない気がして、投稿を見合わせる事があります。そういったもので、「これは発表したい」と、思うものはこのブログに載せていこうと思います。

第一回目のお題は、PageRankの計算です。
お題では、行列演算ライブラリを使う事とありましたが。外部ライブラリを使わない版をC++で書きました。valarrayを使いたかったんです。それと、お題ではページ番号が1始まりですが、使いやすい0始まりにしてます。
#include <iostream>
#include <vector>
#include <valarray>
#include <algorithm>
using namespace std;

valarray<double> page_rank(const valarray<size_t> link[], size_t n) {
valarray<double> m(0.0, n * n), r(1.0 / n, n), prev(n);

for (size_t i = 0; i < n; i++)
m[valarray<size_t>(n * link[i] + i)] = 1.0 / link[i].size();

do {
prev = r;
for (size_t i = 0; i < n; i++)
r[i] = (valarray<double>(m[slice(i * n, n, 1)]) * prev).sum();
} while (valarray<double>(abs(r - prev)).max() > 1e-8);

return r;
}

int main() {
const int N = 7;
int data[N][N] = {
{ 1, 2, 3, 4, 6, -1 },
{ 0, -1 },
{ 0, 1, -1 },
{ 1, 2, 4, -1 },
{ 0, 2, 3, 5, -1 },
{ 0, 4, -1 },
{ 4, -1 }};
valarray<size_t> link[N];

for (size_t i = 0; i < N; i++) {
vector<size_t> v(data[i], find(data[i], data[i] + N, -1));
link[i].resize(v.size());
link[i] = valarray<size_t>(&v[0], v.size());
}

valarray<double> rank = page_rank(link, N);
for (size_t i = 0; i < rank.size(); i++)
cout << ' ' << rank[i];
cout << endl;

return 0;
}

== 出力 ==
0.303514 0.166134 0.140575 0.105431 0.178914 0.0447284 0.0607029

なかなか、書き方もややこしいですが、複雑な行列計算をこれだけの量で書けました。
実際のPageRank計算では規模が全く違うので、このコードじゃダメなんでしょうけど、充分楽しめました。

0 件のコメント: