2

編集:私はこのコードをデバッグするためにあなたを探していません。このよく知られたアルゴリズムに精通している場合は、支援できる可能性があります。アルゴリズムが係数を正しく生成することに注意してください。

この3次スプライン補間のコードは線形スプラインを生成しており、その理由は(まだ)理解できないようです。アルゴリズムはBurdenの数値解析に基づいています。これはここの擬似コードとほぼ同じです。、またはコメント内のリンクからその本を見つけることができます(第3章を参照してください、とにかく持っている価値があります)。コードは正しい係数を生成しています。私はその実装を誤解していると思います。フィードバックをいただければ幸いです。また、私はプログラミングに不慣れなので、コーディングがどれほど悪いかについてのフィードバックも歓迎します。線形システムの写真をh、a、cでアップロードしようとしましたが、新しいユーザーとしてはできません。アルゴリズムが解く、var alphaによって設定される三重対角線形システムのビジュアルが必要な場合は、本のコメントのリンクを参照してください。第3章を参照してください。システムは厳密に対角的に支配的であるため、一意の解c0、...、cnが存在します。ci値がわかれば、他の係数が続きます。

import matplotlib.pyplot as plt

# need some zero vectors...
def zeroV(m):
    z = [0]*m
    return(z)

 #INPUT: n; x0, x1, ... ,xn; a0 = f(x0), a1 =f(x1), ... , an = f(xn).
 def cubic_spline(n, xn, a, xd):
    """function cubic_spline(n,xn, a, xd) interpolates between the knots
       specified by lists xn and a. The function computes the coefficients
       and outputs the ranges of the piecewise cubic splines."""        

    h = zeroV(n-1)

    # alpha will be values in a system of eq's that will allow us to solve for c
    # and then from there we can find b, d through substitution.
    alpha = zeroV(n-1)

    # l, u, z are used in the method for solving the linear system
    l = zeroV(n+1)
    u = zeroV(n)
    z = zeroV(n+1)

    # b, c, d will be the coefficients along with a.
    b = zeroV(n)     
    c = zeroV(n+1)
    d = zeroV(n)    

for i in range(n-1):
    # h[i] is used to satisfy the condition that 
    # Si+1(xi+l) = Si(xi+l) for each i = 0,..,n-1
    # i.e., the values at the knots are "doubled up"
    h[i] = xn[i+1]-xn[i]  

for i in range(1, n-1):
    # Sets up the linear system and allows us to find c.  Once we have 
    # c then b and d follow in terms of it.
    alpha[i] = (3./h[i])*(a[i+1]-a[i])-(3./h[i-1])*(a[i] - a[i-1])

# I, II, (part of) III Sets up and solves tridiagonal linear system...
# I   
l[0] = 1      
u[0] = 0      
z[0] = 0

# II
for i in range(1, n-1):
    l[i] = 2*(xn[i+1] - xn[i-1]) - h[i-1]*u[i-1]
    u[i] = h[i]/l[i]
    z[i] = (alpha[i] - h[i-1]*z[i-1])/l[i]

l[n] = 1
z[n] = 0
c[n] = 0

# III... also find b, d in terms of c.
for j in range(n-2, -1, -1):      
    c[j] = z[j] - u[j]*c[j+1]
    b[j] = (a[j+1] - a[j])/h[j] - h[j]*(c[j+1] + 2*c[j])/3.
    d[j] = (c[j+1] - c[j])/(3*h[j])   

# This is my only addition, which is returning values for Sj(x). The issue I'm having
# is related to this implemention, i suspect.
for j in range(n-1): 
    #OUTPUT:S(x)=Sj(x)= aj + bj(x - xj) + cj(x - xj)^2 + dj(x - xj)^3; xj <= x <= xj+1)
    return(a[j] + b[j]*(xd - xn[j]) + c[j]*((xd - xn[j])**2) + d[j]*((xd - xn[j])**3))

退屈な、またはやり過ぎのために...

これがテスト用のコードです。間隔はx:[1、9]、y:[0、19.7750212]です。テスト関数はxln(x)であるため、1から開始し、.1ずつ増加して9になります。

ln = [] 
ln_dom = [] 
cub = [] 
step = 1. 
X=[1., 9.] 
FX=[0, 19.7750212]
while step <= 9.:
    ln.append(step*log(step))
    ln_dom.append(step)
    cub.append(cubic_spline(2, x, fx, step))
    step += 0.1

...そしてプロット用:

plt.plot(ln_dom, cub, color='blue')
plt.plot(ln_dom, ln, color='red')
plt.axis([1., 9., 0, 20], 'equal')
plt.axhline(y=0, color='black')
plt.axvline(x=0, color='black')
plt.show()
4

2 に答える 2

4

わかりました、これを機能させました。問題は私の実装にありました。スプラインが連続的にではなく個別に構築されるという別のアプローチで動作するようになりました。これは、最初にスプライン多項式の係数(作業の99%)を作成し、次にそれらを実装する方法によって、完全に機能する3次スプライン補間です。明らかに、これがそれを行う唯一の方法ではありません。私は別のアプローチに取り組み、興味があればそれを投稿するかもしれません。コードを明確にする1つのことは、解かれた線形システムの画像ですが、担当者が10になるまで写真を投稿できません。アルゴリズムについて詳しく知りたい場合は、の教科書のリンクを参照してください。上記のコメント。

