2008年3月11日火曜日

モンテカルロでパイ


モンテカルロシュミレーションにより円周率(パイ)を算出するプログラム。
”まぐれ”という不確実性科学の権威が書いた本を読んでいて簡単に
円周率を出せるというのでやってみた。

適当な円に密接する四角形を描く。ダーツゲームのようにその四角内に矢をあてる。
円の内部に入った矢と四角形内の矢すべての比率が円周率となる。
なんでかはわかりそうだったが、考えてたら頭がいたくなった・・・

とりあえず検証ということでrubyのTKでリアルタイムに描写させようとしたらはまった。
乱数発生の精度が低かった模様。最初は0〜100で乱数生成したので。
その後、精度を0〜10000にしたら良い数値が得られた。
3.14に近づくには100万回くらい待たなければだめみたい。


require "tkclass"
require "tk"

OFFSET=10

$oval=0
$sque=0
$disp_hankei=100
$hankei=10000

module MonteCarlo
def MonteCarlo.plot(max_x=$hankei*2, max_y=$hankei*2)
x = rand(max_x+1)
y = rand(max_y+1)
[x, y]
end
end

label = TkLabel.new do
text("0")
pack()
end

$c = TkCanvas.new('width'=>($disp_hankei+OFFSET)*2, 'height'=>($disp_hankei+OFFSET)*2).pack

Oval.new($c,OFFSET+0,OFFSET+0,OFFSET+$disp_hankei*2,OFFSET+$disp_hankei*2)
Rectangle.new($c,OFFSET+0,OFFSET+0,OFFSET+$disp_hankei*2,OFFSET+$disp_hankei*2)

def plot
x2 = 2
bx, by = MonteCarlo.plot($hankei*2, $hankei*2)
x, y = bx, by

x = bx - $hankei
y = by - $hankei

bx = bx / 100
by = by / 100

if (x*x + y*y) < $hankei*$hankei
$oval += 1
dot = Oval.new($c,OFFSET+bx,OFFSET+by,OFFSET+bx, OFFSET+by, "outline" => "red", "fill" => "red")
else
dot = Oval.new($c,OFFSET+bx,OFFSET+by,OFFSET+bx, OFFSET+by)
end
$sque += 1
end

count=0
TkAfter.new(1, -1, proc do
count+=1
plot
pai = $oval.to_f/$sque.to_f * 4.0
label.text("#{count.to_s} #{pai.to_s}")
end).start

Tk.mainloop


リアルタイムで描写しないのであれば乱数を少数で生成して円でなく扇がたで考え
シュミレーションするとあっというまによい精度でできた。
$oval = 0; $sque = 1

def plot
x, y = rand, rand
$oval += 1 if (x*x + y*y) < 1.0
$sque += 1
end

1000000.times {
plot
}

pai = $oval.to_f/$sque.to_f * 4.0
puts "pai #{pai.to_s}"


出力
pai 3.14324485675514


正直この本は難解な箇所が多々ありまが、理解できるとおもろいです。

2008年2月16日土曜日

システムトレード

FX&日経225先物 システムトレード実践テクニックの本を買った。
Click証券であればシステム的には完全自動売買が可能となるので
試してみようかな。。。
以前、ちょっと試しましたが実践したらすぐバグをみつけそれ以来
止めてしまいました。

本はまだ、途中ですがシステムの検証(バックテスト)はエクセルを使って
やっているようです。OpenOfficeのスプレッドシートもそれなりに
使えますが、やっぱエクセルと比べると見劣りします。

ubuntuならやっぱゴリゴリとスクリプトで検証すべきでしょう

2008年2月13日水曜日

ネットワーク理論3

3万人にアクセスしスクリプトも順調に動作していましたが、
mixiに足あとのつけすぎと怒られました。

自分から30693人時点での結果です。

隔たり次数 0 人数 1
隔たり次数 1 人数 38
隔たり次数 2 人数 365
隔たり次数 3 人数 3716
隔たり次数 4 人数 26573

隔たり次数が2で365人というのは自分の友達は他人の友達という
ことで結構友人がかぶっているのではないかと思います。

