高斯-勒让德积分——MATLAB&Python混合实现

高斯-勒让德积分

前言

一种很NB的数值积分。原理我们就不多说了,这里只介绍怎么直接拿来用
核心问题是如何获取系数表。

参数介绍

对于函数 f(x),积分区间为 ab,求在这一区间上的定积分。
在区间 (a, b) 上面,取一系列点 xi,其集合记为 X
那么这一定积分可以表示为:
∫ a b f ( x ) d x = ∑ i = 1 n W [ i ] ⋅ f ( X [ i ] ) \int_a^b f(x) dx = \sum_{i=1}^{n} W[i] \cdot f(X[i]) abf(x)dx=i=1nW[i]f(X[i])
其中,我们取了 n 个点(这里要求 f(x)n 阶可导)。W 是权重,指每个取点 xi 对应的权重因子 wi

系数表获取

好,明白了 XW 的含义之后,那么现在的问题就是如何获取这些数据。

对于一般的函数 f,初始的积分区间 (a, b) 是任意的,但我们下面求的 X 是限制积分区间为 (-1, 1) 。二者可以直接转化:
X n e w = X ⋅ b − a 2 + a + b 2 X_{new} = X \cdot \frac{b-a}{2} + \frac{a+b}{2} Xnew=X2ba+2a+b
同时 W 也要相应做出改变,因为积分长度变了:
W n e w = W ⋅ b − a 2 W_{new} = W \cdot \frac{b-a}{2} Wnew=W2ba

Matlab 代码,获取 XW

f = fopen('data.txt', 'wt');   % 打开准备写入数据的文件

for n = 1:20
    syms x
    y = (x^2-1)^n;          % 构造多项式 
    yx= diff(y,x, n);       % 求导
    Xs= solve(yx==0, x);    % 求解,得到所求xs

    Xs = double(Xs)';       % xs化为小数,并转置
    temp = diff(yx, x) /2^n /factorial(n);
    Ws = (2*ones(1, length(Xs)) ./(1-Xs.^2) ./(double(subs(temp, Xs)).^2)); % 得到Ws

    % 保存数据
    fprintf(f, '%.16f ',Xs);   % 保存xs
    fprintf(f, '\n');
    fprintf(f, '%.16f ',Ws);   % 保存ws
    fprintf(f, '\n\n');
    fprintf('n = %d,\tresult = %d\n\n', n, length(Xs))    % 结果展示
end

fclose(f);  % 关闭文件

Python 应该也能搞这个?但是肯定不如 Matlab 来得方便来的快,而且远不如 Matlab 强♂大
其中,我设定的 n 范围为 1 到 20。其实这个完全可以更大一些,我一直用的是 n 到 100 的数据表。但是没这个必要,因为精度已经够了…
另外推荐一个在线运行matlab,但需要使用 mathworks 账号登录。

结果大概是这样的:
高斯-勒让德积分——MATLAB&Python混合实现_第1张图片
这是一件一劳永逸的事情。这个数据表以后永远都能直接拿来用

如果不想用 Matlab 再跑,可以直接把下面这个复制到 data.txt
这是 n 从 1 到 20 的:

0 
2 

-0.57735026918962573106 0.57735026918962573106 
1 1 

0 -0.77459666924148340428 0.77459666924148340428 
0.88888888888888883955 0.55555555555555558023 0.55555555555555558023 

0.33998104358485625731 0.86113631159405257254 -0.33998104358485625731 -0.86113631159405257254 
0.65214515486254609478 0.34785484513745384971 0.65214515486254609478 0.34785484513745384971 

0 0.53846931010568310771 0.9061798459386639637 -0.53846931010568310771 -0.9061798459386639637 
0.5688888888888888884 0.47862867049936641539 0.23692688505618916817 0.47862867049936641539 0.23692688505618916817 

0.23861918608319690471 0.66120938646626448154 0.93246951420315205006 -0.23861918608319690471 -0.66120938646626448154 -0.93246951420315205006 
0.46791393457269103706 0.36076157304813866178 0.17132449237917021789 0.46791393457269103706 0.36076157304813866178 0.17132449237917021789 