import matplotlib.pyplot as plt
from pylab import arange
from math import e
from math import pi
from math import sin
from math import cos
from numpy import poly1d

# need some zero vectors...
def zeroV(m):
    z = [0]*m
    return(z)

#INPUT: n; x0, x1, ... ,xn; a0 = f(x0), a1 =f(x1), ... , an = f(xn).
def cubic_spline(n, xn, a):
"""function cubic_spline(n,xn, a, xd) interpolates between the knots
   specified by lists xn and a. The function computes the coefficients
   and outputs the ranges of the piecewise cubic splines."""        

    h = zeroV(n-1)

    # alpha will be values in a system of eq's that will allow us to solve for c
    # and then from there we can find b, d through substitution.
    alpha = zeroV(n-1)

    # l, u, z are used in the method for solving the linear system
    l = zeroV(n+1)
    u = zeroV(n)
    z = zeroV(n+1)

    # b, c, d will be the coefficients along with a.
    b = zeroV(n)     
    c = zeroV(n+1)
    d = zeroV(n)    

    for i in range(n-1):
        # h[i] is used to satisfy the condition that 
        # Si+1(xi+l) = Si(xi+l) for each i = 0,..,n-1
        # i.e., the values at the knots are "doubled up"
        h[i] = xn[i+1]-xn[i]  

    for i in range(1, n-1):
        # Sets up the linear system and allows us to find c.  Once we have 
        # c then b and d follow in terms of it.
        alpha[i] = (3./h[i])*(a[i+1]-a[i])-(3./h[i-1])*(a[i] - a[i-1])

    # I, II, (part of) III Sets up and solves tridiagonal linear system...
    # I   
    l[0] = 1      
    u[0] = 0      
    z[0] = 0

    # II
    for i in range(1, n-1):
        l[i] = 2*(xn[i+1] - xn[i-1]) - h[i-1]*u[i-1]
        u[i] = h[i]/l[i]
        z[i] = (alpha[i] - h[i-1]*z[i-1])/l[i]

    l[n] = 1
    z[n] = 0
    c[n] = 0

    # III... also find b, d in terms of c.
    for j in range(n-2, -1, -1):      
        c[j] = z[j] - u[j]*c[j+1]
        b[j] = (a[j+1] - a[j])/h[j] - h[j]*(c[j+1] + 2*c[j])/3.
        d[j] = (c[j+1] - c[j])/(3*h[j]) 

    # Now that we have the coefficients it's just a matter of constructing
    # the appropriate polynomials and graphing.
    for j in range(n-1):
        cub_graph(a[j],b[j],c[j],d[j],xn[j],xn[j+1])

    plt.show()

def cub_graph(a,b,c,d, x_i, x_i_1):
    """cub_graph takes the i'th coefficient set along with the x[i] and x[i+1]'th
       data pts, and constructs the polynomial spline between the two data pts using
       the poly1d python object (which simply returns a polynomial with a given root."""

    # notice here that we are just building the cubic polynomial piece by piece
    root = poly1d(x_i,True)
    poly = 0
    poly = d*(root)**3
    poly = poly + c*(root)**2
    poly = poly + b*root
    poly = poly + a

    # Set up our domain between data points, and plot the function
    pts = arange(x_i,x_i_1, 0.001)
    plt.plot(pts, poly(pts), '-')
    return

テストしたい場合は、開始に使用できるデータをいくつか示します。これは、0から1までの関数1.6e ^(-2x)sin(3 * pi * x)から取得されます。

# These are our data points
x_vals = [0, 1./6, 1./3, 1./2, 7./12, 2./3, 3./4, 5./6, 11./12, 1]

# Set up the domain
x_domain = arange(0,2, 1e-2)

fx = zeroV(10)

# Defines the function so we can get our fx values
def sine_func(x):
    return(1.6*e**(-2*x)*sin(3*pi*x))

for i in range(len(x_vals)):
    fx[i] = sine_func(x_vals[i])

# Run cubic_spline interpolant.
cubic_spline(10,x_vals,fx)
于 2012-03-30T23:10:01.933 に答える
1

コーディングスタイルに関するコメント:


  • コメントとドキュメントはどこにありますか?少なくとも、関数のドキュメントを提供して、関数がどのように使用されるかを人々が理解できるようにします。

それ以外の:

def cubic_spline(xx,yy):

次のように書いてください。

def cubic_spline(xx, yy):
    """function cubic_spline(xx,yy) interpolates between the knots
    specified by lists xx and yy. The function returns the coefficients
    and ranges of the piecewise cubic splines."""

  • *リストの演算子を使用して、繰り返される要素のリストを作成できます。

このような:

>>> [0] * 10
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

zeroV関数を。に置き換えることができるようにします[0] * m

可変タイプではこれを行わないでください!(特にリスト)。

>>> inner_list = [1,2,3]
>>> outer_list = [inner_list] * 3
>>> outer_list
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
>>> inner_list[0] = 999
>>> outer_list
[[999, 2, 3], [999, 2, 3], [999, 2, 3]] # wut

  • 数学はおそらくnumpyまたはを使用して行う必要がありscipyます。

それとは別に、DavidGoodgerによる慣用的なPythonを読む必要があります

于 2012-03-26T06:49:50.247 に答える