mitsuba/include/mitsuba/core/qmc.h

295 lines
10 KiB
C

/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2012 by Wenzel Jakob and others.
Mitsuba is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Mitsuba is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined(__MITSUBA_CORE_QMC_H_)
#define __MITSUBA_CORE_QMC_H_
#include <mitsuba/mitsuba.h>
MTS_NAMESPACE_BEGIN
/** \addtogroup libcore
* \addtogroup libpython
* @{
*/
// -----------------------------------------------------------------------
//! @{ \name Elementary Quasi-Monte Carlo number sequences
//
// Based on implementations by Leonhard Gruenschloss
// -----------------------------------------------------------------------
static const size_t primeTableSize = 1024;
/// Table of the first 1024 prime numbers
extern const int MTS_EXPORT_CORE primeTable[primeTableSize];
/// Van der Corput radical inverse in base 2 with single precision
inline float radicalInverse2Single(uint32_t n, uint32_t scramble = 0U) {
/* Efficiently reverse the bits in 'n' using binary operations */
#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))) || defined(__clang__)
n = __builtin_bswap32(n);
#else
n = (n << 16) | (n >> 16);
n = ((n & 0x00ff00ff) << 8) | ((n & 0xff00ff00) >> 8);
#endif
n = ((n & 0x0f0f0f0f) << 4) | ((n & 0xf0f0f0f0) >> 4);
n = ((n & 0x33333333) << 2) | ((n & 0xcccccccc) >> 2);
n = ((n & 0x55555555) << 1) | ((n & 0xaaaaaaaa) >> 1);
// Account for the available precision and scramble
n = (n >> (32 - 24)) ^ (scramble & ~-(1 << 24));
return (float) n / (float) (1U << 24);
}
/// Van der Corput radical inverse in base 2 with double precision
inline double radicalInverse2Double(uint64_t n, uint64_t scramble = 0ULL) {
/* Efficiently reverse the bits in 'n' using binary operations */
#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))) || defined(__clang__)
n = __builtin_bswap64(n);
#else
n = (n << 32) | (n >> 32);
n = ((n & 0x0000ffff0000ffffULL) << 16) | ((n & 0xffff0000ffff0000ULL) >> 16);
n = ((n & 0x00ff00ff00ff00ffULL) << 8) | ((n & 0xff00ff00ff00ff00ULL) >> 8);
#endif
n = ((n & 0x0f0f0f0f0f0f0f0fULL) << 4) | ((n & 0xf0f0f0f0f0f0f0f0ULL) >> 4);
n = ((n & 0x3333333333333333ULL) << 2) | ((n & 0xccccccccccccccccULL) >> 2);
n = ((n & 0x5555555555555555ULL) << 1) | ((n & 0xaaaaaaaaaaaaaaaaULL) >> 1);
// Account for the available precision and scramble
n = (n >> (64 - 53)) ^ (scramble & ~-(1LL << 53));
return (double) n / (double) (1ULL << 53);
}
/// Sobol' radical inverse in base 2 with single precision.
inline float sobol2Single(uint32_t n, uint32_t scramble = 0U) {
for (uint32_t v = 1U << 31; n != 0; n >>= 1, v ^= v >> 1)
if (n & 1)
scramble ^= v;
return (float) scramble / (float) (1ULL << 32);
}
/// Sobol' radical inverse in base 2 with double precision.
inline double sobol2Double(uint64_t n, uint64_t scramble = 0ULL) {
scramble &= ~-(1LL << 53);
for (uint64_t v = 1ULL << 52; n != 0; n >>= 1, v ^= v >> 1)
if (n & 1)
scramble ^= v;
return (double) scramble / (double) (1ULL << 53);
}
/// Generate an element from a (0, 2) sequence, single precision
inline Point2f sample02Single(uint32_t n, uint32_t scramble[2]) {
return Point2f(
radicalInverse2Single(n, scramble[0]),
sobol2Single(n, scramble[1])
);
}
/// Generate an element from a (0, 2) sequence, double precision version
inline Point2d sample02Double(uint64_t n, uint64_t scramble[2]) {
return Point2d(
radicalInverse2Double(n, scramble[0]),
sobol2Double(n, scramble[1])
);
}
/// Generate an element from a (0, 2) sequence (without scrambling)
inline Point2 sample02(size_t n) {
#if defined(SINGLE_PRECISION)
return Point2(
radicalInverse2Single((uint32_t) n),
sobol2Single((uint32_t) n)
);
#else
return Point2(
radicalInverse2Double((uint64_t) n),
sobol2Double((uint64_t) n)
);
#endif
}
/**
* \brief Generate fast and reasonably good pseudorandom numbers using the
* Tiny Encryption Algorithm (TEA) by David Wheeler and Roger Needham.
*
* For details, refer to "GPU Random Numbers via the Tiny Encryption Algorithm"
* by Fahad Zafar, Marc Olano, and Aaron Curtis.
*
* \param v0
* First input value to be encrypted (could be the sample index)
* \param v1
* Second input value to be encrypted (e.g. the requested random number dimension)
* \param rounds
* How many rounds should be executed? The default for random number
* generation is 4.
* \return
* A uniformly distributed 64-bit integer
*/
inline uint64_t sampleTEA(uint32_t v0, uint32_t v1, int rounds = 4) {
uint32_t sum = 0;
for (int i=0; i<rounds; ++i) {
sum += 0x9e3779b9;
v0 += ((v1 << 4) + 0xA341316C) ^ (v1 + sum) ^ ((v1 >> 5) + 0xC8013EA4);
v1 += ((v0 << 4) + 0xAD90777D) ^ (v0 + sum) ^ ((v0 >> 5) + 0x7E95761E);
}
return ((uint64_t) v1 << 32) + v0;
}
/**
* \brief Generate fast and reasonably good pseudorandom numbers using the
* Tiny Encryption Algorithm (TEA) by David Wheeler and Roger Needham.
*
* This function uses \ref sampleTEA to return single precision floating point
* numbers on the interval <tt>[0, 1)</tt>
*
* \param v0
* First input value to be encrypted (could be the sample index)
* \param v1
* Second input value to be encrypted (e.g. the requested random number dimension)
* \param rounds
* How many rounds should be executed? The default for random number
* generation is 4.
* \return
* A uniformly distributed floating point number on the interval <tt>[0, 1)</tt>
*/
inline float sampleTEASingle(uint32_t v0, uint32_t v1, int rounds = 4) {
/* Trick from MTGP: generate an uniformly distributed
single precision number in [1,2) and subtract 1. */
union {
uint32_t u;
float f;
} x;
x.u = ((sampleTEA(v0, v1, rounds) & 0xFFFFFFFF) >> 9) | 0x3f800000UL;
return x.f - 1.0f;
}
/**
* \brief Generate fast and reasonably good pseudorandom numbers using the
* Tiny Encryption Algorithm (TEA) by David Wheeler and Roger Needham.
*
* This function uses \ref sampleTEA to return single precision floating point
* numbers on the interval <tt>[0, 1)</tt>
*
* \param v0
* First input value to be encrypted (could be the sample index)
* \param v1
* Second input value to be encrypted (e.g. the requested random number dimension)
* \param rounds
* How many rounds should be executed? The default for random number
* generation is 4.
* \return
* A uniformly distributed floating point number on the interval <tt>[0, 1)</tt>
*/
inline double sampleTEADouble(uint32_t v0, uint32_t v1, int rounds = 4) {
/* Trick from MTGP: generate an uniformly distributed
single precision number in [1,2) and subtract 1. */
union {
uint64_t u;
double f;
} x;
x.u = (sampleTEA(v0, v1, rounds) >> 12) | 0x3ff0000000000000ULL;
return x.f - 1.0;
}
#if defined(SINGLE_PRECISION)
/// Alias to \ref sampleTEASingle or \ref sampleTEADouble based on compilation flags
inline Float sampleTEAFloat(uint32_t v0, uint32_t v1, int rounds = 4) {
return sampleTEASingle(v0, v1, rounds);
}
#else
/// Alias to \ref sampleTEASingle or \ref sampleTEADouble based on compilation flags
inline Float sampleTEAFloat(uint32_t v0, uint32_t v1, int rounds = 4) {
return sampleTEADouble(v0, v1, rounds);
}
#endif
/**
* \brief Calculate the radical inverse function
*
* This function is used as a building block to construct Halton and
* Hammersley sequences. Roughly, it computes a b-ary representation
* of the input value \c index, mirrors it along the decimal
* point, and returns the resulting fractional value.
*/
extern MTS_EXPORT_CORE Float radicalInverse(int base, uint64_t index);
/**
* \brief Calculate a scrambled radical inverse function
*
* This function is used as a building block to construct permuted
* Halton and Hammersley sequence variants. It works like the normal
* radical inverse function \ref radicalInverse(), except that every digit
* is run through an extra scrambling permutation specified as array
* of size \c base.
*
* \remark This function is not available in the Python API
*/
extern MTS_EXPORT_CORE Float scrambledRadicalInverse(int base,
uint64_t index, uint16_t *perm);
/**
* \brief Incrementally calculate the next Van Der Corput sequence
* value starting from a current entry \c x (wrt. a fixed base)
*
* Repeated evaluation eventually causes a loss of accuracy
*/
extern MTS_EXPORT_CORE Float radicalInverseIncremental(int base, Float x);
/**
* \brief Calculate a radical inverse function (fast version)
*
* This function works similarly to \ref radicalInverse, but is potentially much
* faster. Internally, it relies on optimized implementations of the radical inverse
* functions for the first 1024 prime number bases. For that reason, only works for
* such bases.
*
* \param baseIndex
* Prime number index starting at 0 (i.e. 3 would cause 7 to be
* used as the basis)
* \param index
* Sequence index
*/
extern MTS_EXPORT_CORE Float radicalInverseFast(uint16_t baseIndex, uint64_t index);
/**
* \brief Calculate a scrambled radical inverse function (fast version)
*
* This function is used as a building block to construct permuted
* Halton and Hammersley sequence variants. It works like the fast
* radical inverse function \ref radicalInverseFast(), except that every
* digit is run through an extra scrambling permutation.
*
* \remark This function is not available in the Python API
*/
extern MTS_EXPORT_CORE Float scrambledRadicalInverseFast(uint16_t baseIndex,
uint64_t index, uint16_t *perm);
//! @}
// -----------------------------------------------------------------------
//! @}
MTS_NAMESPACE_END
#endif /* __MITSUBA_CORE_QMC_H_ */