Kodama's home / tips.

Rubyによる 超準解析 クラス.(HyperRael,MathExt)

超実数体とは,(大雑把に云えば) 実数体にライプニッツ的な無限小を添加して出来る体のことだ. 微分等, 通常の実数では limit を使う場面で, 超実数体内部の四則演算として直接求めることが出来る.

超準的な計算では, 無限小や∞の強さもわかるので 無限小/無限小, 無限小*∞, ∞/∞ 等の計算が矛盾無く解釈可能となる. ただし単なる体なので, 真の0(無限小でなく) については, 0*∞=0 で, 0/0 や 1/0 は定義されない. この点は IEEE754 的な浮動小数点計算で 1.0/0.0 で Infinity を返すような気持の悪さは解消できる.

Ruby で 超実数(HyperReal) の計算を実行する クラスを作成. 興味がある方は polynomial-ruby.tar.gz をどうぞ.

今のところ, 四則演算に関して, 超準的な計算を実行できる. また, MathExt モジュ−ルで sin, cos, sqrt 等の初等的な関数が HyperReal, Rational, RationalPoly 等を受け付けるように拡張した. 内部では Polynomial クラスに頼っているので, polynomial と同梱している.

内部の計算では RationalPoly を使用しているので Float の場合のような 桁落ちや桁溢れの問題は無い. RationalPoly の係数も, デフォルトでは Float を Rational に変換して扱うようになっている. Float から Rational への変換では桁落ちしないようになっている.

最大の欠点は, RationalPoly の弱点を引き継いで, 四則演算をくりかえすと爆発的にデ−タ−のサイズが増してしまい 計算が遅くなる点にある. Rational と HyperReal に関しては, 精度を指定して 内部表現を簡約/近似するメソッドを用意した.

一応使えるはずだけど, まだ細かい仕様が洗練されていない. 興味がある方は使ってみて改善案等を送って頂けるとありがたい. "kodama@kobe-kosen.ac.jp" までお願いします.

例1. 0/0 , ∞/∞ の扱い.

x〜1 のときの (x^2-1)/(x^2+x-2) の値. (注1. 〜 は普通 2重波線で書き, (x)-(1) が無限小と云うこと.) x を∞にしたときの (x*x*2+x*3+4)/(x*x*5+x*6+7) の値.
##### test1.rb ファイルの内容 
require "hyperreal"

# x=1 # 通常の Integer を与える. ZeroDivisionErrorになる.
# printf "%s\n", (x*x-1)/(x*x+x-2)

x=1.0 # 通常の Float を与える.
a = x*x-1; b = x*x+x-2
printf "%s/%s=%s\n",a,b,a/b

x=HyperReal::Epsilon+1 # 無限小を加える.
a = x*x-1; b = x*x+x-2
printf "%s/%s=%s\n",a,b,a/b

x=HyperReal::Infinity # ∞
a = x*x*2+x*3+4; b = x*x*5+x*6+7
printf "%s/%s=%s\n",a,b,a/b
これを実行する.
$ ruby test1.rb
0/0=NaN  ------- Floatの計算ではダメダメ
0/0=2/3  ------- 勝利! (^_^)v
Infinity/Infinity=2/5  ------- ∞/∞ も問題無し

例2. 微分

微分は単に dx=無限小 としたときの, df/dx = (f(x+dx)-f(x))/dx の標準実数部分として計算できる. limit は不要. ライプニッツ的微分の概念をほぼそのまま実行できる事になる. まあ, Polynomial, RationalPoly クラスに derivative があるので, 多項式の微分だけが目的ならそのほうが良いはず...

###### test2.rb ファイルの内容
require "hyperreal"
require "polynomial"

f=Poly("5x^3+6x^2+7x+8"); x=2; dx=HyperReal::Epsilon
df=(f.substitute(dx+x)-f.substitute(x))
# 超準解析的に...
printf "f=%s, f'(%s)=%s\n",f, x, df/dx

# Polynomial クラスの微分で...
printf "f'=%s, f'(%s)=%s\n", f.derivative, x, f.derivative.substitute(x)
これを実行する
$ ruby test2.rb
f=5x^(3)+6x^(2)+7x+8, f'(2)=91
f'=15x^(2)+12x+7, f'(2)=91

高階自動微分

超準演算を観点を変えてみると, 高次の微分係数まで一気に求まる 高階の自動微分型とみなすことができる.

こんな風に関数を用意し, 1+epsilon を代入する.

require "hyprereal"
def f(x)
return (2*x+3)/(4*x+5)
end

x = Rational(1)
e = HyperReal::Epsilon

printf "f(1)=%s\n", f(x)
printf "f(1+e)=%s\n", f(x+e)

これを Ruby で実行してみると5/9 の結果が出て来る. f(1)=5/9 f(1+e)=5/9

ここで, HyperReal での内部表現を覗いてみよう. 1+e を (2*x+3)/(4*x+5) に代入したものがそのまま見えている. 更に, この e に関しての有理多項式を多項式近似してやる.

printf "f(1+e)=%s\n", f(x+e).to_s(false)
printf "f(1+e)=%s\n", f(x+e).approx(3).to_s(false)

実行結果.

f(1+e)=(5+2e)/(9+4e)
f(1+e)=(3645-162e+72e^(2)-32e^(3))/(6561)

この f(1+e)の HyperReal 表現を f(1+e) のテ−ラ−展開とみなす事ができ, 微分係数の指数型母関数が得られた事になるので, HyperReal を "高階の自動微分型" と考える事ができる.

printf "f(1+e)=%s\n", f(e+x).to_approx_poly.to_s("text","e",false)
実行結果は以下のようになる.
f(1+e)=5/9-2e/81+8e^(2)/729-32e^(3)/6561

つまり, 普通に四則演算を用いて関数を書けば, そのままHyperReal を与える事ができ, 高階の自動微分も行うことができるわけだ.

結局,無限小の世界では, 関数の値と関数芽の情報を区別する必要が無くなってしまうということらしい.


Kodama's home / tips.