倭算数理研究所

科学・数学・学習関連の記事を、「倭マン日記」とは別に書いていくのだ!

倭マン's Math (4) : FieldElement (org.apache.commons.math パッケージ)

前回まではメタクラスによってメソッド(クロージャ型のプロパティ)を追加してましたが、今回はカテゴリ & use キーワードで使い方を簡便化できるようにします(一覧, Jar)。

カテゴリメソッドと use キーワード


Groovy でのカテゴリ(カテゴリメソッド)とは単なる static メソッドで、use キーワードによってインスタンスメソッドのように扱えます。 例えば以下のように ComplexCategory を定義したとします:

import org.apache.commons.math.complex.Complex

class ComplexCategory{

    static def Complex plus(Complex c1, Complex c2){
        return c1.add(c2)
    }
}

このとき、以下のように plus() メソッドをインスタンスメソッドのように扱うことができます:

def c1 = new Complex(1d, 2d)
def c2 = new Complex(3d, 4d)

use(ComplexCategory){
    def c = c1.plus(c2)    // def c = ComplexCategory.plus(c1, c2) と同じ
    assert c == new Complex(4d, 6d)

    assert c1 + c2 == new Complex(4d, 6d)    // 演算子オーバーロードも使える
}

メソッドが呼び出されているオブジェクトが、実際には static メソッドの第1引数になります。

FieldCategory クラス


では、以下で FieldElement オブジェクトを使いやすくするカテゴリを定義してみましょう。 定義するのは

  • 和演算、積演算に関する単位元 (0, 1) と等しいかどうかを評価する izZero(), isOne() メソッド
  • 四則演算を行う plus(), minus(), multiply(), div() メソッド

です。 定義はこんな感じ:

import org.apache.commons.math.FieldElement

class FieldCategory {

    static def boolean isZero(FieldElement<?> f){
        return f.getField().getZero() == f
    }

    static def boolean isOne(FieldElement<?> f){
        return f.getField().getOne() == f
    }

    // Groovy の演算子オーバーロード
    // + : plus
    static def <F extends FieldElement<F>> F plus(F f1, F f2){
        return f1.add(f2)
    }

    // - : minus
    static def <F extends FieldElement<F>> F minus(F f1, F f2){
        return f1.subtract(f2)
    }

    // * : multiply
    static def <F extends FieldElement<F>> F multiply(F f1, F f2){
        return f1.multiply(f2)
    }

    // / : div
    static def <F extends FieldElement<F>> F div(F f1, F f2){
        return f1.divide(f2)
    }
}

四則演算を行うメソッドはジェネリックなメソッドにすると定義がややこしく見えますが、使い方は簡単。 また、Groovy の演算子オーバーロード機能によって、それぞれ +, -, *, / 演算子による式として実行できます:

@GrabResolver('http://www5.ocn.ne.jp/~coast/repo/')
@Grab('org.waman.math:wamans-math:0.0.1')

import org.waman.math.FieldCategory
import org.apache.commons.math.complex.Complex

def c0 = new Complex(0d, 0d)    // 0
def c1 = new Complex(1d, 0d)    // 1
def c2 = new Complex(1d, 2d)    // 1+2i
def c3 = new Complex(3d, 4d)    // 3+4i

use(FieldCategory){
    // 零元、単位元の確認
    assert c0.isZero()
    assert !c1.isZero()
    assert !c0.isOne()
    assert c1.isOne()
    
    // 加減乗除演算
    assert c2 + c3 == new Complex(4d, 6d)
    assert c2 - c3 == new Complex(-2d, -2d)
    assert c2 * c3 == new Complex(-5d, 10d)
    assert c2 / c3 == new Complex(0.44d, 0.08d)
}

カテゴリメソッドは static メソッドとしてしか定義できないのでちょっと融通が利かないところもありますが、メタクラスによるクラスの追加よりは簡単に使えますね。

入門Common Lisp―関数型4つの特徴とλ(ラムダ)計算

入門Common Lisp―関数型4つの特徴とλ(ラムダ)計算


Javaによるアルゴリズム事典

Javaによるアルゴリズム事典