AAAアルゴリズムによる有理関数近似
概要
AAA (adaptive Antoulas–Anderson) アルゴリズムは、与えられた精度あるいは与えられた近似次数に対して有理関数近似を求めるアルゴリズムである。[1][2]このアルゴリズムは、Antoulas–Anderson[3]に倣って有理関数をbarycentric形式で表し、サポート点を段階的に追加して近似次数を高める適応的な戦略を採用することで、Padé近似等の有理近似で現れる偽の極ー零点対をほとんど回避することができるのが特徴である(らしい)。
本稿では、AAAアルゴリズムを概観する。詳細は原論文[1:1][2:1]を参照のこと。
問題設定
実軸上のある区間における
および近似したい関数
を入力データとする。
ここで考える問題は、
を満たす
を見つけることである。上式右辺をbarycentric形式と呼ぶ。また本稿では、最右辺?は極ー留数形式と呼ぶことにする。
AAAアルゴリズムの手順
AAAアルゴリズムは反復型のアルゴリズムである[1:2]。ステップ
と、その補集合
に分割する。そして、barycentric形式で定義される有理関数
を考え、重み
という線形最小二乗問題を解く。
へと書き換えられる。ここで、Loewner行列
と定義される。次に、
を行い、右特異ベクトル
のように得られる。
ステップ
が満たされたならば反復を終了し、そのときの次数は
さらに、極
の固有値として評価できる[1:4]。留数
によって計算される。
ソースコード
MATLAB版は
Python版は Julia版は でそれぞれ実装されている。ここでは、RationalFunctionApproximation.jlを使ってみる。例として、関数
を
using RationalFunctionApproximation
using CairoMakie
# 近似したい関数
f = x -> exp(-5(x+1)^2) + 2exp(-10(x-2)^2)
# 近似に用いるサンプル点を作成
x = LinRange(-4, 4, 200)
# AAAアルゴリズム
r = aaa(x, f.(x), tol=1e-8)
# 有理関数の次数、極、留数
deg = degree(r)
println("Degree: ", deg)
pol = poles(r)
res = residues(r)
# barycentric型有理関数の関数オブジェクト
f_approx1 = x -> r(x)
# 有理関数の極とその留数から有理関数を作成
f_approx2 = x -> sum(res[i] / (x - pol[i]) for i in 1:deg)
# CairoMakie を用いた可視化
xplot = LinRange(-4, 4, 500)
y_original = f.(xplot)
y_approx1 = f_approx1.(xplot)
y_approx2 = real.(f_approx2.(xplot))
fig = Figure()
ax = Axis(fig[1, 1],
xlabel = "x",
ylabel = "f(x)",
title = "Rational Approximation"
)
lines!(ax, xplot, y_original, label = "Original function", color = :blue)
lines!(ax, xplot, y_approx1, label = "AAA approximation (barycentric)", color = :orange, linestyle = :dash)
lines!(ax, xplot, y_approx2, label = "AAA approximation", color = :green, linestyle = :dot)
axislegend(ax, position = :lt)
save("aaa-figure.png", fig)
# 誤差を計算、図示
err1 = abs.(f.(xplot) - f_approx1.(xplot))
err2 = abs.(f.(xplot) - f_approx2.(xplot))
println("Max error (barycentric): ", maximum(err1))
println("Max error: ", maximum(err2))
fig = Figure()
ax = Axis(fig[1, 1],
xlabel = "x",
ylabel = "Error",
title = "Error of Rational Approximation"
)
lines!(ax, xplot, err1, label = "Error (barycentric)", color = :orange)
lines!(ax, xplot, err2, label = "Error", color = :green)
ax2 = Axis(
fig;
bbox = BBox(350, 550, 150, 350),
title = "Enlarged view",
xgridvisible = false,
ygridvisible = false,
)
lines!(ax2, xplot, err1, label = "Error (barycentric)", color = :orange)
axislegend(ax, position = :lc)
save("aaa-error.png", fig)
結果は、barycentric形式(橙)と 極ー留数形式(緑)の両方の結果を図示した。与えた精度に対して、項数は
どちらもよく近似できていることが分かる。しかし、誤差の絶対値を見てみると
barycentric形式ではほとんど指定した精度に収まっているが、極と留数を計算する段階で誤差が大きくなるようなので注意が必要である。
Discussion