Fredholm第二类积分方程的Python代码实现(2)

这是《The Numerical Solution of Integral Equations of the Second Kind》书上的例题代码实现,课本P37-P41的例题:插值退化核逼近

# -*- coding: utf-8 -*-
"""
Created on Mon Apr  9 21:42:44 2018
@author: shaowu

本代码主要运用Degenerate kernel method实现Fredholm integral equations of the second kind的求解,方程如下:
    lamda*x(t)-integrate(K(t,s)*x(s))ds=y(t),a=0<=t<=b,K(t,s)取exp(s*t)
首先,我们给定两个精确解exp(-t)cos(t)和sqrt(t),求出其对应的y(t),然后再来反解x(t).更详细说明可
参见《The Numerical Solution of Integral Equations of the Second Kind》P30-34.
"""
import sympy as sp
import scipy as scp
import numpy as np
import pandas as pd
import numpy.linalg as LA
import matplotlib.pyplot as plt
from scipy.special.orthogonal import p_roots
import time
start_time=time.time()

def gauss_xw(m=400):##默认用400个点求高斯——勒让德节点xi和权weight,并返回x和w数组
    x,w=p_roots(m+1)
    return x,w
def gauss_solve2_b(x,w,lamda,a,b,n): #参数n>=1
    """
    求解课本2.3.41式中的右端项,
    利用gauss_Legendre
    """
    c=(b-a)/2
    s=(b-a)/2*x+(a+b)/2 #把区间变化到[-1,1]
    h=(b-a)/(n)
    t=[a+i*h for i in range(0,n+1)] #等距划分a=t0<t1<...<tn=b

    return [((w*c*lamda*scp.exp(-s)*scp.cos(s)*scp.exp(s*i)).sum()-
            sum([c*w[k]*sum([c*w[j]*scp.exp(s[k]*s[j])*scp.exp(-s[j])*scp.cos(s[j])*scp.exp(i*s[k]) for j in range(len(s))]) for k in range(len(s))]))
            for i in t],\
           [((w*c*lamda*scp.sqrt(s)*scp.exp(s*i)).sum()-
            sum([c*w[k]*sum([c*w[j]*scp.exp(s[k]*s[j])*scp.sqrt(s[j])*scp.exp(i*s[k]) for j in range(len(s))]) for k in range(len(s))]))
            for i in t]

def hat_f(j,x,a,b):
    """
    定义hat函数(下面的积分是直接调用这个函数,建议分段来积分,而不是带有绝对值abs函数在里面)
    """
    h=(b-a)/(n)
    t=[a+i*h for i in range(0,n+1)]
    if j==0:
        if x>=t[0] and x<=t[1]:
            return 1-abs(x-t[0])/h
        else:
            return 0
    if j==n:
        if t[n-1]<=x and x<=t[n]:
            return 1-abs(x-t[n])/h
        else:
            return 0
    if j>0 and j<n:
        if t[j-1]<=x and x<=t[j+1]:
            return 1-abs(x-t[j])/h
        else:
            return 0
def elements_of_matrix(x,w,i,j,t,a,b,n):#
    """
    求系数矩阵中的元素,
    (其中的hat_f函数建议分段来积分,这里我直接调用,对第一个解,误差没有影响的,但对第二个的误差有影响)
    """
    #h=(b-a)/(n)
    if j==0:
        #c=h/2;s=h/2*x+(t[0]+t[1])/2 #区间变化
        return -scp.integrate.quad(lambda x:hat_f(j,x,a,b)*scp.exp(t[i]*x),t[0],t[1])[0]
        #return -sum([w[k]*c*hat_f(j,s[k],a,b)*scp.exp(t[i]*s[k]) for k in range(len(s))])
    elif j==n:
        #c=h/2;s=h/2*x+(t[n-1]+t[n])/2 #区间变化
        return -scp.integrate.quad(lambda x:hat_f(j,x,a,b)*scp.exp(t[i]*x),t[n-1],t[n])[0]
        #return -sum([w[k]*c*hat_f(j,s[k],a,b)*scp.exp(t[i]*s[k]) for k in range(len(s))])
    else:
        #c=h;s=h*x+(t[j-1]+t[j+1])/2 #区间变化
        return -scp.integrate.quad(lambda x:hat_f(j,x,a,b)*scp.exp(t[i]*x),t[j-1],t[j+1])[0]
        #return -sum([w[k]*c*hat_f(j,s[k],a,b)*scp.exp(t[i]*s[k]) for k in range(len(s))])
