クラス型を用いた関数の積分
C++には関数オブジェクトやテンプレートがあり、汎用的なプログラムを書くときに便利である。Pythonにおいて、クラス型を用いて同様のことを試みた。
統計計算では、確率分布関数はいくつかのパラメータを有しているのが普通であるので、パラメータ付きの関数をクラス型で表すと便利である。また、Pythonでは型は実行時に決まるので、テンプレートのように書くことができる。
次のプログラムFuncClass.pyでは、1次関数がクラス型MyFuncによって表されている。
============= FuncClass.py =================
def CalcFunc( f, x ):
print
("%f"%f.v(x))
class MyFunc:
def __init__(self, a, b):
self.a = a
self.b = b
def v(self, x):
return self.a + self.b * x
myf = MyFunc(10.0,
20.0)
print("v =
", end="")
CalcFunc(myf, 1.0)
======================================
この関数には2つのパラメータaとbがあるが、これは初期化時にメソッド__init__(self, a, b)によって設定される。クラス型MyFuncの表す関数の値は、メソッドMyFunc.v()によって与えられる。
関数CalcFunc(f, x)は、第1引数であるオブジェクトfのメソッドf.v()によってxに対する値f.v(x)を求めているので、オブジェクトfのクラス型はメソッドvを実装している必要がある。
上のプログラムを実行すると、
myf = MyFunc(10.0, 20.0)
の実行によりa=10.0, b=20.0 で初期化されたオブジェクトがmyfによって表され、myfの表す関数のx=1.0 における値が関数CalcFunc(myf, 1.0) によって表示される(図1)。
図1
上のクラス型によって関数を表す方法を用いて、パラメータをもつ関数の積分を行う例を以下に示す。積分は、ガウス・ルジャンドルの積分公式を適応的に用いる方法を使っている(岡本安晴(2010)「大学生のための心理学VC++プログラミング入門」勁草書房、pp. 113-115)。これは、積分区間によって分割点の設定を調節して計算精度を保つものであり、次のadap_gl.pyではクラス型AdapGLとして実装されている。ガウス・ルジャンドルの公式による計算はメソッドglによって行われている。このglはメソッドcalc内で呼び出されていて、メソッドcalcは再帰的呼び出しによって分割点の調節を行っている。計算は、メソッドintegralの呼び出しによって始まる。
================= adap_gl.py ==================
class AdapGL:
x = [
-9.68160239507626090E-0001,
-8.36031107326635794E-0001,
-6.13371432700590397E-0001,
-3.24253423403808929E-0001,
0.00000000000000000E+0000,
3.24253423403808929E-0001,
6.13371432700590397E-0001,
8.36031107326635794E-0001,
9.68160239507626090E-0001 ]
w = [ 8.12743883615744120E-0002,
1.80648160694857404E-0001,
2.60610696402935462E-0001,
3.12347077040002840E-0001,
3.30239355001259763E-0001,
3.12347077040002840E-0001,
2.60610696402935462E-0001,
1.80648160694857404E-0001,
8.12743883615744120E-0002 ]
def __init__(self):
pass
def gl(self, a, b):
v1 = 0.0
i_w = b - a
for i in range(0, 9):
xi =
(0.5 * i_w * AdapGL.x[i]) + (0.5 * (b + a))
v1 += AdapGL.w[i] * self.f.v(xi)
v1 = 0.5 * i_w * v1
return v1
def calc(self, s0, a, b):
s1 = self.gl( a, 0.5 * (a + b))
s2 = self.gl(0.5 * (a + b), b)
if ((abs(s0 - s1 - s2) < (1.0e-14) * abs(s1 + s2))
or
(((abs(s0) + abs(s1 + s2)) < 1.0e-14)
and
(abs(b - a) < 1.0))):
return s1 + s2
else:
s1 = self.calc(s1, a, 0.5 * (a + b))
s2 = self.calc(s2, 0.5 * (a + b), b)
return s1 + s2
def integral(self, a, b, f):
self.f = f
v = 0.0
v = self.calc( v, a, b )
return v
=========================================
上のモジュールadap_gl.pyのクラス型AdapGLによって積分
の計算を行っているのが次のプログラムCheckGauss.pyである。
============== CheckGauss.py =================
from adap_gl import AdapGL
class myfunc:
def __init__(self, a):
self.a = a
def v(self, x):
return self.a * x * x
mf = myfunc(3.0)
gl = AdapGL()
v = gl.integral(0.0,
1.0, mf)
print("v =
%f"%v)
=======================================
関数を表すオブジェクトは
my=myfunc(3.0)
によって生成されている。この関数を表すオブジェクトmfを実引数としてAdapGLのメソッドintegralが呼び出され、AdapGLのself.fにmfが設定される。self.fの表す関数の値は、fのメソッドself.f.vによって与えられているので、実引数mfにはメソッドvが実装されていなければならない。
上のプログラムCheckGauss.pyを実行すると図2の結果を得る。
図2
生成された関数 my=myfunc(3.0) の積分値
が求められていることが確認できる。
上のプログラムファイルを圧縮ファイルfunc_c_prg.zipにまとめた。圧縮ファイル名func_c_prg.zipをクリックしてダウンロードできる。プログラムは、利用者の責任において、自由に御利用下さい。