Deterministic Gaussian Sampling
Loading...
Searching...
No Matches
lcd_even_closed_form.h
Go to the documentation of this file.
1#ifndef LCD_EVEN_CLOSED_FORM_H
2#define LCD_EVEN_CLOSED_FORM_H
3
4#include <gsl/gsl_errno.h>
5#include <gsl/gsl_sf_expint.h>
6
7#include <cassert>
8#include <cmath>
9#include <cstddef>
10
35inline double lcd_ei(double x) {
36 assert(x < 0.00);
37
39 const int status = gsl_sf_expint_Ei_e(x, &result);
40
41 if (status == GSL_EUNDRFLW || status == GSL_EDOM || status == GSL_EOVRFLW) return 0.00;
43
44 return result.val;
45}
46
65inline double lcd_a_n(size_t N, double b) {
66 assert(N >= 1);
67 assert(b >= 0.00);
68
69 const double bSqrd = b * b;
70
71 size_t n = (N % 2 == 0) ? 2 : 1;
72 double aN = (N % 2 == 0)
73 ? 0.50 * (bSqrd - std::log1p(bSqrd))
74 : 0.50 * (b * std::sqrt(1.00 + bSqrd) - std::asinh(b));
75
76 for (n += 2; n <= N; n += 2) {
77 const double dn = static_cast<double>(n);
78 const double tail =
79 bSqrd * std::pow(bSqrd / (1.00 + bSqrd), (dn - 2.00) / 2.00);
80 aN = (dn * aN - tail) / (dn - 2.00);
81 }
82
83 return aN;
84}
85
97inline double lcd_c_repulsion(double b, double c) {
98 assert(b > 0.00);
99 assert(c >= 0.00);
100
101 const double bSqrd = b * b;
102 if (c <= 0.00) return 0.50 * bSqrd; // coincident samples
103
104 const double z = -c / (4.00 * bSqrd);
105 return 0.50 * bSqrd * std::exp(z) + 0.125 * c * lcd_ei(z);
106}
107
112 size_t k;
113 size_t q;
114 double cValue;
115 bool reduced;
116};
117
129inline double lcd_delta_b_integrand(double b, void* params) {
131 static_cast<const LcdDeltaBIntegrandParams*>(params);
132
133 const double u = 1.00 + 2.00 * b * b;
134 double value = b * std::pow(b * b / u, static_cast<double>(p->k));
135 for (size_t i = p->k; i < p->q; ++i) value /= u;
136
137 const double exponent = -p->cValue / (2.00 * u);
138 return value * (p->reduced ? std::expm1(exponent) : std::exp(exponent));
139}
140
153inline double lcd_delta_b0(size_t d, double u, double eULeading, double eU,
154 double e0, double dEi, double c) {
155 assert(c > 0.00);
156
157 if (d == 0) return 0.25 * u * eULeading - 0.25 * e0 + 0.125 * c * dEi;
158 if (d == 1) return -0.25 * dEi;
159
160 double coefficient = 0.50;
161 double cPower = c; // c^(d-j+1), j = d
162 double uPower = 1.00; // u^(j-2), j = d ... built downwards below
163 for (size_t j = d; j > 2; --j) uPower *= u;
164
165 double sum = 0.00;
166 for (size_t j = d;; --j) {
167 sum += coefficient * (eU / (cPower * uPower) - e0 / cPower);
168 if (j == 2) break;
169 coefficient *= static_cast<double>(j - 2) * 2.00;
170 cPower *= c;
171 uPower /= u;
172 }
173
174 return sum;
175}
176
189inline double lcd_delta_bkk(size_t k, double bMax, double c);
190
200inline double lcd_delta_bkk1(size_t k, double bMax, double c);
201
211inline double lcd_delta_bkk_closed(size_t k, double bMax, double c,
212 size_t shift, bool reduced = false) {
213 assert(k >= 1);
214 assert(bMax > 0.00);
215 assert(c > 0.00);
216 assert(!reduced || shift == 0); // no reduction is defined for dBkk1
217
218 const double u = 1.00 + 2.00 * bMax * bMax;
219 const double exponent = -c / (2.00 * u);
220 const double eU = std::exp(exponent);
221 const double eULeading = reduced ? std::expm1(exponent) : eU;
222 const double e0 = std::exp(-c / 2.00);
223 const double dEi = lcd_ei(exponent) - lcd_ei(-c / 2.00);
224
225 double sum = 0.00;
226 double binomial = 1.00; // binom(k, j)
227 for (size_t j = 0; j <= k; ++j) {
228 const double term =
230 sum += (j % 2 == 0) ? binomial * term : -binomial * term;
231 binomial *= static_cast<double>(k - j) / static_cast<double>(j + 1);
232 }
233
234 return std::ldexp(sum, -static_cast<int>(k));
235}
236
256inline double lcd_delta_bkk_zero(size_t k, double bMax) {
257 assert(k >= 1);
258 assert(bMax > 0.00);
259
260 const double u = 1.00 + 2.00 * bMax * bMax;
261
262 double sum = (u - 1.00) - static_cast<double>(k) * std::log(u);
263
264 double binomial = static_cast<double>(k); // binom(k, 1), stepped up below
265 for (size_t j = 2; j <= k; ++j) {
266 binomial *= static_cast<double>(k - j + 1) / static_cast<double>(j);
267 const double dj = static_cast<double>(j);
268 const double term =
269 binomial * (std::pow(u, 1.00 - dj) - 1.00) / (1.00 - dj);
270 sum += (j % 2 == 0) ? term : -term;
271 }
272
273 return std::ldexp(sum, -static_cast<int>(k) - 2);
274}
275
287inline double lcd_delta_bkk_zero_minus_leading(size_t k, double bMax) {
288 assert(k >= 1);
289 assert(bMax > 0.00);
290
291 const double u = 1.00 + 2.00 * bMax * bMax;
292
293 double sum = -1.00 - static_cast<double>(k) * std::log(u);
294
295 double binomial = static_cast<double>(k);
296 for (size_t j = 2; j <= k; ++j) {
297 binomial *= static_cast<double>(k - j + 1) / static_cast<double>(j);
298 const double dj = static_cast<double>(j);
299 const double term =
300 binomial * (std::pow(u, 1.00 - dj) - 1.00) / (1.00 - dj);
301 sum += (j % 2 == 0) ? term : -term;
302 }
303
304 return std::ldexp(sum, -static_cast<int>(k) - 2);
305}
306
321inline double lcd_delta_bkk_reduced(size_t k, double bMax, double c) {
322 assert(k >= 1);
323 assert(bMax > 0.00);
324 assert(c >= 0.00);
325
326 if (c <= 0.00) return 0.00; // dBkk(0) - dBkk(0)
327
328 // the expm1 form has already dropped pow(2,-k) * U/4; take off what is left
329 // of dBkk(k, 0), which is only O(ln U)
330 return lcd_delta_bkk_closed(k, bMax, c, 0, true) -
332}
333
343inline double lcd_delta_bkk_impl(size_t k, double bMax, double c,
344 size_t shift) {
345 assert(k >= 1);
346 assert(bMax > 0.00);
347 assert(c >= 0.00);
348
349 return lcd_delta_bkk_closed(k, bMax, c, shift);
350}
351
352inline double lcd_delta_bkk(size_t k, double bMax, double c) {
353 return lcd_delta_bkk_impl(k, bMax, c, 0);
354}
355
356inline double lcd_delta_bkk1(size_t k, double bMax, double c) {
357 return lcd_delta_bkk_impl(k, bMax, c, 1);
358}
359
360
385inline double lcd_reported_offset(size_t N, double bMax, double weightSum) {
386 assert(N >= 2);
387 assert(N % 2 == 0);
388 assert(bMax > 0.00);
389
390 const size_t k = N / 2;
391 const double bMaxSqrd = bMax * bMax;
392
393 if (N == 2) {
394 // K = W^2 bMax^2/2 + bMax^2/2 - W bMax^2 - ln(1+bMax^2)/2
395 // + W ln(1+2bMax^2)/2
396 //
397 // Two rearrangements:
398 // - the three bMax^2 terms collapse to (1-W)^2 bMax^2 / 2;
399 // - W ln(1+2b^2)/2 - ln(1+b^2)/2 is split as
400 // W/2 * ln((1+2b^2)/(1+b^2)) + (W-1)/2 * ln(1+b^2), whose first factor
401 // is log1p(b^2/(1+b^2)).
402 const double weightDefect = 1.00 - weightSum;
403 return 0.50 * bMaxSqrd * weightDefect * weightDefect +
404 0.50 * weightSum * std::log1p(bMaxSqrd / (1.00 + bMaxSqrd)) -
405 0.50 * weightDefect * std::log1p(bMaxSqrd);
406 }
407
408 return lcd_a_n(N, bMax) -
409 std::ldexp(weightSum * lcd_delta_bkk_zero(k, bMax),
410 static_cast<int>(k) + 1) +
411 0.50 * weightSum * weightSum * bMaxSqrd;
412}
413
414#endif // LCD_EVEN_CLOSED_FORM_H
Definition dirac_to_dirac_approx_short.h:9
double lcd_delta_bkk_closed(size_t k, double bMax, double c, size_t shift, bool reduced=false)
closed form of dBkk / dBkk1
Definition lcd_even_closed_form.h:211
double lcd_c_repulsion(double b, double c)
C(b, c), the per-pair repulsion term of D3.
Definition lcd_even_closed_form.h:97
double lcd_delta_b_integrand(double b, void *params)
b^(2k+1) * (1 + 2b^2)^(-q) * exp(-c / (2 (1 + 2b^2)))
Definition lcd_even_closed_form.h:129
double lcd_reported_offset(size_t N, double bMax, double weightSum)
the constant that turns the reduced objective back into the true distance
Definition lcd_even_closed_form.h:385
double lcd_a_n(size_t N, double b)
D1, the sample-independent term of the mCvM distance.
Definition lcd_even_closed_form.h:65
double lcd_delta_bkk1(size_t k, double bMax, double c)
dBkk1(k, c) = B_{k,k+1}(bMax, c) - B_{k,k+1}(0, c), the D2 gradient
Definition lcd_even_closed_form.h:356
double lcd_delta_b0(size_t d, double u, double eULeading, double eU, double e0, double dEi, double c)
dB_{0,d}(c) = B_{0,d}(bMax, c) - B_{0,d}(0, c)
Definition lcd_even_closed_form.h:153
double lcd_delta_bkk_reduced(size_t k, double bMax, double c)
dBkk(k, c) - dBkk(k, 0), the cancellation-free attraction term
Definition lcd_even_closed_form.h:321
double lcd_delta_bkk_impl(size_t k, double bMax, double c, size_t shift)
shared body of lcd_delta_bkk / lcd_delta_bkk1
Definition lcd_even_closed_form.h:343
double lcd_ei(double x)
exponential integral Ei(x) for negative arguments
Definition lcd_even_closed_form.h:35
double lcd_delta_bkk_zero_minus_leading(size_t k, double bMax)
lcd_delta_bkk_zero(k, bMax) - pow(2, -k) * U / 4
Definition lcd_even_closed_form.h:287
double lcd_delta_bkk_zero(size_t k, double bMax)
dBkk(k, 0) = integral{0 to bMax} b^(2k+1) / (1 + 2b^2)^k db
Definition lcd_even_closed_form.h:256
double lcd_delta_bkk(size_t k, double bMax, double c)
dBkk(k, c) = B_{k,k}(bMax, c) - B_{k,k}(0, c), the D2 term
Definition lcd_even_closed_form.h:352
parameters of the raw b-integrand used by the small-c fallback
Definition lcd_even_closed_form.h:111
double cValue
squared norm of the sample
Definition lcd_even_closed_form.h:114
size_t k
half the dimension
Definition lcd_even_closed_form.h:112
bool reduced
true to use expm1, giving dBkk(c) - dBkk(0) directly
Definition lcd_even_closed_form.h:115
size_t q
exponent of (1 + 2b^2); k for dBkk, k+1 for dBkk1
Definition lcd_even_closed_form.h:113