def solve2_AC(x,w,lamda,a,b,n,f1,f2):
    """
    求解C
    """
    A=[]
    h=(b-a)/(n)
    t=[a+i*h for i in range(0,n+1)] #等距划分a=t0<t1<...<tn<tn+1=b
 #   A.append([-scp.integrate.quad(lambda x:(1-abs(x-t[j])/h)*scp.exp(t[0]*x),t[0],t[1])[0] for j in range(n+1)]) #计算i=0时的
    for i in range(0,n+1):
       # guodu=[-scp.integrate.quad(lambda x:(1-abs(x-t[0])/h)*scp.exp(t[i]*x),t[0],t[1])[0]]+\
        guodu=[elements_of_matrix(x,w,i,j,t,a,b,n) for j in range(0,n+1)]#+\
               #   [-scp.integrate.quad(lambda x:(1-abs(x-t[n])/h)*scp.exp(t[i]*x),t[n-1],t[n])[0]]
        A.append(guodu)
   # A.append([-scp.integrate.quad(lambda x:(1-abs(x-t[j])/h)*scp.exp(t[n]*x),t[n-1],t[n])[0] for j in range(n+1)])  #计算i=n时的
    A=np.array(A)

    for i in range(0,n+1):
        A[i][i]=lamda+A[i][i]
    
    C1=np.linalg.solve(A,f1) #求解C
    C2=np.linalg.solve(A,f2)
    return C1,C2
def solve2_xn(lamda,a,b,n,c1,c2):
    """
    这里计算xn(t);xnt1和xnt2分别对应xt1=exp(-t)*cos(t)和xt2=sqrt(t)的情况.
    为了计算范数,这里把t属于[a,b]进了行离散
    结果返回误差E1和E2
    """
    tt=np.array([i for i in np.arange(a+0.1,b,0.1)])
    xt1=scp.exp(-tt)*scp.cos(tt)  ##第一个精确解xt1
    xt2=scp.sqrt(tt)   ##第二个精确解xt2
    xnt1=[];xnt2=[]
    #这部分代码是用scipy中的数值积分求对应的y1和y2,和上一部分的相差不大
    for j in tt:
        m1=0;m2=0
        for i in range(0,n+1):
            m1=m1+c1[i]*hat_f(i,j,a,b)
            m2=m2+c2[i]*hat_f(i,j,a,b)
        xnt1.append((m1+lamda*scp.exp(-j)*scp.cos(j)-
            scp.integrate.quad(lambda x:scp.exp(x*j)*scp.exp(-x)*scp.cos(x),a,b)[0])/lamda)
        xnt2.append((m2+lamda*scp.sqrt(j)-
            scp.integrate.quad(lambda x:scp.exp(x*j)*scp.sqrt(x),a,b)[0])/lamda)
    
    
    E1=LA.norm(xt1-xnt1,np.inf)  ##计算无穷范数
    E2=LA.norm(xt2-xnt2,np.inf)
    """
    #如果n=10,那么就画误差图
    plt.plot(tt,xt1,'*--',tt,xnt1,'-')
    plt.plot(t,xt2-xnt2,'--r',label='x2')
    plt.title('Figure1.(where a=0,b=1,n=10,lambda=5)')
    plt.xlabel('t')
    plt.ylabel('error')
    plt.legend()
    """
    return E1,E2
if __name__ == '__main__':
    
    print('******************************程序入口*******************************')
    lamda=int(input('pleas input lambda:'))
    n=int(input('please input degree n:'))
    a=int(input('please input the left value of interval:'))
    b=int(input('please input the right value of interval:'))
    m=int(input('please input the node of Gauss_Legendre:'))
    print('计算中...')
    x,w=gauss_xw(m)
    f1,f2=gauss_solve2_b(x,w,lamda,a,b,n)
    C1,C2=solve2_AC(x,w,lamda,a,b,n,f1,f2)
    E1,E2=solve2_xn(lamda,a,b,n,C1,C2)
    print('all_cost_time:',time.time()-start_time)
运行结果:

自己试一试就出来了,,,

 
 



猜你喜欢

转载自blog.csdn.net/wushaowu2014/article/details/80501790
今日推荐