蒙特卡洛積分-重要性採樣原理及其應用

我自己是數學菜逼,所以我在學習數學之類的內容的時候,我基本上會去找視頻看,雖然視頻比較耗時間,但數學真的很難,沒辦法,菜逼一個。好在在b站上找到一位數學老師有這個視頻講解,真的救命呀!!!放下視頻鏈接https://www.bilibili.com/video/BV17D4y1o7J2?p=1&vd_source=4451d7e9f1ccf3c1318002d60666d680。下面記錄一下筆記。


蒙特卡洛積分主要原理是通過隨機抽樣來估算。假設我們有一個概率密度(分佈)函數如下,是某學校女生身高的分佈

 

假設我們想算身高平方的均值,f(x)是概率密度函數,g(x)=x2,身高平方的均值也就是

但是因爲這個積分解析式不一定能解出來,我們可以在概率密度函數的分佈中抽取樣本X,也就是在某學校女生中抽樣,然後計算g(X),進而算術平均

但在數學中如何找到可以服從概率密度分佈的樣本呢,這裏需要用到累積分佈函數

由於累積分佈函數從0到1,它的函數圖像如下

我們在累積分佈函數的縱座標上隨機取一個數i,找到它在橫座標上對應的值xi,這個xi就是符合概率密度函數的樣本了,xi的求解也就是累積分佈函數的逆函數了,這個也就是重要性採樣

到這裏就可以解出來了。

我們經常看到在圖形學中的渲染公式中那一長串的被積函數,然後就突然變成了一長串除以pdf了,那這個除以pdf是怎麼來的呢?

假設我們要求f(x)在(a,b)上的定積分(面積),g(x)是一個概率密度函數,我們可以把這個式子變形

我們可以把f(x)/g(x)看成一個整體z(x),那這樣不就是對應我們前面的列子了嗎,就相當於變成了求z(x)的均值了,然後我們就可以採樣得出結果了,有一些細節就是概率密度函數的積分爲1,也就是

然後我們的式子就變成這樣了

 對,這樣就變成了我們經常看到的除以pdf的那種樣子了。

下面舉一個實例,求解y=x2在(0,8)之間的面積,用定積分的解析式很好求,但這裏用蒙特卡洛重要採樣來解積分。首先pdf是隨便的,這裏取概率密度函數p(x)=3/8*x2,儘量貼合原積分函數,然後我們求出累積分佈函數P(x)=x3/8,按照上面的講解我們求出累積分佈函數的逆函數P-1(x)=2*x1/3。代碼中只採樣了一個點,但得到的結果還是比較準確的

#include <iostream>
#include <random>
#include <iomanip>

double random_double(double min, double max)
{
    // 使用rd來生成一個真正的隨機數生成器
    std::random_device rd;

    // 使用該隨機數生成器初始化Mersenne Twister引擎
    std::mt19937 engine(rd());

    // 創建一個分佈,在min和max之間均勻分佈
    std::uniform_real_distribution<> distrib(min, max);

    // 生成一個均勻分佈的隨機數
    return distrib(engine);
}

inline double pdf(double x)
{
    return 3 * x * x / 8;
}

int main()
{
    int N = 1;
    auto sum = 0.0;
    for (int i = 0; i < N; i++)
    {
        //這裏就是用累積分佈函數的逆函數來求解符合概率密度函數的分佈
        auto x = 2*pow(random_double(0, 1), 1.0 / 3.0);
        sum += x * x / pdf(x);
    }
    std::cout << std::fixed << std::setprecision(12);
    std::cout << "I = " << sum / N << '\n';
}

結果如下:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章