PythonでMethod Missing

 聞くところによると、RubyにはMethod Missingなる機能があるとか。
いわく、オブジェクトにメソッドがない場合に、どういう処理をするかを記述するとか。


こいつぁ、われらがPythonにも欲しい機能です。


上記の文面をまともに受け取る使い方でも良いのですが、たとえば、あるオブジェクトのメソッド全てについて、
同様な処理を付加するといったラッパーが簡単に書けちゃうわけです。


というわけで調べてみた。
そのものずばりは出てこなかったけれど、おおむねこんなかんじ。
Method missing(のようなもの)を使った簡易ラッパー。

import threading
import time

class Wrappee:
    def __init__( self, count ):
        self.count = count

    def print_something( self, text ):
        for i in range( self.count ):
            print( i, " something : ", text )
            time.sleep( 0.5 )

class Wrapper:
    def __init__( self, wrapper ):
        self.wrappee= wrapper

    # Emulate ruby like " missing method ".
    def __getattr__( self, name ):
        def _method_missing( *args ):
            return args

        print( "--", name, " is called --")
        ret = getattr( self.wrappee, name, _method_missing)
        return ret


wrappee = Wrappee( 10 )
wrapper = Wrapper( wrappee )
wrapper.print_something( " foo " )


ううん、これは便利だ。
ただ、ラップされるオブジェクトに指定の関数名がない場合にエラーが出ないのが玉に傷。
どこかのサイトで関数名一覧をディクショナリでもっておいて検査するという手法も見られたけど、もっと楽にいけないものだろうか。

すごいのみつけた

 以前から、Haskellの遅延評価の枠組みは確率分布のサンプリングとかやるのによさそうだなぁとか思っていたのですよ。

再帰を使うってだけなら、C++とかでも上記の式と同様になるかと思いますが、
いざサンプリングするぞって時に面倒なのが、SBPのtailの方。

僕の場合だと、必要な分だけ確率列を用意して、サンプリング中に必要になる、
そのつど確率変数に値を振っていくという形式のコードです。面倒。

んが、Haskellだと(多分)そのへん自動でやってくれる!すごい!
んじゃないのかな。実際動かしたわけじゃないのでわからないのですが。


そんなこんなで、Haskellでノンパラベイズ周辺のライブラリを書こうと意気込んだその矢先、

すごいのみつけた


しかもコードは、かのHal Daume III御大。


とりあえずオープンソースにして。コミットするから。

O'REILLYどうした

 もともと翻訳どうよ、と思うものが多い出版社でしたが、
久々の出物、しかも大物、しかも2つ。


あまりに酷いので、ここで血祭りにあげようと思います。

プライムナンバーズ ―魅惑的で楽しい素数の事典 (O’Reilly math series)

プライムナンバーズ ―魅惑的で楽しい素数の事典 (O’Reilly math series)

数学を生み出す魔法のるつぼ ―実験数学への招待 (O’Reilly math series)

数学を生み出す魔法のるつぼ ―実験数学への招待 (O’Reilly math series)


これはひどすぎる。読めたものではないとはまさにこれか。


分かりにくい日本語とか、そういうレベルではなく、
もはや日本語の体をなしていない文章だらけ。
誤植等も非常に多い。


久々に焚書目録に登録しました。


なお、非常に残念ですが、内容については触れることはできません。
50ページくらいで読むのをやめてしまったので。
そのうち原書のほうを買います。


原著をなぶって遊ぶのはやめたらどうかと声を大にして言いたい。



....追記
プライムナンバーズを無理やり読んでみた。
普通に原書がほしい。

はじめてのMac

 時代の流れに負けてMac book Proを買った。

とりあえずキーボードの使い方がwindowsと違いすぎて困ったが、

GUIのとてもきれいなlinuxなんだという友人のアドバイスでバリバリ使えるようになった。


 もちろんコマンドラインでしか使ってない。どうしてこうなった。

Project Euler Problem 84

モノポリーで、どの升目に止まりやすいかという問題。
まじめに計算できそうな感じだけど、せっかくなのでサンプリングしてみる。
ただひたすら面倒なだけ。

import random
# monopoly simulator
cells = [ 'GO', 'A', 'CC', 'A', 'T', 
         'R', 'B', 'CH', 'B', 'B',
         'JAIL', 'C', 'U', 'C', 'C',
         'R', 'D', 'CC', 'D', 'D',
         'FP', 'E', 'CH', 'E', 'E',
         'R', 'F', 'F', 'U', 'F',
         'G2J', 'G', 'G', 'CC', 'G',
         'R', 'CH', 'H', 'T', 'H' ]
