Redundanz

僕の言葉は、人と話をするためにあるんじゃない。

0704

 「遊声」の演奏会を聞きにゆきました。自分の所属している(?)団の演奏を客席から聞くのは初めてだったけれど良いステージだったと思います。森下唯さんの伴奏もすごかった。頭の良さそうな弾き方をする。

 終わってから演奏会に参加しなかった団員の一部と飲み会をしました。全体的に世を儚む雰囲気が漂っていたのは卒論や院試、就活が近づいているからか。まあでも割と楽しかったです。今日はあんまり悪酔いしなかったし。それなりに飲んだのだけれどな。

 帰宅後ふと思い至ってPythonで自動微分アルゴリズムを実装してみました。C++で書いている人がいたのでそれを翻訳しただけですが。具体的にはx,dxの値を持つdualというクラスを作って、後は各演算子fに対してf(dual(x,dx)) = dual(f(x), dx*f'(x))の関係を定義しておく。するとdualの組み合わせで定義された関数に対して微分係数を計算できる、みたい。実際ニュートン法平方根求める関数にdual(2)を放り込むと0.35355339059327373(=1/2*sqrt(2))と出る。何やらうまくいっているようです。今後もうちょっと改良してgradientの計算とかできるようにしたい。
 Pythonのオペレータはその左か右かで色々挙動が異なるみたいで面倒ですね。相手がなんであれこっち優先!というふうにできたらいいのに。

 コードを貼ってみる。

class Variable():
    def __init__(self, x, dx=1.0):
        self.x = x
        self.dx = dx
    def __add__(self, r):
        r = self.cast2var(r)
        return Variable(self.x+r.x, self.dx*1.0 + r.dx*1.0 )
    def __sub__(self, r):
        r = self.cast2var(r)
        return Variable(self.x-r.x, self.dx*1.0 + r.dx*-1.0 )
    def __mul__(self, r):
        r = self.cast2var(r)
        return Variable(self.x*r.x, self.dx*r.x + r.dx*self.x )
    def __div__(self, r):
        r = self.cast2var(r)
        return Variable(self.x/r.x, self.dx*(1.0/r.x) + r.dx*(-self.x/r.x/r.x) )
    def __radd__(self, r):
        r = self.cast2var(r)
        return Variable(self.x+r.x, self.dx*1.0 + r.dx*1.0 )
    def __rsub__(self, r):
        r = self.cast2var(r)
        return Variable(self.x-r.x, self.dx*1.0 + r.dx*-1.0 )
    def __rmul__(self, r):
        r = self.cast2var(r)
        return Variable(self.x*r.x, self.dx*r.x + r.dx*self.x )
    def __rdiv__(self, r):
        r = self.cast2var(r)
        return Variable(r.x/self.x, r.dx*(1.0/self.x) + self.dx*(-r.x/self.x/self.x) )
    def __neg__(self):
        return Variable(-self.x, -self.dx)
    def __int__(self):
        return Variable(int(self.x), self.dx)
    def cast2var(self, x):
        if x.__class__.__name__ == 'Variable':
            return x
        else:
            return Variable(x, 0.0)