/usr/include/hpptools/logdiff.hpp is in libhpptools-dev 1.1.1-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | //
// logdiff -- inspired by Sean Eddy's fast table-driven log sum
//
// The MIT License (MIT)
//
// (C) Matei David, Ontario Institute for Cancer Research, 2015
//
#ifndef __LOGDIFF_HPP
#define __LOGDIFF_HPP
#include <algorithm>
#include <cassert>
#include <cmath>
/*
* LOGDIFF_SCALE defines the precision of the calculation; the
* default of 1000.0 means rounding differences to the nearest 0.001
* nat. LOGDIFF_TBL defines the size of the lookup table; the
* default of 16000 means entries are calculated for differences of 0
* to 16.000 nats (when LOGDIFF_SCALE is 1000.0).
*/
#define LOGDIFF_TBL 16000
#define LOGDIFF_SCALE 1000.0f
namespace logdiff
{
namespace detail
{
struct LogDiff_Helper
{
/* Function: table()
* Synposis: Holds the main lookup table used in logspace diff computations.
*
* Purpose: Encapsulate static array inside a function to avoid the need for a separate definition.
*/
static inline float* table(void)
{
static float _table[LOGDIFF_TBL]; /* LOGDIFF_TBL=16000: (A-B) = 0..16 nats, steps of 0.001 */
return _table;
}
/* Function: init()
* Synopsis: Initialize the logdiff table.
*
* Purpose: Initialize the logdiff lookup table for logdiff().
* This function must be called once before any
* call to logdiff().
*
* Note: The precision of the lookup table is determined
* by the compile-time <LOGDIFF_TBL> constant.
*
* Returns: true on success.
*/
static bool init()
{
static bool first_time = true;
if (not first_time)
{
return true;
}
first_time = false;
for (unsigned i = 0; i < LOGDIFF_TBL; i++)
{
auto x = -((double) i / LOGDIFF_SCALE);
auto e_x = std::exp(x);
table()[i] = std::log(1.0 - e_x);
}
return true;
}
/* Function: logdiff()
* Synopsis: Approximate $\log(e^a - e^b)$.
*
* Purpose: Returns a fast table-driven approximation to
* $\log(e^a - e^b)$.
*
* Either <a> or <b> (or both) may be $-\infty$,
* but neither may be $+\infty$ or <NaN>.
*
* Note: This function is a critical optimization target, because
* it's in the inner loop of generic Forward() algorithms.
*/
static inline float logdiff(float a, float b)
{
if (a < b) std::swap(a, b);
return logdiff_nocomp(a, b);
}
static inline float logdiff_nocomp(float a, float b)
{
// static object whose constructor initializes the lookup table
static Table_Initializer _init;
(void)_init;
return (b == -INFINITY or a - b >= (float)(LOGDIFF_TBL - 1) / LOGDIFF_SCALE)
? a
: a + table()[(int)((a - b) * LOGDIFF_SCALE)];
}
/* Function: logdiff_error()
* Synopsis: Compute absolute error in probability from logdiff.
*
* Purpose: Compute the absolute error in probability space
* resulting from logdiff()'s table lookup:
* approximation result - exact result.
*/
static float logdiff_error(float a, float b)
{
if (a < b) std::swap(a, b);
return logdiff_error_nocomp(a, b);
}
static float logdiff_error_nocomp(float a, float b)
{
assert(a >= b);
if (a == b) return 0.0;
float approx = logdiff_nocomp(a, b);
float exact = std::log(std::exp(a) - std::exp(b));
return std::exp(approx) - std::exp(exact);
}
/* Struct: Table_Initializer
* Purpose: Initialize the lookup table on construction.
*/
struct Table_Initializer
{
Table_Initializer()
{
init();
}
}; // struct Table_Initializer
}; // struct LogDiff_Helper
} // namespace detail
/*
* Publish main methods outside of the helper struct.
*/
inline float LogDiff(float a, float b) { return detail::LogDiff_Helper::logdiff(a, b); }
inline float LogDiffError(float a, float b) { return detail::LogDiff_Helper::logdiff_error(a, b); }
} // namespace logdiff
#endif
#ifdef SAMPLE_LOGDIFF
/*
g++ -std=c++11 -DSAMPLE_LOGDIFF -x c++ logdiff.hpp -o sample-logdiff
*/
#include <iostream>
#include <sstream>
using namespace std;
using namespace logdiff;
int main(int argc, char* argv[])
{
if (argc != 3)
{
cerr << "use: " << argv[0] << " <a> <b>" << endl;
return EXIT_FAILURE;
}
float a;
float b;
float result;
istringstream(argv[1]) >> a;
istringstream(argv[2]) >> b;
result = LogDiff(a, b);
cout << "logdiff(" << a << ", " << b << ") = " << result << endl;
result = log(exp(a) - exp(b));
cout << "log(exp(" << a << ") - exp(" << b << ")) = " << result << endl;
cout << "Absolute error in probability: " << LogDiffError(a, b) << endl;
}
#endif
|