0 0.40584515137739718416 0.74153118559939446008 0.94910791234275848627 -0.40584515137739718416 -0.74153118559939446008 -0.94910791234275848627 
0.41795918367346940325 0.38183005050511892309 0.27970539148927664463 0.12948496616886978616 0.38183005050511892309 0.27970539148927664463 0.12948496616886978616 

-0.18343464249564980784 -0.52553240991632899082 -0.79666647741362672797 -0.96028985649753628717 0.18343464249564980784 0.52553240991632899082 0.79666647741362672797 0.96028985649753628717 
0.36268378337836199021 0.31370664587788732458 0.22238103445337450981 0.10122853629037611989 0.36268378337836199021 0.31370664587788732458 0.22238103445337450981 0.10122853629037611989 

0 -0.32425342340380891581 -0.61337143270059035771 -0.83603110732663576954 -0.96816023950762608585 0.32425342340380891581 0.61337143270059035771 0.83603110732663576954 0.96816023950762608585 
0.33023935500125978226 0.31234707704000286288 0.26061069640293549332 0.18064816069485745142 0.081274388361574384509 0.31234707704000286288 0.26061069640293549332 0.18064816069485745142 0.081274388361574384509 

-0.14887433898163121571 -0.4333953941292472134 -0.67940956829902443559 -0.86506336668898453635 -0.97390652851717174343 0.14887433898163121571 0.4333953941292472134 0.67940956829902443559 0.86506336668898453635 0.97390652851717174343 
0.29552422471475287002 0.26926671930999634963 0.21908636251598201383 0.14945134915058055913 0.06667134430868815187 0.29552422471475287002 0.26926671930999634963 0.21908636251598201383 0.14945134915058055913 0.06667134430868815187 

0 -0.26954315595234495939 -0.51909612920681180714 -0.73015200557404935644 -0.88706259976809531675 -0.97822865814605697299 0.26954315595234495939 0.51909612920681180714 0.73015200557404935644 0.88706259976809531675 0.97822865814605697299 
0.27292508677790061622 0.26280454451024665152 0.23319376459199050999 0.18629021092773420665 0.1255803694649045843 0.055668567116173711673 0.26280454451024665152 0.23319376459199050999 0.18629021092773420665 0.1255803694649045843 0.055668567116173711673 

0.12523340851146891328 0.36783149899818018413 0.58731795428661748293 0.76990267419430469253 0.90411725637047490878 0.98156063424671924356 -0.12523340851146891328 -0.36783149899818018413 -0.58731795428661748293 -0.76990267419430469253 -0.90411725637047490878 -0.98156063424671924356 
0.24914704581340277323 0.23349253653835483346 0.20316742672306589701 0.16007832854334622108 0.10693932599531838501 0.047175336386511806941 0.24914704581340277323 0.23349253653835483346 0.20316742672306589701 0.16007832854334622108 0.10693932599531838501 0.047175336386511806941 

0 0.2304583159551348015 0.44849275103644686835 0.6423493394403402279 0.80157809073330987815 0.91759839922297792292 0.98418305471858813505 -0.2304583159551348015 -0.44849275103644686835 -0.6423493394403402279 -0.80157809073330987815 -0.91759839922297792292 -0.98418305471858813505 
0.23255155323087389752 0.22628318026289725995 0.20781604753688848186 0.17814598076194573806 0.13887351021978724952 0.092121499837728521021 0.040484004765315960428 0.22628318026289725995 0.20781604753688848186 0.17814598076194573806 0.13887351021978724952 0.092121499837728521021 0.040484004765315960428 

0.10805494870734366764 0.31911236892788974462 0.51524863635815409957 0.68729290481168547888 0.82720131506976501967 0.92843488366357351804 0.98628380869681231413 -0.10805494870734366764 -0.31911236892788974462 -0.51524863635815409957 -0.68729290481168547888 -0.82720131506976501967 -0.92843488366357351804 -0.98628380869681231413 
0.21526385346315776714 0.20519846372129557643 0.18553839747793779424 0.1572031671581935186 0.12151857068790318517 0.080158087159760194051 0.035119460331751908844 0.21526385346315776714 0.20519846372129557643 0.18553839747793779424 0.1572031671581935186 0.12151857068790318517 0.080158087159760194051 0.035119460331751908844 

