diff --git a/heuristic/exponential_dist_sampler.hpp b/heuristic/exponential_dist_sampler.hpp new file mode 100644 index 00000000..35db5384 --- /dev/null +++ b/heuristic/exponential_dist_sampler.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include + +template struct ExponentialDistSampler { + std::array minuslogps; + + constexpr ExponentialDistSampler() { + for (int i = 0; i < (1 << D); ++i) minuslogps.at(i) = -log((0.5 + i) / (1 << D)); + } + + double sample(uint32_t random_mask) const { + return minuslogps.at(random_mask & ((1 << D) - 1)); + } + + // p ~ U(0, 1) => -log(p) ~ Ex(1) + // P[exp(-|dx| / T) >= p] = P[|dx| <= -log(p) * T] + bool check_sa(double abs_dx, double T, uint32_t random_mask) const { + return abs_dx <= minuslogps.at(random_mask & ((1 << D) - 1)) * T; + } +}; +// const ExponentialDistSampler<16> log_ps; diff --git a/heuristic/exponential_dist_sampler.md b/heuristic/exponential_dist_sampler.md new file mode 100644 index 00000000..77a1e08a --- /dev/null +++ b/heuristic/exponential_dist_sampler.md @@ -0,0 +1,25 @@ +--- +title: Fast sampler of exponential distribution (高速指数分布サンプラー・擬似焼きなまし法の遷移判定) +documentation_of: ./exponential_dist_sampler.hpp +--- + +母数 $\lambda = 1$ の指数分布を模擬するサンプラー. + +典型的な用途として,擬似焼きなまし法 (simulated annealing, SA) の遷移判定を(指数関数や対数関数の計算を毎回行うことなく)高速に行える. + +## 使用方法 + +```cpp +constexpr int D = 18; +const ExponentialDistSampler eds; // 2^D 個のサンプルを前計算 + +// 下位 D bit がランダムに分布した mask を与えると x ~ Ex(1) をサンプル +uint32_t mask; +double x = eds.sample(mask); + +double dx; +double T; + +// コストの変化が abs(dx), 温度 T のとき焼きなまし法の遷移を受理するか確率的に判定 +bool upd = eds.check_sa(abs(dx), T, mask); +```