迭代地细化 Metropolis 标准的 exp 边界

计算科学 优化 模拟 迭代法
2021-12-07 16:26:58

在 Monte Carlo 模拟中,使用 Metropolis 准则, 通常必须将随机数与玻尔兹曼分布进行比较,其中是模拟中两个状态之间的转换。a0a<1exp(βΔE)ΔE

一个常见的优化是检查是否,在这种情况下,肯定小于ΔE>0aexp(βΔE)

对于我的模拟,指数函数的计算似乎花费了最多的时间,我正在寻找降低成本的方法。

我想到的一种方法是基于这样一个事实,即对于偶数,泰勒级数的下限,而对于奇数,它是上限。因此,可以编写如下函数,Kk=0Kxk/k!exp(x)K


static inline int fast_metropolis(double a, double x){
    double est = 1.0 + x;
    double f = x;
    int i = 1;
    while(true){
        if(rand_num < est) return 1;
        f *= x / (i + 1);
        est += f;
        if(rand_num > est) return 0;
        f *= x / (i + 2);
        est += f;
        i += 2;
    }
    return 0;
}

不幸的是,事后看来,上面的代码并不是非常消极的论点,因为边界的绝对值增加了。

上面描述的方法是否有任何替代方法,即我们可以迭代地改进一些上限和下限,同时确保它们的绝对值正在减少?

还是我最好使用指数函数的一些“快速”估计?

1个回答

我的问题最简单的解决方案非常明显,太糟糕了,我在发布问题之前没有看到它。

您可以将的参数拆分为整数部分和小数部分。对于整数部分,可以预先计算一个查找表,而对于小数部分,您可以使用问题中描述的算法。exp(x)

下面我展示了我使用的最终代码,


static inline int fast_metropolis(double rand_num, double x){
    int exp_i = -(int)x;
    if(exp_i > 256) return rand_num < exp(x);
    double prefactor = (exp_i > 0)? exp_table[exp_i - 1]: 1.0;
    double k = x + exp_i;
    double f = k;
    double est = 1.0 + k;
    int i = 1;
    while(1){
        if(rand_num < prefactor * est) return 1;
        f *= k / (i + 1);
        est += f;
        if(rand_num > prefactor * est) return 0;
        f *= k / (i + 2);
        est += f;
        i += 2;
    }
    return 0;
}

所描述的算法在我的模拟中非常准确,只有的情况与使用标准库的函数不同。相比之下,此处的情况下有所不同,尽管它在模拟中的性能稍好一些。的参数进行均匀分布的性能测试似乎表明性能提升了 3 倍。8.4106%exp0.3%exp(x)

我不会在几天内将我的答案标记为正确,以防有人提出更快/更准确的算法。