0 0.20119409399743451439 0.39415134707756338539 0.57097217260853883047 0.72441773136017006962 0.84820658341042720618 0.93727339240070595139 0.98799251802048537741 -0.20119409399743451439 -0.39415134707756338539 -0.57097217260853883047 -0.72441773136017006962 -0.84820658341042720618 -0.93727339240070595139 -0.98799251802048537741 
0.20257824192556128651 0.19843148532711157861 0.18616100001556223908 0.16626920581699392021 0.13957067792615429624 0.10715922046717193949 0.070366047488108041108 0.030753241996117359341 0.19843148532711157861 0.18616100001556223908 0.16626920581699392021 0.13957067792615429624 0.10715922046717193949 0.070366047488108041108 0.030753241996117359341 

0.095012509837637440513 0.28160355077925891543 0.45801677765722736968 0.61787624440264377057 0.75540440835500299865 0.8656312023878317552 0.94457502307323260027 0.98940093499164993851 -0.095012509837637440513 -0.28160355077925891543 -0.45801677765722736968 -0.61787624440264377057 -0.75540440835500299865 -0.8656312023878317552 -0.94457502307323260027 -0.98940093499164993851 
0.18945061045506850217 0.18260341504492361153 0.16915651939500253587 0.14959598881657673597 0.12462897125553387689 0.09515851168249277181 0.062253523938647865876 0.027152459411754120699 0.18945061045506850217 0.18260341504492361153 0.16915651939500253587 0.14959598881657673597 0.12462897125553387689 0.09515851168249277181 0.062253523938647865876 0.027152459411754120699 

0 0.17848418149584785453 0.35123176345387630004 0.51269053708647693846 0.65767115921669072609 0.78151400389680136804 0.88023915372698591231 0.95067552176876779502 0.9905754753144173641 -0.17848418149584785453 -0.35123176345387630004 -0.51269053708647693846 -0.65767115921669072609 -0.78151400389680136804 -0.88023915372698591231 -0.95067552176876779502 -0.9905754753144173641 
0.1794464703562065333 0.17656270536699264495 0.16800410215645003587 0.15404576107681028363 0.13513636846852550288 0.11188384719340399576 0.08503614831717916378 0.055459529373987168088 0.024148302868547827371 0.17656270536699264495 0.16800410215645003587 0.15404576107681028363 0.13513636846852550288 0.11188384719340399576 0.08503614831717916378 0.055459529373987168088 0.024148302868547827371 

-0.084775013041735305941 -0.25188622569150548314 -0.41175116146284262975 -0.55977083107394753902 -0.69168704306035322382 -0.80370495897252314244 -0.89260246649755570214 -0.95582394957139771297 -0.99156516842093089803 0.084775013041735305941 0.25188622569150548314 0.41175116146284262975 0.55977083107394753902 0.69168704306035322382 0.80370495897252314244 0.89260246649755570214 0.95582394957139771297 0.99156516842093089803 
0.16914238296314360044 0.16427648374583270208 0.15468467512626524196 0.14064291467065065389 0.12255520671147844547 0.10094204410628714041 0.076425730254889065463 0.049714548894969852466 0.021616013526483436602 0.16914238296314360044 0.16427648374583270208 0.15468467512626524196 0.14064291467065065389 0.12255520671147844547 0.10094204410628714041 0.076425730254889065463 0.049714548894969852466 0.021616013526483436602 

0 -0.16035864564022536682 -0.31656409996362983028 -0.46457074137596093832 -0.60054530466168098979 -0.72096617733522938565 -0.82271465653714281885 -0.90315590361481790094 -0.96020815213483001749 -0.99240684384358435199 0.16035864564022536682 0.31656409996362983028 0.46457074137596093832 0.60054530466168098979 0.72096617733522938565 0.82271465653714281885 0.90315590361481790094 0.96020815213483001749 0.99240684384358435199 
0.16105444984878369841 0.15896884339395436769 0.15276604206585966961 0.14260670217360663092 0.12875396253933624191 0.11156664554733400352 0.091490021622450012906 0.069044542737641226293 0.044814226765699613497 0.019461788229726644656 0.15896884339395436769 0.15276604206585966961 0.14260670217360663092 0.12875396253933624191 0.11156664554733400352 0.091490021622450012906 0.069044542737641226293 0.044814226765699613497 0.019461788229726644656 