この後の推移を見たかったのですがここで止めときます。
おそらくmixiもスモールワールドなんだと思いますが、
実証できなくて残念。

2008年2月12日火曜日

weather hack

天気予報で降水確率が40%以上だったら、傘忘れないでね〜メールを
携帯に送るスクリプトを作りました。

天気予報データからXMLでデータを取得する。
自分の住まいのエリアの1日分の降水確率で40%以上があれば
予報データを組み立て携帯へ送信する。

携帯へはgmailを利用。gmailerというrubyのライブラリが必要です。

後は、crontab or タスクリストへ朝自動で起動する用にしておくだけです。
rubyなのでサクッとできました。

require 'net/http'
require 'gmailer'
require 'rexml/document'

host="www.drk7.jp"
path="/weather/xml/14.xml"

user="gmailのID"
pass="gmailのパスワード"
cellphone="携帯のアドレス"

#降水確率の基準値 メール送るか送らないか
RAINFALL_RATE=40

resp = ""
Net::HTTP.version_1_2

Net::HTTP.start(host, 80) {|http|
response = http.get(path)
if response.code != "200"
raise HttpError, "Http Conection Error."
end
resp = response.body
}

send_flag=false

body = "傘!!\n"
body << "神奈川県東部\n"
doc = REXML::Document.new(resp)
doc.elements.each("./weatherforecast/pref/area/info") do |item|
if item.attributes["date"] == Time.now.strftime("%Y/%m/%d")
#and doc.elements.each("./weatherforecast/pref/area").attributes["id"] == "東部"
body << item.text("weather") + "\n"
body << "降水確率\n"
4.times do |i|
period = item.get_elements("./rainfallchance/period")[i].text
hour = item.get_elements("./rainfallchance/period")[i].attributes["hour"]
body << "#{hour} #{period}\n"
begin
send_flag = true if period.to_i >= RAINFALL_RATE
rescue
end
end
body << item.text("weather_detail") + "\n"
# 西部をスキップする
break
end
end

puts body

if send_flag
GMailer.connect(user, pass) do |g|
g.send(
:to => cellphone,
:subject => "weather hack",
:body => body)
end
end


メールのイメージ
傘!!
神奈川県東部
くもり時々雨
降水確率
00-06 --
06-12 60
12-18 50
18-24 30
北の風のちやや強く海上では後北の風強くくもり朝から昼過ぎ雨

2008年2月10日日曜日

FX@ターミナル


Click証券が提供するFXトレード用のWEB API自作クライアントが実際に
使えるようになりました。現在は成行約定、成行決済、IFO注文、レート取得、
建玉取得だけできます。Click証券のWebページからトレードするよりはすばやく
トレードできます。
Rubyのカーセスの勉強にもなりました。

2008年2月9日土曜日

ネットワーク理論2

mixiへ再びアクセスできるようになりました。
隔たり次数がすぐに上がってしまうバグもあったので修正しました。

mixiのユーザ件数は1000万くらいだったので、スクリプトを途中で
止めた場合に内容をダンプする機能を付け加えました。

あと、アクセスする間隔は2秒が最適のようです。
メモリーが最後まで足りるかは?です。すべてのユーザにアクセスする
には先が長そうです。

途中経過(6千人程度)です。
隔たり次数 0 人数 1
隔たり次数 1 人数 38
隔たり次数 2 人数 365
隔たり次数 3 人数 3716
隔たり次数 4 人数 1832
全人数 5952

list.yaml
"自分のMIXIのID": 
:url: http://mixi.jp/show_friend.pl
:flag: false
:depth: 0


スクリプト
require 'rubygems'
require 'mechanize'
require "yaml"

username = '<メールアドレス>'
password = '<パスワード>'

agent = WWW::Mechanize.new
page = agent.get('http://mixi.jp/')
form = page.forms[0]
form.fields.find {|f| f.name == 'email'}.value = username
form.fields.find {|f| f.name == 'password'}.value = password
form.fields.find {|f| f.name == 'next_url'}.value = '/home.pl'
page = agent.submit(form, form.buttons.first)


def url()
a = nil; id = ""
$list.each do |k,i|
if i[:flag] == false
if a == nil
a = i; id = k
end
if a[:depth] > i[:depth]
a = i
id = k
end
end
end
id
end