cccards = ['DC', 'DC', 'DC', 'DC', 'DC',
           'DC', 'DC', 'DC', 'DC', 'DC',
           'DC', 'DC', 'DC', 'DC', '0', '10']
ccards = ['DC', 'DC', 'DC', 'DC', 'DC',
               'DC', '0', '10', '11', '24', 
               '39', '5', 'G2NR', 'G2NR', 'G2NU',
               'GB3']
def pe84():
    ntrial = 500000
    shuffle_cards()
    visited = sampling( ntrial )
    print visited
    print get_solution( visited )
def get_solution( visited ):
    first = get_max_index( visited )
    visited[first] = 0
    second = get_max_index( visited )
    visited[second] = 0
    third = get_max_index( visited )
    return "".join( [encode_squareface( first ), encode_squareface( second ), encode_squareface( third ) ] )
def get_max_index( lis ):
    idx = 0
    max = 0
    for i in range( 0, len( lis ) ):
        if lis[i] >= max:
            idx = i
            max = lis[i]
    return idx
              
def sampling( ntrial ):
    visited = [ 0 for i in range(0, len(cells))]
    pos = 0
    tried = 0
    # should I count first GO as visited ?
    while tried < ntrial:
        nextpos = nextcell( pos)
        #print len( visited ), " ", nextpos
        visited[nextpos]+= 1
        pos = nextpos
        tried +=1
    return visited

def nextcell( current_position):
    global prev_doubles
    score1 = random.randint( 1, 4 )
    score2 = random.randint( 1, 4 )
    if score1 == score2:
        if prev_doubles == 2:
            prev_doubles = 0
            return 10 
        else:
            prev_doubles += 1
    else:
        prev_doubles = 0
    next_position = advance( score1+score2, current_position )
    #print score, next_position
    if cells[next_position] == 'CC':
        return ccjump( next_position )
    elif cells[next_position] == 'CH':
        return cjump( next_position )
    elif cells[next_position] == 'G2J':
        return 10
    else:
        return next_position
def ccjump( current_position ): 
    card = drawcc()
    if card == 'DC':
        return current_position
    else:
        return int( card )
def cjump( current_position ):
    card = drawc()
    if card == 'DC':
        return current_position
    elif card == 'G2NR':
        return g2nr( current_position ) 
    elif card == 'G2NU':
        return g2nu( current_position )
    elif card == 'GB3':
        return back( 3, current_position )
    else:
        return int( card )
def g2nr( current_position ):
    while( True ):
        current_position = advance( 1, current_position)
        if cells[current_position] == 'R':
            return current_position
def g2nu( current_position ): 
    while( True ):
        current_position = advance( 1, current_position )
        if cells[current_position]  == 'U':
            return current_position
def advance( nsteps, current_position ):
    while nsteps > 0:
        current_position+=1
        if current_position > len( cells ) - 1:
            current_position = 0
        nsteps-=1
    return current_position
def back( nsteps, current_position ):
    while nsteps > 0:
        current_position -= 1
        if current_position < 0:
            current_position = len( cells ) - 1
        nsteps -=1
    return current_position 
def shuffle_cards():
    global ccards
    global cccards
    random.shuffle( ccards ) 
    random.shuffle( cccards )
def drawc():
    global ccards
    drawed = ccards.pop( 0 )
    ccards.append( drawed )
    return drawed 
def drawcc():
    global cccards
    drawed = cccards.pop( 0 )
    cccards.append( drawed )
    return drawed
def encode_squareface( num ):
    print "n : ", num 
    if num < 10:
        return '0'+str(num )
    else:
        return str( num )

prev_doubles = 0
pe84()

なんだかとてもまじめに書いた。

Project Euler Problem 125

 単なるブルートフォースなのだが、範囲が違うけど同じ数が出うることと、それを加算してはいけないことに1時間ハマって死にたい。何この凡ミス。

typedef unsigned long long int nat;

vector<nat> gensqsq(nat lim){
	vector<nat> sqsq;
	for(nat i=1;i*i <= lim;++i)sqsq.push_back(i*i);
	return sqsq;
}

bool ispalindromic( nat n ){
	if( n >= 10 && n % 10 == 0 ) return false;
	deque<int> d;
	while( n ){
		d.push_front( n % 10 );
		n /= 10; 
	}
	for( int i=0, j=d.size()-1; i <= j; ++i, --j ){
		if( d[i] != d[j] ) return false;
	}
	return true;
}