0.076526521133497338312 0.2277858511416450682 0.37370608871541954876 0.5108670019508271265 0.63605368072651502498 0.74633190646015079572 0.83911697182221878233 0.91223442825132594614 0.96397192727791380928 0.99312859918509488466 -0.076526521133497338312 -0.2277858511416450682 -0.37370608871541954876 -0.5108670019508271265 -0.63605368072651502498 -0.74633190646015079572 -0.83911697182221878233 -0.91223442825132594614 -0.96397192727791380928 -0.99312859918509488466 
0.15275338713072586505 0.14917298647260374134 0.14209610931838206893 0.13168863844917663708 0.11819453196151842589 0.10193011981724042769 0.083276741576704782499 0.062672048334109053958 0.040601429800386917846 0.017614007139152162984 0.15275338713072586505 0.14917298647260374134 0.14209610931838206893 0.13168863844917663708 0.11819453196151842589 0.10193011981724042769 0.083276741576704782499 0.062672048334109053958 0.040601429800386917846 0.017614007139152162984 

例如,对 e 指数积分,从 -1 到 1。其真实值为 2.3504023872876028
当 n=1 时,
∫ − 1 1 exp ⁡ ( x ) d x = 2 ⋅ exp ⁡ ( 0 ) = 2 \int_{-1}^1 \exp(x) dx = 2 \cdot \exp(0) = 2 11exp(x)dx=2exp(0)=2
n = 2 时:
∫ − 1 1 exp ⁡ ( x ) d x = 1 ⋅ exp ⁡ ( − 0.577 ) + 1 ⋅ exp ⁡ ( 0.577 ) = 2.342 \int_{-1}^1 \exp(x) dx = 1 \cdot \exp(-0.577) + 1 \cdot \exp(0.577) = 2.342 11exp(x)dx=1exp(0.577)+1exp(0.577)=2.342
精度立马就上来了。
我记得这个积分的精度是 n,恐怖如斯。

普适化使用

现在数据保存在 data.txt 中,先读取:
Python 代码:

import numpy as np

fi = open('data.txt', 'r')
s  = fi.read()
xyall = s.split('\n')
fi.close()

coefficients_all = {}

for n in range(1, round(len(xyall)/3)):
    x=xyall[3*n-3].split()
    Xs = np.asarray(x, dtype=np.float64)
    w=xyall[3*n-2].split()
    Ws = np.asarray(w, dtype=np.float64)

    if len(x)==n and len(w)==n:
        coefficients_all.update({n:np.array([Xs,Ws])})

好,现在系数表就被提取到 coefficients_all 里面了
使用方法:

def gausf(f, a=0, b=1, n=10):
    '''## 通用的一维高斯定积分
    `input`:    函数 `f`, 积分边界 `a`, `b`,精度 `n`
    `return`:   定积分结果
    '''
    xs=(a+b)/2+(b-a)/2*coefficients_all[n][0]
    result=(coefficients_all[n][1]*f(xs)).sum()

    return result*(b-a)/2

测试:

>>> import numpy as np
>>> np.exp(10) - np.exp(-1)
>>> 22026.097915365546

>>> gausf(np.exp, -1,10, n=1)
>>> 990.18844430574
>>> gausf(np.exp, -1,10, n=5)
>>> 22007.439661681645
>>> gausf(np.exp, -1,10, n=10)
>>> 22026.097914828657
>>> gausf(np.exp, -1,10, n=20)
>>> 22026.097915365546

我原称之为:最小的计算量最大的精度
数学家真的nb

Matlab 代码:

f = fopen('data.txt', 'wt');   % 打开准备写入数据的文件