def set(id, url, depth)
if !$list.key?(id)
a={:url=>url,:depth=>depth,:flag=>false}
$list[id] = a
end
end

def output_data
result = {}

$list.each do |k,v|
depth = v[:depth]
if result.key?(depth)
result[depth] += 1
else
result[depth] = 1
end
size = v[:list].size if v[:list] != nil
puts "#{k} #{size} #{v[:flag]} #{depth}"
end

result.each do |k,v|
puts "隔たり次数 #{k} 人数 #{v}"
end
puts "全人数 #{$list.size}"
end

$list = YAML::load(File.open("list.yaml").read)

Signal.trap('INT') do
output_data()
YAML.dump($list, File.open("list.yaml", 'w'))
exit 0

end

while (id = url()) != nil
$list[id][:list] = []
depth = $list[id][:depth] + 1
diarylist = agent.get($list[id][:url])
diarylist.links.each do |link|
if link.href =~ /show_friend.pl\?id\=(\d+)/
friend_id = $1.to_s
url = "http://mixi.jp/" + link.href
$list[id][:list] << $1
set(friend_id, url, depth)
end
end
$list[id][:flag] = true
puts "#{id} size #{$list.size}"

#中間報告
output_data() if rand(50) == 20
sleep 2
end

output_data()



本はこれです。

ネットワーク理論

ネットワーク理論の本を読んでます。

新ネットワーク思考—世界のしくみを読み解く(LINKED: The New Science of Networks)

有名なのはケビン・ベーコンゲームというものでケビン・ベーコンと他のハリウッド俳優は
少なくとも2人の共演者で繋がっているという法則。これはハリウッドの世界だけでなく
世界中の人々もすくなくとも6人の友人で繋がっている。自分と福田総理、自分とアフリカの
誰かとも6人の友人を通じてその人にたどり着けるというもの。
これは6次の隔たりと呼ばれています。

そこで思ったのがmixiはどうなってるんだろう?何次の隔たり?
スクリプトを作って検証しようと思いました。

require 'rubygems'
require 'mechanize'

username = '<メールアドレス>'
password = '<パスワード>'

agent = WWW::Mechanize.new
page = agent.get('http://mixi.jp/')
form = page.forms[0]
form.fields.find {|f| f.name == 'email'}.value = username
form.fields.find {|f| f.name == 'password'}.value = password
form.fields.find {|f| f.name == 'next_url'}.value = '/home.pl'
page = agent.submit(form, form.buttons.first)

$list={}
h={}
h[:url] = 'http://mixi.jp/list_friend.pl'
h[:flag] = false
h[:depth] = 0
$list["mixiのid"] = h

def url()
res=nil
$list.each do |k,i|
if i[:flag] == false
i[:flag] = true
return k
end
end
nil
end

def set(id, url, depth)
if !$list.key?(id)
a={:url=>url,:depth=>depth,:flag=>false}
$list[id] = a
end
end

while (id = url()) != nil
#break if $list.size > 100

$list[id][:list] = []
depth = $list[id][:depth] + 1
diarylist = agent.get($list[id][:url])
diarylist.links.each do |link|
if link.href =~ /show_friend.pl\?id\=(\d+)/
friend_id = $1.to_s
url = "http://mixi.jp/" + link.href
$list[id][:list] << $1
set(friend_id, url, depth)
else
# puts "not mutch"
end
sleep 1
end
puts "size #{$list.size}"
end

result = {}

$list.each do |k,v|
depth = v[:depth]
if result.key?(depth)
result[depth] += 1
else
result[depth] = 1
end
size = v[:list].size if v[:list] != nil
puts "#{k} #{size} #{v[:flag]} #{depth}"
end

result.each do |k,v|
pust "隔たり #{k} 人数 #{v}"
end


結果はアクセスし過ぎで接続不可になってしまいました。
sleepの時間を調節しないとダメみたいです。

間隔を空けない連続的なページの遷移・更新を頻繁におこなわれていることが見
受けられましたので、一時的に操作を停止させていただきます。申し訳ございま
せんが、しばらくの間お待ちください。

干し芋のリスト