nat pe125(){
	set<nat> s;
	nat limit = 100000000;
	nat total = 0;
	
	vector<nat> sq = gensqsq(limit);

	for( nat from = 0; from < sq.size(); ++from){
		nat seqsum = 0;
		for(nat to=from; to < sq.size(); ++to ){
			seqsum += sq[(unsigned int )to];
			if( to == from ) continue;
			if( seqsum >= limit )break;
			if( ispalindromic( seqsum ) )
				s.insert( seqsum );
		}
	}
	for( set<nat>::iterator itr = s.begin(); itr != s.end(); ++itr )
		total += *itr;
	return total;
}

新言語

 NTTはもう少しまじめくさいところだと思っていた。


 NTTの人が書いたプログラミング言語http://www.brl.ntt.co.jp/people/hirata/Papers/spa99.pdf:論文

 その名も、織田信長
 論文の字面の時点ですでにシュールすぎるが、この言語の真価はその由来にある。

 新しい言語 → 新言語 → 信玄後 → 織田信長


 ソース:
http://iiyu.asablo.jp/blog/2008/03/14/2741992
http://www.brl.ntt.co.jp/people/hirata/Papers/spa99-on-slides.pdf


 NTTのCS研は、自然言語だけでなく計算機言語もすばらしく、
その上ギャグも一流なんですね。


 完全に僕の負けです。本当にありがとうございました。

スライスでちょっと考え込んだ

Pythonにて、

s = "123456789"

というようなリスト(この場合文字列だが)で、マイナスのインデックスを指定してスライスすると、末尾から数えてくれる。

print s[-4:-1]

とすれば"678"が取れる。


じゃあマイナスインデックスから、リスト末尾までのスライスはどうすればいいの?

print s[-4:0]

違う違う。

print s[-4:-0]

なんぞこれは。違う。



pythonのスライスの2つ目のargument(何ていうんだ)は"未満"の扱いなので、困る。
どうすればいいんだー。


と悩んで10分。

print s[-4:]


あ、そっか。


インデックス指定できないのは気持ち悪いけど、多分これしかなさそう。
末尾の次の要素、なんてないもんなぁ。これでいいのかpython

Project Euler 87

ストレートにx^2 + y^3 + z^4を総当りでとけばよい。


どうせそれぞれの変数に入る素数の値候補は多くは無いので、
最初にリストにしてしまって、リストの3重ループで回す。


当然xのとりうる範囲は50000000の平方根より少ない。
yのとりうる範囲は50000000の立方根より少ない。
zのとりうる範囲は50000000の4乗根より少ない。

#project euler 87

use strict;
use warnings;
use POSIX qw( ceil );

sub isprime{
	my $target = $_[0];
	return 0 if( $target <= 1 );
	return 1 if( $target == 2 );
	return 0 if( $target % 2 == 0 );

	for( my $i = 3; $i <= ceil( sqrt( $target ) ); $i+=2 ){

		if( $target % $i == 0){

			return 0;
		}
	}
	return 1;
}

sub get_primearray{
	my $limit = $_[0];
	my @prime;
	return 0 if ( $limit < 1 );
	foreach( 1..$limit){
		if( isprime( $_ ) == 1 ){

			push( @prime, $_ );
		}
	}
	return @prime;
}

my $limit = 50000000;
my $sq_lim = ceil( $limit ** ( 1 / 2) );
my $cb_lim = ceil( $limit ** ( 1 / 3) );
my $fr_lim = ceil( $limit ** ( 1 / 4) );

print "square : calcurate to $sq_lim\n";
print "cube : calcurate to $cb_lim\n";
print "forth power : calcurate to $fr_lim\n";

my @sqarr = get_primearray( $sq_lim );
my @cbarr = get_primearray( $cb_lim );
my @frarr =get_primearray( $fr_lim );
my %expr;

print "for sqare : @sqarr\n";
print "for cube : @cbarr\n";
print "for fourth power : @frarr\n";

foreach my $x(@sqarr){
	foreach my $y( @cbarr ){
		foreach my $z( @frarr ){
			my $key = $x ** 2 + $y ** 3 + $z ** 4;
			if( $key >= $limit ){
				next;
			} else {
				$expr{$key} = 1;
			}
		}
	}
}
my $count = keys( %expr );
print "$count\n";

このあたりの問題の難易度差が激しい気がする。