for n = 1:20
    syms x
    y = (x^2-1)^n;          % 构造多项式 
    yx= diff(y,x, n);       % 求导
    Xs= solve(yx==0, x);    % 求解,得到所求xs

    Xs = double(Xs)';       % xs化为小数,并转置
    temp = diff(yx, x) /2^n /factorial(n);
    Ws = (2*ones(1, length(Xs)) ./(1-Xs.^2) ./(double(subs(temp, Xs)).^2)); % 得到Ws

    % 保存数据
    fprintf(f, '%.16f ',Xs);   % 保存xs
    fprintf(f, '\n');
    fprintf(f, '%.16f ',Ws);   % 保存Ws
    fprintf(f, '\n\n');
    fprintf('n = %d,\tresult = %d\n\n', n, length(Xs))    % 结果展示
end

fclose(f);  % 关闭文件

整体的 Python 代码:(附有二重三重定积分
GitHub链接

import numpy as np

# 读取高斯积分的系数表
def read_gauss_data() -> dict:
    '''## 读取高斯系数数据
    `return`: `coefficients_all` : `dict`
    '''
    fi=open('./Mylibs/Data/Const_gauss.txt', 'r')
    s=fi.read()
    xyall=s.split('\n')
    fi.close()

    coefficients_all={}

    for n in range(1, round(len(xyall)/3)):
        x=xyall[3*n-3].split()
        Xs = np.asarray(x, dtype=np.float64)
        w=xyall[3*n-2].split()
        Ws = np.asarray(w, dtype=np.float64)

        if len(x)==n and len(w)==n:
            coefficients_all.update({n:np.array([Xs,Ws])})

    return coefficients_all

coefficients_all = read_gauss_data()


# 通用一维定积分
def gausf(f, a=0, b=1, n=10):
    '''## 通用的一维高斯定积分
    `input`:    函数 `f`, 积分边界 `a`, `b`,精度 `n`
    `return`:   定积分结果
    '''
    xs=(a+b)/2+(b-a)/2*coefficients_all[n][0]
    result=(coefficients_all[n][1]*f(xs)).sum()

    return result*(b-a)/2

# 测试:
print('真实值:\t{}'.format(np.exp(10) - np.exp(-1)))
for n in [1,5,10,20]:
    print('n={}:\t{}'.format(n, gausf(np.exp, -1, 10, n=n)))


# 通用的二维高斯定积分
def gausf2(f, xa=0, xb=1, ya=0, yb=1, n=10):
    '''## 通用的二维高斯定积分
    `input`:    函数 `f`, 积分边界 `xa`, `xb`, `ya`, `yb`,精度 `n`
    `return`:   定积分结果
    '''
    if n not in coefficients_all:
        print('not a correct n')
        return None

    xs = (xa+xb)/2+(xb-xa)/2*coefficients_all[n][0]
    ys = (ya+yb)/2+(yb-ya)/2*coefficients_all[n][0]
    wx = coefficients_all[n][1]*(xb-xa)/2
    wy = coefficients_all[n][1]*(yb-ya)/2

    xys = np.meshgrid(xs, ys)   # 取点
    wws = np.meshgrid(wx, wy)   # 权重
    result = (wws[0] *wws[1] *f(xys[0], xys[1])).sum()

    return result


# 通用的三维高斯定积分
def gausf3(f, xa=0, xb=1, ya=0, yb=1, za=0, zb=1, n=10):
    '''## 通用的三维高斯定积分
    `input`:    函数 `f`, 积分边界 `xa`, `xb`, `ya`, `yb`, `za`, `zb`, 精度 `n`
    `return`:   定积分结果
    '''
    if n not in coefficients_all:
        print('not a correct n')
        return None

    xs = (xa+xb)/2+(xb-xa)/2*coefficients_all[n][0]
    ys = (ya+yb)/2+(yb-ya)/2*coefficients_all[n][0]
    zs = (za+zb)/2+(zb-za)/2*coefficients_all[n][0]
    wx = coefficients_all[n][1]*(xb-xa)/2
    wy = coefficients_all[n][1]*(yb-ya)/2
    wz = coefficients_all[n][1]*(zb-za)/2

    xyzs = np.meshgrid(xs, ys, zs)   # 取点
    wwws = np.meshgrid(wx, wy, wz)   # 权重
    result = (wwws[0] *wwws[1] *wwws[2] *f(xyzs[0], xyzs[1], xyzs[2])).sum()

    return result

有问题也欢迎提出~

你可能感兴趣的:(matlab,python,开发语言)