Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F96964213
random.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Wed, Jan 1, 04:00
Size
91 KB
Mime Type
text/x-c
Expires
Fri, Jan 3, 04:00 (2 d)
Engine
blob
Format
Raw Data
Handle
23226209
Attached To
R1448 Lenstool-HPC
random.c
View Options
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Filename: random.c
//
// Purpose: Random utility procedures for BayeSys3.
//
// History: Random.c 17 Nov 1994 - 13 Sep 2003
//
// Acknowledgments:
// "Numerical Recipes", Press et al, for ideas
// "Handbook of Mathematical Functions", Abramowitz and Stegun, for formulas
// Peter J Acklam website, for inverse normal code
//-----------------------------------------------------------------------------
/*
Copyright (c) 1994-2003 Maximum Entropy Data Consultants Ltd,
114c Milton Road, Cambridge CB4 1XE, England
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "license.txt"
*/
#include <stddef.h>
#include <time.h>
#include <math.h>
#include <float.h>
#include "random.h"
static const double SHIFT32 = 1.0 / 4294967296.0; // 2^-32
static const double HalfPi = 1.57079632679489661922; // pi/2
static const double TwoxPi = 6.28318530717958647688; // 2*pi
static const double SqrPi2 = 1.25331413731550025120; // sqrt(pi/2)
static const double Sqr2Pi = 2.50662827463100050240; // sqrt(2*pi)
static const double LogSqr2Pi = 0.91893853320467274177; // log(sqrt(2*pi))
// Internal prototypes
static void Positive2 (Rand_t, double, double, double, double*, double*);
static void Positive2A (double, double, double, double,
double*, double*, double*);
static void Positive2B (double, double, double, double,
double*, double*, double*);
static void Positive2C (double, double, double, double,
double*, double*, double*);
static void Positive2D (double, double, double*, double*, double*);
static void Posneg2 (Rand_t, double, double, double, double, double,
double*, double*);
static void Posneg2A (double, double, double, double, double, double,
double*, double*, double*);
static void Posneg2B (double, double, double, double, double, double,
double*, double*, double*);
static void Posneg2C (double, double, double, double, double, double,
double*, double*, double*);
static void Posneg2D (double, double, double, double, double, double,
double*, double*, double*);
static double eigenerf2 (double, double, double, double, double);
static double erfint2 (double, double);
static double wedge (double, double, double);
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: RanInit
//
// Purpose: Initialise generator of 4 unsigneds for other Random procedures
//
// Format: Rand[0] + Rand[1] * 2^32 = # calls to Ranint since initialisation
// Rand[2] = generator offset, re-randomised every 2^32 calls
// Rand[3] = extra random integer available after each call
//
// History: John Skilling 15 Jan 2002, 31 Oct 2002
//-----------------------------------------------------------------------------
//
int RanInit( // O Seed, either from input or time
Rand_t Rand, // O Random generator state [4]
int seed) // I Seed: +ve = value, -ve = time seed
{
unsigned j, k;
k = 1;
for ( j = 0; k; ++j )
k += k;
if ( j != 32 ) // Check 32-bit arithmetic
return E_RAN_ARITH;
if ( seed < 0 )
{
seed = (int)time(NULL);
if ( seed < 0 )
seed = ~seed; // still OK after A.D.2030
}
Rand[0] = Rand[1] = 0; // 64-bit counter
Rand[2] = 1013904223 + 1664525 * seed; // sticky offset
Rand[3] = 1013904223 + 1664525 * Rand[2]; // extra random integer
return seed;
}
#if 0
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Kernel of alternative initialiser #1, crude congruential.
//-----------------------------------------------------------------------------
void RanInit1(
Rand_t Rand, // O Random generator state [1]
int seed) // I Non-negative seed
{
Rand[0] = seed;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Kernel of alternative initialiser #2, double congruential with shuffling.
//-----------------------------------------------------------------------------
void RanInit2(
Rand_t Rand, // O Random generator state [35]
int seed) // I Non-negative seed
{
int i, j;
i = (seed > 2147483397) ? seed - 2147483397 : seed + 1; // [1...2147483398]
Rand[33] = i;
for ( j = 39; j >= 0; j-- )
{
i = 40014 * i - 2147483563 * (i / 53668);
if ( i < 0 )
i += 2147483563; // [1...2147483562]
if ( j < 32 )
Rand[j] = i;
}
Rand[34] = Rand[0];
Rand[32] = i;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Kernel of alternative initialiser #3, Knuth's subtractive.
//-----------------------------------------------------------------------------
void RanInit3(
Rand_t Rand, // O Random generator state [112]
int seed) // I Non-negative seed
{
unsigned i, j, k, m;
m = (unsigned)(161803398 - seed);
Rand[54] = m;
Rand[109] = 0;
k = 1;
for ( i = 1; i < 55; ++i )
{
j = (21 * i - 1) % 55;
Rand[j] = k;
k = m - k;
m = Rand[j];
Rand[54+i] = i;
}
for ( k = 0; k < 4; ++k )
for ( i = 0; i < 55; ++i )
Rand[i] -= Rand[(i + 31) % 55];
Rand[110] = 0;
Rand[111] = 31;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Kernel of alternative initialiser #4, 64-bit hashing.
//-----------------------------------------------------------------------------
void RanInit4(
Rand_t Rand, // O Random generator state [3]
int seed) // I Non-negative seed
{
Rand[0] = Rand[1] = 0;
Rand[2] = seed;
}
#endif
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Ranint
//
// Purpose: Random integer sample, in [-2^31,2^31).
//
// Method: 64-bit hashing is on #calls + offset to produce 32-bit candidate
// with algorithm from ran4 in "Numerical Recipes".
// After each 2^32 calls, the 64-bit offset is incremented by
// congruential generators on its 32-bit halves.
//
// Notes: (1) Period is just less than 2^95, extremely large.
// (2) All random calls are directed through this procedure.
// (3) After a call, Rand[3] is available as another random integer.
//
// History: John Skilling 28 Jan 2002, 31 Oct 2002, 17 Dec 2002
//-----------------------------------------------------------------------------
//
int Ranint( // O 32-bit integer
Rand_t Rand) // I O Random generator state [4]
{
unsigned m, n; // 64-bit register
unsigned u, v, w;
int i;
// 64-bit counter, for hashing
if ( !(Rand[0] ++) )
{
Rand[1] ++;
// occasional update offset in Rand[2]
i = Rand[2] >> 1; // [0...2147483647]
i -= i / 24683721; // [0...2147483561]
i++; // [1...2147483562]
i = 40014 * i - 2147483563 * (i / 53668);
if ( i < 0 ) // (40014 * i) % 2147483563
i += 2147483563; // [1...2147483562]
i--; // [0...2147483561]
i += i / 24683720; // [0...2147483647] (with holes)
Rand[2] = i << 1; // even
if ( 1013904223 + 1664525 * i < 0 ) // chance
Rand[2]++; // even or odd
}
// Two double steps of 64-bit hash
n = Rand[0] + Rand[2];
m = Rand[1] + Rand[2];
w = n ^ 0xbaa96887;
v = w >> 16;
w &= 0xffff;
u = (v - w) * (v + w);
m ^= (((u >> 16) | (u << 16)) ^ 0xb4f0c4a7) + w * v;
w = m ^ 0x1e17d32c;
v = w >> 16;
w &= 0xffff;
u = (v - w) * (v + w);
n ^= (((u >> 16) | (u << 16)) ^ 0x178b0f3c) + w * v;
w = n ^ 0x03bcdc3c;
v = w >> 16;
w &= 0xffff;
u = (v - w) * (v + w);
m ^= (((u >> 16) | (u << 16)) ^ 0x96aa3a59) + w * v;
w = m ^ 0x0f33d1b2;
v = w >> 16;
w &= 0xffff;
u = (v - w) * (v + w);
n ^= (((u >> 16) | (u << 16)) ^ 0xaa5835b9) + w * v;
Rand[3] = m;
return n;
}
#if 0
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Kernel of alternative generator #1, crude congruential.
//-----------------------------------------------------------------------------
int Ranint1( // O 32-bit integer
Rand_t Rand) // I O Random generator state [1]
{
Rand[0] = Rand[0] * 1664525 + 1013904223;
return Rand[0];
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Kernel of alternative generator #2, double congruential with shuffling.
//-----------------------------------------------------------------------------
int Ranint2( // O Odd integer with 85 holes: ONLY (2^31 - 85) VALUES
Rand_t Rand) // I O Random generator state [35]
{
int i, j, k;
// First congruential sequence
i = Rand[32];
i = 40014 * i - 2147483563 * (i / 53668);
if ( i < 0 )
i += 2147483563;
Rand[32] = i; // [1...2147483562]
// Second congruential sequence
k = Rand[33];
k = 40692 * k - 2147483399 * (k / 52774);
if ( k < 0 )
k += 2147483399;
Rand[33] = k; // [1...2147483398]
// Subtract from shuffled table
j = Rand[34] / 67108862; // [0...31]
k = Rand[j] - k; // [-2147483397...2147483561]
if ( k < 0 )
k += 2147483563; // (2^31 - 85) values
Rand[34] = k; // [0...2147483562]
Rand[j] = i;
// Expand result k
k += k / 24970740; // [0...2^31) with holes at 24970740*[1...85]
return (k << 1) | 1;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Kernel of alternative generator #3, Knuth's subtractive.
//-----------------------------------------------------------------------------
int Ranint3( // O 32-bit integer
Rand_t Rand) // I O Random generator state [112]
{
unsigned j, k;
j = Rand[110];
Rand[110] = Rand[55+j];
k = Rand[111];
Rand[111] = Rand[55+k];
return (Rand[j] -= Rand[k]);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Kernel of alternative generator #4, 64-bit hashing.
//-----------------------------------------------------------------------------
int Ranint4( // O 32-bit integer
Rand_t Rand) // I O Random generator state [3]
{
unsigned u, v, w, m, n;
// 64-bit counter, for hashing
if ( !(Rand[0] ++) )
Rand[1] ++;
// 64-bit hash
n = Rand[0] + Rand[2];
m = Rand[1] + Rand[2];
w = n ^ 0xbaa96887;
v = w >> 16;
w &= 0xffff;
u = (v - w) * (v + w);
m ^= (((u >> 16) | (u << 16)) ^ 0xb4f0c4a7) + w * v;
w = m ^ 0x1e17d32c;
v = w >> 16;
w &= 0xffff;
u = (v - w) * (v + w);
n ^= (((u >> 16) | (u << 16)) ^ 0x178b0f3c) + w * v;
w = n ^ 0x03bcdc3c;
v = w >> 16;
w &= 0xffff;
u = (v - w) * (v + w);
m ^= (((u >> 16) | (u << 16)) ^ 0x96aa3a59) + w * v;
w = m ^ 0x0f33d1b2;
v = w >> 16;
w &= 0xffff;
u = (v - w) * (v + w);
n ^= (((u >> 16) | (u << 16)) ^ 0xaa5835b9) + w * v;
return n;
}
#endif
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Randouble
//
// Purpose: Random single-precision doubleing-point sample.
// The 2^23 allowed values are odd multiples of 2^-24,
// symmetrically placed in strict interior of (0,1).
//
// Notes: (1) Tuned to 23-bit mantissa in "double" format.
// (2) Uses Ranint.
//
// History: John Skilling 20 Oct 2002
//-----------------------------------------------------------------------------
//
float Ranfloat( // O Value
Rand_t Rand) // I O Random generator state
{
unsigned u = ((unsigned)Ranint(Rand)
& 0xfffffe00) ^ 0x00000100; // switch lowest (2^-24) bit ON
return (float)u * (float)SHIFT32;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Randouble
//
// Purpose: Random double-precision doubleing-point sample.
// The 2^52 allowed values are odd multiples of 2^-53,
// symmetrically placed in strict interior of (0,1).
//
// Notes: (1) Tuned to 52-bit mantissa in "double" format.
// (2) Uses one call to Ranint to get 64 random bits, with extra
// random integer available in Rand[3].
// (3) All doubleing-point random calls are directed through this code,
// except Rangauss which uses the extra random integer in Rand[3].
//
// History: John Skilling 6 May 1995, 3 Dec 1995, 24 Aug 1996
// 20 Oct 2002, 17 Dec 2002
//-----------------------------------------------------------------------------
//
double Randouble( // O Value within (0,1)
Rand_t Rand) // I O Random generator state
{
unsigned hi, lo;
hi = (unsigned)Ranint(Rand); // top 32 bits
lo = (Rand[3] // low bits
& 0xfffff000) ^ 0x00000800; // switch lowest (2^-53) bit ON
return ((double)hi + (double)lo * SHIFT32) * SHIFT32;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Rangauss
//
// Purpose: Sample from Gaussian N(0,1)
//
// Notes: (1) Cannot overflow; |value| < 10 standard deviations
// (2) 2nd sample y*sqrt(...) could be available, best with y = ...+ 0.5
//
// History: JS 3 Oct 2002 Half of Box-Muller
// 17 Dec 2002 Use Rand[3] for extra 40% speedup
//-----------------------------------------------------------------------------
//
double Rangauss( // O Value
Rand_t Rand) // I O Random generator state
{
static const double RR = 4611686018427387904.0; // 2^62
double x, y, r;
do
{
x = Ranint(Rand) + 0.5; // (-2^31,2^31), not 0
y = (int)Rand[3]; // [-2^31,2^31)
r = x * x + y * y;
}
while ( r >= RR ); // disc, radius 2^31
return x * sqrt(2.0 * log(RR / r) / r); // Waste 2nd Box-Muller sample
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Rancauchy
//
// Purpose: Draw sample from
// prob(x) = 1 / (1 + x * x)
//
// Notes: Cannot overflow; |value| <= 2^53/pi
//
// History: JS 3 Oct 2002
//-----------------------------------------------------------------------------
//
double Rancauchy( // O Value
Rand_t Rand) // I O Random generator state
{
double t = tan(HalfPi * (Randouble(Rand) - 0.5));
return (1.0 - t * t) / (2.0 * t);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Rangamma
//
// Purpose: Draw sample from
// -1+c -x
// prob(x) = x e / Gamma(c) for x in [0, inf)
//
// Notes: x=0 can be returned, especially if c is small, but x=inf cannot.
//
// History: JS 24 Jan 1994, 19 Oct 1995, 24 Aug 1996, 3 Oct 2002
//-----------------------------------------------------------------------------
//
double Rangamma( // O Value
Rand_t Rand, // I O Random generator state
double c) // I Exponent
{
double a, q, r, g, e;
g = c - 1.0;
if (g > 0.0)
{
e = sqrt(g + c) / g;
do
{
do
{
r = Rancauchy(Rand);
q = e * r + 1.0;
}
while (q <= 0.0);
}
while ( log(Randouble(Rand) / (1.0 + r * r))
> g * (log(q) - q + 1.0) ); // Accept?
q *= g;
}
else
{
r = 1.0 / (1.0 + c * exp(-1.0)); // prob(bounding p < 1)
do
{
if ( Randouble(Rand) >= r ) // Bounding x > 1
{
q = 1.0 - log(Randouble(Rand)); // exp(-q) in (1,inf)
a = g * log(q); // log(Accept ratio)
}
else // Bounding x <= 1
{
q = exp(log(Randouble(Rand)) / c); // q^(-1+c) in (0,1)
a = -q; // log(Accept ratio)
}
}
while ( log(Randouble(Rand)) > a );
}
return q;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Ranpoiss
//
// Purpose: Draw sample from Poisson
//
// -c j
// prob(j) = e c / j! ( 0 <= c <~ 4000000000 )
//
// Notes: Distribution is truncated at 2^32-1,
// so input parameter c should not approach 2^32.
//
// History: JS 15 May 1998, 24 Mar 2001, 3 Oct 2002
//-----------------------------------------------------------------------------
//
unsigned Ranpoiss( // O Value
Rand_t Rand, // I O Random generator state
double c) // I Mean
{
unsigned j, k;
double a, b, r, t, y;
if ( c <= 0.0 )
return 0;
if ( c < 70.0 ) // Direct is faster for small c
{
j = k = (unsigned)c;
t = exp(j * log(c) - c - logfactorial(j));
for ( ; ; )
{
r = Randouble(Rand);
if ( t >= r )
return j;
a = b = t;
do
{
if ( a > b )
{
if ( (t += a *= j-- / c) >= r )
return j;
}
else
{
if ( (t += b *= c / ++k) >= r )
return k;
}
}
while ( b > 0.0 ); // Trap failure from rounding error
}
}
else
{
b = sqrt(2.0 * c);
do
{
do
{
y = Rancauchy(Rand);
r = c + b * y;
}
while ( r < 0.0 );
j = (unsigned)r;
t = j * log(c) - logfactorial(j) - c;
}
while ( log(Randouble(Rand) / (1.731 * (1.0 + y * y) * b)) > t );
return j;
}
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Ranbinom
//
// Purpose: Draw sample from binomial
//
// n! j n-j
// prob(j) = -------- p (1-p) 0 <= j <= n
// j!(n-j)!
//
// History: JS 24 Mar 2001, 3 Oct 2002
//-----------------------------------------------------------------------------
//
unsigned Ranbinom( // O Value
Rand_t Rand, // I O Random generator state
unsigned n, // I Range
double p) // I Mean/Range
{
unsigned j;
double a, b, g, q, r, t, u, w, y;
if ( n == 0 )
return 0;
if ( p <= 0.0 )
return 0;
if ( p >= 1.0 )
return n;
q = 1.0 - p;
if ( n < 100 )
{
u = w = j = (unsigned)(p * n + p);
t = exp(j * log(p) + (n - j) * log(q)
+ logfactorial(n) - logfactorial(j) - logfactorial(n - j));
for ( ; ; )
{
r = Randouble(Rand);
if ( t >= r )
return j;
a = b = t;
do
{
if ( a > b )
{
a *= u / p;
u -= 1.0;
a *= q / (n - u);
t += a;
if ( t >= r )
return (unsigned)u;
}
else
{
b *= (n - w) / q;
w += 1.0;
b *= p / w;
t += b;
if ( t >= r )
return (unsigned)w;
}
}
while ( a + b > 0.0 ); // Trap failure from rounding error
}
}
else
{
b = sqrt(2.0 * n * p * q + 0.25);
g = logfactorial(n);
do
{
do
{
y = Rancauchy(Rand);
r = n * p + b * y + 0.5;
}
while ( r < 0.0 || r >= n + 1.0 );
j = (unsigned)r;
t = g - logfactorial(j) - logfactorial(n - j)
+ j * log(p) + (n - j) * log(q);
}
while ( log(Randouble(Rand) / (0.8190 * (1.0 + y * y) * b)) > t );
return j;
}
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Ranbeta
//
// Purpose: Draw sample from beta distribution
// r n-r
// prob(x) = x (1 - x) / Z , Z = (n+1)! / r! (n-r)!
//
// Method: Rejection beneath Cauchy of phenomenologically adequate width.
//
// History: John Skilling 28 Nov 2000
//-----------------------------------------------------------------------------
//
double Ranbeta( // O Value
Rand_t Rand, // I O Random generator state
int r, // I Number of successes >= 0
int n) // I Total number >= r
{
double p, q, x, y, c;
x = (double)n;
if ( r <= 0 )
x = 1.0 - exp(log(Randouble(Rand)) / (x + 1.0));
else if ( r >= n )
x = exp(log(Randouble(Rand)) / (x + 1.0));
else
{
p = (double)r / x;
q = 1.0 - p;
c = x / (3.0 * p * q); // less than curvature at top
do
{
do
{
y = Rancauchy(Rand) / sqrt(c);
x = p + y; // x from Cauchy upper bound
}
while ( x <= 0.0 || x >= 1.0 ); // x within range
y = r * log(x / p) + (n - r) * log((1.0 - x) / q) // log(true)
+ log(1.0 + c * y * y); // -log(Cauchy)
}
while ( log(Randouble(Rand)) > y ); // accept?
}
return x;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Rangeom
//
// Purpose: Draw integer from truncated geometric distribution
// j
// prob(j) proportional a for j in [0,N-1]
//
// where a = alpha/(alpha+1), alpha > 0.0
//
// Special case N = 0 means N = 2^32 for which
//
// <j> = alpha , var(j) = alpha(alpha+1)
//
// History: John Skilling 3 Apr 2001 Linearly truncated version
// 17 Dec 2002 Hard truncation
//-----------------------------------------------------------------------------
//
unsigned Rangeom( // O Value
Rand_t Rand, // I O Random generator state
double alpha, // I Parameter
unsigned N) // I Supremum (0 interpreted as 2^32)
{
double a, r;
if ( N == 1 || alpha <= 0.0 )
return 0;
if ( alpha * DBL_EPSILON >= 0.5 )
return Rangrid(Rand, N);
a = alpha / (alpha + 1.0);
do
{
r = Randouble(Rand);
if ( N )
r *= 1.0 - pow(a, (double)N);
r = log(1.0 - r) / log(a);
}
while ( r >= N ); // safety
return (int)r;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Rangrid
//
// Purpose: Random integer from [0,bound-1].
//
// Method: Development of Ranint.
//
// History: John Skilling 6 May 1995 - 15 Jan 2002
//-----------------------------------------------------------------------------
//
unsigned Rangrid( // O Value
Rand_t Rand, // I O Random generator state
unsigned bound) // I Supremum (0 interpreted as 2^32)
{
unsigned i, M, N;
if ( bound == 0 )
return (unsigned)Ranint(Rand);
N = (unsigned)(-1) / bound;
M = N * bound;
do i = (unsigned)Ranint(Rand);
while ( i >= M );
return i / N;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Ranperm
//
// Purpose: Random permutation of {0,1,2,...,n-1}.
//
// History: John Skilling 23 May 1998, 24 Jan 1999, 9 Nov 2000
//-----------------------------------------------------------------------------
//
void Ranperm(
Rand_t Rand, // I O Random generator state
int n, // I Dimension
int* perm) // O Output permutation
{
int i, m;
for ( m = 0; m < n; ++m )
{
i = Rangrid(Rand, (unsigned)(m + 1));
if ( i < m )
perm[m] = perm[i];
perm[i] = m;
}
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Ran2gauss
//
// Purpose: Draw sample from normalised form of
//
// exp( - g.x - x.A.x / 2 ) ( A non-negative )
//
// History: JS 31 Dec 2001
//-----------------------------------------------------------------------------
//
void Ran2gauss(
Rand_t Rand, // I O Random generator state
double g1, // I x gradient at origin
double g2, // I y gradient at origin
double A11, // I xx curvature >= 0
double A12, // I xy curvature, A12*A12 <= A11*A22
double A22, // I yy curvature >= 0
double* x, // O x sample position
double* y) // O y sample position
{
double d = A11 * A22 - A12 * A12;
double xbar = (g2 * A12 - g1 * A22) / d;
double ybar = (g1 * A12 - g2 * A11) / d;
*x = Rangauss(Rand) * sqrt(A22 / d);
*y = Rangauss(Rand) / sqrt(A22) - *x * A12 / A22;
*x += xbar;
*y += ybar;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Ran1pos
//
// Purpose: Draw positive sample (x +ve) from normalised form of
//
// exp( - g x - A x^2 / 2 )
//
// History: JS 30 Nov 1997
//-----------------------------------------------------------------------------
//
double Ran1pos( // O sample value
Rand_t Rand, // I O random generator state
double g, // I coeff of x
double A) // I coeff of x^2, >= 0
{
double a, x;
a = sqrt(A);
if ( 0.3 * a > g ) // Reject from completed normal curve
{
do x = Rangauss(Rand) / a - g / A;
while ( x < 0.0 );
}
else // Reject from bounding exponential
{
do x = -log(Randouble(Rand)) / g;
while ( -log(Randouble(Rand)) < A * x * x / 2.0 );
}
return x;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Ran2pos
//
// Purpose: Draw sample in positive quadrant from normalised form of
//
// exp( - g1 x - g2 y - (A11 x^2 + 2 A12 x y + A22 y^2) / 2 )
//
// History: JS 31 Dec 2001, 3 Oct 2002
//-----------------------------------------------------------------------------
//
void Ran2pos(
Rand_t Rand, // I O random generator state
double g1, // I coeff of |x|, > 0
double g2, // I coeff of |y|, > 0
double A11, // I coeff of x^2, >= 0
double A12, // I coeff of xy, |A12| < sqrt(A11*A22)
double A22, // I coeff of y^2, >= 0
double* x, // O sample
double* y) // O sample
{
double a;
if ( A12 * A12 <= DBL_EPSILON * A11 * A22 )
{
*x = Ran1pos(Rand, g1, A11);
*y = Ran1pos(Rand, g2, A22);
return;
}
g1 /= sqrt(A11);
g2 /= sqrt(A22);
a = A12 / sqrt(A11 * A22);
if ( a > 1.0 )
a = 1.0;
if ( a < -1.0 )
a = -1.0;
if ( g2 <= g1 )
Positive2(Rand, g1, g2, -a, x, y);
else
Positive2(Rand, g2, g1, -a, y, x);
*x /= sqrt(A11);
*y /= sqrt(A22);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Positive2
//
// Purpose: Draw sample in positive quadrant from normalised form of
//
// exp( - u x - v y - (x^2 - 2 a x y + y^2) / 2 )
//
// with u >= v as well as |a| < 1
//
// Method:
// Apart from the simple special case u > 0.3 or so, v > 0.3 or so:
//
// Sample x from | exp -x^2/2 - u x + (a x - v)^2/2 , ax > v
// | exp -x^2/2 - u x , ax < v
//
// then
// Sample y from | exp -(y - a x + v)^2 / 2 , ax > v
// | exp - y^2 / 2 , ax < v
// with
// Acceptance | 1 , ax > v
// | exp (a x - v)y , ax < v
//
// Provided u >= v, these algorithms always sample with O(1) efficiency.
//
// General sampler for ANY logconcave function of x (such as the above) is
// exp( height + ycap + q * (x - xcap) ), x > xcap (q < 0)
// exp( height + ycap + p * (x - xcap) ), x < xcap (p > 0)
// where (xcap,ycap) is apex of required curve over all x, height = O(1) +ve,
// and p,q define left and right exponentials tangent to the required curve
// A x^2 + B x + C (with A < 0), according to
// p = Lslope(x,y, A,B,C) = 2*A*x + B + 2 * sqrt(-A *(y - A*x*x - B*x - C))
// q = Rslope(x,y, A,B,C) = 2*A*x + B - 2 * sqrt(-A *(y - A*x*x - B*x - C))
// This method always samples with O(1) efficiency.
//
// Subsidiary codes crafted to evaluate all sqrt arguments definitely +ve,
// left slope p definitely +ve, and right slope q definitely -ve.
//
// History: JS 31 Dec 2001, 3 Oct 2002
//-----------------------------------------------------------------------------
//
static void Positive2(
Rand_t Rand, // I O random generator state
double u, // I coeff of x
double v, // I coeff of y
double a, // I coeff of xy, 0 < |a| <= 1
double* x0, // O sample
double* y0) // O sample
{
double height = 0.5000;
double x, y, accept, xcap, p, q, r, s, dx;
if ( v > 0.3000 )
// Special case: sample around (0,0) from exp - u x - v y
{
do
{
x = -log(Randouble(Rand)) / u;
y = -log(Randouble(Rand)) / v;
accept = a * x * y - 0.5 * (x * x + y * y);
}
while ( accept < log(Randouble(Rand)) );
}
else
// General sampler ....
{
// Bi-exponential for x
for ( ; ; )
{
if ( a > 0.0 )
{
if ( v < 0.0 )
Positive2A(u, v, a, height, &xcap, &p, &q);
else
Positive2B(u, v, a, height, &xcap, &p, &q);
}
else
{
if ( v < 0.0 )
Positive2C(u, v, a, height, &xcap, &p, &q);
else
Positive2D(u, height, &xcap, &p, &q);
}
// Sample x
for ( ; ; )
{
s = (xcap == 0.0 || Randouble(Rand) < p / (p - q)) ? q : p;
dx = log(Randouble(Rand)) / s;
x = dx + xcap;
if ( x <= 0.0 )
continue;
accept = -dx * (u + xcap + 0.5 * dx);
r = a * x - v;
if ( r > 0.0 )
accept += a * dx * (0.5 * a * (x + xcap) - v);
accept -= height + s * dx;
if ( log(Randouble(Rand)) < accept )
break;
}
// Sample y|x
if ( - v + a * x > 0.0 )
{
y = - v + a * x + Rangauss(Rand);
if ( y >= 0.0 )
break;
}
else
{
y = Rangauss(Rand);
if ( y >= 0.0 && log(Randouble(Rand)) < (- v + a * x) * y )
break;
}
}
}
// Exit
*x0 = x;
*y0 = y;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Positive2A
//
// Purpose: Set bi-exponential sampler for Positive2 in case a > 0, v <= 0
// x = inf |
// | exp - x^2 / 2 - u x + (a x - v)^2 / 2
// x = 0 |
//
// History: JS 31 Dec 2001, 3 Oct 2002
//-----------------------------------------------------------------------------
//
static void Positive2A(
double u, // I >= v
double v, // I <= 0
double a, // I > 0
double height, // I height of sampler cusp above target maximum
double* xc, // O target maximum
double* p0, // O sampler exp( yc + p0 * (x-xc) ), x < xc (p0 > 0)
double* q0) // O sampler exp( yc + q0 * (x-xc) ), x > xc (q0 < 0)
{
double y0, m0, xcap, ycap;
double d, p, q;
d = 1.0 - a * a;
if ( d < DBL_EPSILON )
d = DBL_EPSILON;
// Set boundaries (0,y0)...
// and slopes m0
y0 = 0.5 * v * v;
m0 = -(u + a * v);
// Find apex from slope=0
if ( m0 <= 0.0 ) // apex at 0
{
xcap = 0.0;
ycap = height + y0;
p = 0.0; // arbitrary
q = m0 - sqrt(2.0 * d * height); // Rslope(xcap, ycap, -d/2, m0, v*v/2)
}
else // apex in (0,inf)
{
xcap = m0 / d;
ycap = height + 0.5 * (m0 * xcap + v * v);
if ( ycap - y0 <= m0 * xcap )
p = sqrt(2.0 * d * height); // Lslope(xcap, ycap, -d/2, m0, v*v/2)
else
p = (ycap - y0) / xcap;
q = -sqrt(2.0 * d * height); // Rslope(xcap, ycap, -d/2, m0, v*v/2)
}
*xc = xcap;
*p0 = p;
*q0 = q;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Positive2B
//
// Purpose: Set bi-exponential sampler for Positive2 in case a > 0, v >= 0
//
// | exp - x^2 / 2 - u x + (a x - v)^2 / 2
// x2 = v/a |
// | exp - x^2 / 2 - u x
// x = 0 |
//
// History: JS 31 Dec 2001, 3 Oct 2002
//-----------------------------------------------------------------------------
//
static void Positive2B(
double u, // I >= v
double v, // I >= 0
double a, // I > 0
double height, // I height of sampler cusp above target maximum
double* xc, // O target maximum
double* p0, // O sampler exp( yc + p0 * (x-xc) ), x < xc (p0 > 0)
double* q0) // O sampler exp( yc + q0 * (x-xc) ), x > xc (q0 < 0)
{
double x2, y2, m2;
double d, q, r;
d = 1.0 - a * a;
if ( d < DBL_EPSILON )
d = DBL_EPSILON;
// Set boundaries (0,y0)...(x2,y2)...
// and slopes +ve,-ve m2
x2 = v / a;
y2 = x2 * (- u - 0.5 * x2);
m2 = - u - x2;
// Apex necessarily at 0
r = (height - y2) + m2 * x2;
if ( r <= 0.0 ) // Rslope(0, height, -1/2., -u, 0)
q = -u - sqrt(2.0 * height);
else // Rslope(0, height, -d/2, -u-a*v, v*v/2)
q = -(u + a * v) - sqrt(2.0 * d * (d * height + a * a * r));
*xc = 0.0;
*p0 = 0.0; // arbitrary
*q0 = q;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Positive2C
//
// Purpose: Set bi-exponential sampler for Positive2 in case a < 0, v <= 0
//
// | exp - x^2 / 2 - u x
// x1 = -v/-a |
// | exp - x^2 / 2 - u x + (a x - v)^2 / 2
// x = 0 |
//
// History: JS 31 Dec 2001, 3 Oct 2002
//-----------------------------------------------------------------------------
//
static void Positive2C(
double u, // I >= v
double v, // I <= 0
double a, // I < 0
double height, // I height of sampler cusp above target maximum
double* xc, // O target maximum
double* p0, // O sampler exp( yc + p0 * (x-xc) ), x < xc (p0 > 0)
double* q0) // O sampler exp( yc + q0 * (x-xc) ), x > xc (q0 < 0)
{
double x1, y0, y1, m0, m1, xcap, ycap;
double d, p, q, r;
d = 1.0 - a * a;
if ( d < DBL_EPSILON )
d = DBL_EPSILON;
// Set boundaries (0,y0)...(x1,y1)...
// and slopes m0 m1
x1 = v / a;
y1 = x1 * (- u - 0.5 * x1);
m1 = - u - x1; // -ve
y0 = 0.5 * v * v;
m0 = -(u + a * v);
// Find apex from slope=0
if ( m0 <= 0.0 ) // apex at 0
{
xcap = 0.0;
ycap = height + 0.5 * v * v;
p = 0.0; // arbitrary
r = (ycap - y1) + m1 * x1;
if ( r <= 0.0 ) // Rslope(0, ycap, -d/2, -u-a*v, v*v/2)
q = m0 - sqrt(2.0 * d * height);
else // Rslope(0, ycap, -1/2., -u, 0)
q = (v - u) + 2.0 * height / (v - sqrt(2.0 * ycap));
}
else // apex in (0,x1)
{
xcap = m0 / d;
ycap = height + 0.5 * (d * xcap * xcap + v * v);
r = (ycap - y0) - m0 * xcap;
if ( r <= 0.0 ) // Lslope(xcap, ycap, -d/2, -u-a*v, v*v/2)
p = sqrt(2.0 * d * height);
else
p = (ycap - y0) / xcap;
r = (ycap - y1) - m1 * (xcap - x1);
if ( r <= 0.0 ) // Rslope(xcap, ycap, -d/2, -u-a*v, v*v/2)
q = -sqrt(2.0 * d * height);
else // Rslope(xcap, ycap, -1/2., -u, 0)
q = (a * (u - v) + (1.0 + a) * v) * a / d
- sqrt(2.0 * r + (xcap - x1) * (xcap - x1));
}
*xc = xcap;
*p0 = p;
*q0 = q;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Positive2D
//
// Purpose: Set bi-exponential sampler for Positive2 in case a < 0, v >= 0
// x = inf |
// | exp - x^2 / 2 - u x
// x = 0 |
//
// History: JS 31 Dec 2001, 3 Oct 2002
//-----------------------------------------------------------------------------
//
static void Positive2D(
double u, // I >= v >= 0
double height, // I height of sampler cusp above target maximum
double* xc, // O target maximum
double* p0, // O sampler exp( yc + p0 * (x-xc) ), x < xc (p0 > 0)
double* q0) // O sampler exp( yc + q0 * (x-xc) ), x > xc (q0 < 0)
{
// Apex necessarily at 0
*xc = 0.0;
*p0 = 0.0; // arbitrary
*q0 = -u - sqrt(2.0 * height); // Rslope(0, height, -1/2., -u, 0)
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Ran1posneg
//
// Purpose: Draw sample from normalised form of
//
// exp( - u|x| - f x - A x^2 / 2 )
//
// Method:
// General sampler for ANY logconcave function of x (such as the above) is
// exp( height + ycap + q * (x - xcap) ), x > xcap (q < 0)
// exp( height + ycap + p * (x - xcap) ), x < xcap (p > 0)
// where (xcap,ycap) is apex of required curve over all x, height = O(1) +ve,
// and p,q define left and right exponentials tangent to the required curve
// a x^2 + b x + c (with A < 0), according to
// p = Lslope(x,y, a,b,c) = 2*a*x + b + 2 * sqrt(-a *(y - a*x*x - b*x - c))
// q = Rslope(x,y, a,b,c) = 2*a*x + b - 2 * sqrt(-a *(y - a*x*x - b*x - c))
// This method always samples with O(1) efficiency.
//
// History: JS 31 Dec 2001, 3 Oct 2000
//-----------------------------------------------------------------------------
//
double Ran1posneg( // O sample value
Rand_t Rand, // I O random generator state
double f, // I coeff of x
double u, // I coeff of |x|, > 0
double A) // I coeff of x^2, >= 0
{
static const double height = 0.5000;
double x, xcap, ycap;
double accept, p, q, r, m9, m0;
// Special case of no curvature
if ( A <= 0.0 )
{
if ( Randouble(Rand) < 0.5 * (1.0 + f / u) )
return log(Randouble(Rand)) / (u - f);
else
return -log(Randouble(Rand)) / (u + f);
}
// Scale general case to unit curvature
f /= sqrt(A);
u /= sqrt(A);
m9 = u - f;
m0 = -u - f;
// Set dominating bi-exponential sampler
if ( m9 < 0.0 ) // Apex in x -ve
{
xcap = m9;
ycap = height + 0.5 * xcap * xcap;
p = sqrt(2.0 * height); // Lslope(xcap, ycap, -1/2., m9, 0)
if ( ycap <= m9 * xcap )
q = -sqrt(2.0 * height); // Rslope(xcap, ycap, -1/2., m9, 0)
else
{
r = ycap - m0 * xcap;
if ( r <= 0.0 )
q = ycap / xcap;
else // Rslope(xcap, ycap, -1/2., m0, 0)
q = -2.0 * u - sqrt(2.0 * r + m9 * m9);
}
}
else if ( m0 <= 0.0 ) // Apex at x = 0
{
xcap = 0.0;
ycap = height;
p = m9 + sqrt(2.0 * height); // Lslope(xcap, ycap, -1/2., m9, 0)
q = m0 - sqrt(2.0 * height); // Rslope(xcap, ycap, -1/2., m0, 0)
}
else // Apex in x +ve
{
xcap = m0;
ycap = height + 0.5 * xcap * xcap;
if ( ycap <= m0 * xcap )
p = sqrt(2.0 * height); // Lslope(xcap, ycap, -1/2., m0, 0)
else
{
r = ycap - m9 * xcap;
if ( r <= 0.0 )
p = ycap / xcap;
else // Lslope(xcap, ycap, -1/2., m9, 0)
p = 2.0 * u + sqrt(2.0 * r + m0 * m0);
}
q = -sqrt(2.0 * height); // Rslope(xcap, ycap, -1/2., m0, 0)
}
// Sample x
do
{
// accept = -log(sampler)
if ( Randouble(Rand) < p / (p - q) )
{
x = xcap + log(Randouble(Rand)) / q;
accept = -(ycap + q * (x - xcap));
}
else
{
x = xcap + log(Randouble(Rand)) / p;
accept = -(ycap + p * (x - xcap));
}
// accept += log(true)
if ( x > 0.0 )
accept += x * (- u - f - 0.5 * x);
else
accept += x * (u - f - 0.5 * x);
}
while ( log(Randouble(Rand)) > accept );
// Exit
return x / sqrt(A);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Ran2posneg
//
// Purpose: Draw sample from normalised form of
//
// exp( - u|x| - v|y| - f x - g y - (A11 x^2 + 2 A12 x y + A22 y^2) / 2 )
//
// History: JS 31 Dec 2001, 3 Oct 2002
//-----------------------------------------------------------------------------
//
void Ran2posneg(
Rand_t Rand, // I O random generator state
double f, // I coeff of x
double g, // I coeff of y
double u, // I coeff of |x|, > 0
double v, // I coeff of |y|, > 0
double A11, // I coeff of x^2, >= 0
double A12, // I coeff of xy, |A12| < sqrt(A11*A22)
double A22, // I coeff of y^2, >= 0
double* x, // O sample
double* y) // O sample
{
double a;
if ( A12 * A12 <= DBL_EPSILON * A11 * A22 )
{
*x = Ran1posneg(Rand, f, u, A11);
*y = Ran1posneg(Rand, g, v, A22);
return;
}
f /= sqrt(A11);
u /= sqrt(A11);
g /= sqrt(A22);
v /= sqrt(A22);
a = A12 / sqrt(A11 * A22);
if ( a > 1.0 )
a = 1.0;
if ( a < -1.0 )
a = -1.0;
if ( f <= 0.0 )
{
if ( g <= 0.0 )
{
if ( -g - v >= -f - u )
Posneg2(Rand, -f, -g, u, v, -a, x, y);
else
Posneg2(Rand, -g, -f, v, u, -a, y, x);
}
else
{
if ( g - v >= -f - u )
Posneg2(Rand, -f, g, u, v, a, x, y);
else
Posneg2(Rand, g, -f, v, u, a, y, x);
*y = - *y;
}
}
else
{
if ( g <= 0.0 )
{
if ( -g - v >= f - u )
Posneg2(Rand, f, -g, u, v, a, x, y);
else
Posneg2(Rand, -g, f, v, u, a, y, x);
}
else
{
if ( g - v >= f - u )
Posneg2(Rand, f, g, u, v, -a, x, y);
else
Posneg2(Rand, g, f, v, u, -a, y, x);
*y = - *y;
}
*x = - *x;
}
*x /= sqrt(A11);
*y /= sqrt(A22);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Posneg2
//
// Purpose: Draw sample from normalised form of
//
// exp( - u|x| - v|y| + f x + g y - (x^2 - 2 a x y + y^2) / 2 )
//
// with f >= 0, g >= 0, f - u <= g - v
// as well as u > 0, v > 0, 0 < |a| <= 1
//
// Method:
// Apart from the simple special case u - f > 0.3 or so, v - g > 0.3 or so:
//
// | exp -x^2/2 + f x - u|x| + (g - v + a x)^2/2 , g-v+ax > 0
// Sample x from | exp -x^2/2 + f x - u|x| , |g+ax| < v
// | exp -x^2/2 + f x - u|x| + (g + v + a x)^2/2 , g+v+ax < 0
// then
// | exp -(y - g + v - a x)^2 / 2 , g-v+ax > 0
// Sample y from | exp - y^2 / 2 , |g+ax| < v
// | exp -(y - g - v - a x)^2 / 2 , g+v+ax < 0
// with
// | exp - v (|y| - y) , g-v+ax > 0
// Acceptance | exp - v |y| + (g + a x) y , |g+ax| < v
// | exp - v (|y| + y) , g+v+ax < 0
//
// Provided f-u <= g-v, these algorithms always sample with O(1) efficiency.
//
// General sampler for ANY logconcave function of x (such as the above) is
// exp( height + ycap + q * (x - xcap) ), x > xcap (q < 0)
// exp( height + ycap + p * (x - xcap) ), x < xcap (p > 0)
// where (xcap,ycap) is apex of required curve over all x, height = O(1) +ve,
// and p,q define left and right exponentials tangent to the required curve
// A x^2 + B x + C (with A < 0), according to
// p = Lslope(x,y, A,B,C) = 2*A*x + B + 2 * sqrt(-A *(y - A*x*x - B*x - C))
// q = Rslope(x,y, A,B,C) = 2*A*x + B - 2 * sqrt(-A *(y - A*x*x - B*x - C))
// This method always samples with O(1) efficiency.
//
// Subsidiary codes crafted to evaluate all sqrt arguments definitely +ve,
// left slope p definitely +ve, and right slope q definitely -ve.
//
// History: JS 31 Dec 2001, 3 Oct 2002
//-----------------------------------------------------------------------------
//
static void Posneg2(
Rand_t Rand, // I O random generator state
double f, // I coeff of x, >= 0
double g, // I coeff of y, >= 0
double u, // I coeff of |x|, > 0
double v, // I coeff of |y|, > 0
double a, // I coeff of xy, -1 < a < 1
double* x0, // O sample
double* y0) // O sample
{
double height = 0.5000;
double x, y, accept, xcap, p, q, r, s, dx;
if ( v - g > 0.3000 )
// Special case: sample around (0,0) from exp f x + g y - u|x| - v|y|
{
do
{
x = (Randouble(Rand) > 0.5 * (1.0 - f / u))
? log(Randouble(Rand)) / (f - u)
: log(Randouble(Rand)) / (f + u);
y = (Randouble(Rand) > 0.5 * (1.0 - g / v))
? log(Randouble(Rand)) / (g - v)
: log(Randouble(Rand)) / (g + v);
accept = a * x * y - 0.5 * (x * x + y * y);
}
while ( accept < log(Randouble(Rand)) );
*x0 = x;
*y0 = y;
return;
}
// General bi-exponential for x
do
{
if ( a > 0.0 )
{
if ( g > v )
Posneg2A(f + u, f - u, g + v, g - v, a, height, &xcap, &p, &q);
else
Posneg2B(f + u, f - u, g + v, g - v, a, height, &xcap, &p, &q);
}
else
{
if ( g > v )
Posneg2C(f + u, f - u, g + v, g - v, a, height, &xcap, &p, &q);
else
Posneg2D(f + u, f - u, g + v, g - v, a, height, &xcap, &p, &q);
}
// Sample x
do
{
s = (Randouble(Rand) < p / (p - q)) ? q : p;
dx = log(Randouble(Rand)) / s;
x = dx + xcap;
if ( x > 0.0 )
accept = dx * (f - u - 0.5 * (xcap + x));
else
accept = dx * (f + u - 0.5 * (xcap + x));
r = g - v + a * x;
if ( r > 0.0 )
accept += a * dx * (r - 0.5 * a * dx);
r = g + v + a * x;
if ( r < 0.0 )
accept += a * dx * (r - 0.5 * a * dx);
accept -= height + s * dx;
}
while ( log(Randouble(Rand)) > accept );
// Sample y|x
if ( g - v + a * x > 0.0 )
{
y = g - v + a * x + Rangauss(Rand);
accept = (y >= 0.0) ? 0.0 : 2.0 * v * y;
}
else if ( g + v + a * x < 0.0 )
{
y = g + v + a * x + Rangauss(Rand);
accept = (y > 0.0) ? -2.0 * v * y : 0.0;
}
else
{
y = Rangauss(Rand);
accept = (g + a * x) * y - v * fabs(y);
}
}
while ( accept < 0.0 && accept < log(Randouble(Rand)) );
// Exit
*x0 = x;
*y0 = y;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Posneg2A
//
// Purpose: Set bi-exponential sampler for Posneg2 in case a > 0, g >= v
//
// | exp - x^2 / 2 + f x - u x + (g - v + a x)^2 / 2
// x = 0 |
// | exp - x^2 / 2 + f x + u x + (g - v + a x)^2 / 2
// x2 = -(g-v)/a |
// | exp - x^2 / 2 + f x + u x
// x1 = -(g+v)/a |
// | exp - x^2 / 2 + f x + u x + (g + v + a x)^2 / 2
//
// History: JS 31 Dec 2001, 3 Oct 2002
//-----------------------------------------------------------------------------
//
static void Posneg2A(
double fpu, // I f + u > 0
double fmu, // I f - u <= gmv
double gpv, // I g + v > 0
double gmv, // I g - v >= 0
double a, // I > 0
double height, // I height of sampler cusp above target maximum
double* xc, // O target maximum
double* p0, // O sampler exp( yc + p0 * (x-xc) ), x < xc (p0 > 0)
double* q0) // O sampler exp( yc + q0 * (x-xc) ), x > xc (q0 < 0)
{
double x1, x2, y0, y1, y2, m0, m1, m2, m9, xcap, ycap;
double d, p, q, r, s, t, u;
d = 1.0 - a * a;
if ( d < DBL_EPSILON )
d = DBL_EPSILON;
// Set boundaries ...(x1,y1)...(x2,y2)...(0,y0)...
// and slopes m1 m2 m9,m0
x1 = -gpv / a;
y1 = x1 * (fpu - 0.5 * x1);
m1 = fpu - x1;
x2 = -gmv / a;
y2 = x2 * (fpu - 0.5 * x2);
m2 = fpu - x2;
y0 = 0.5 * gmv * gmv;
m9 = fpu + a * gmv; // +ve
m0 = fmu + a * gmv;
// Find apex from slope=0
if ( m0 <= 0.0 ) // apex at 0
{
xcap = 0.0;
ycap = height + y0;
if (ycap <= y2 - m2*x2) // Lslope(xcap,ycap,-d/2,fpu+a*gmv,gmv*gmv/2)
p = m9 + sqrt(2.0 * d * height);
else
{
r = (ycap - y1) + m1 * x1;
if ( r <= 0.0 ) // Lslope(xcap, ycap, -1/2., fpu, 0)
p = fpu + sqrt(2.0 * ycap);
else // Lslope(xcap,ycap,-d/2,fpu+a*gpv,gpv*gpv/2)
p = (fpu + a * gpv) + sqrt(2.0 * d * (d * ycap + a * a * r));
} // Rslope(xcap,ycap,-d/2,fmu+a*gmv,gmv*gmv/2)
q = m0 - sqrt(2.0 * d * height);
}
else // apex in (0,inf)
{
xcap = m0 / d;
ycap = height + 0.5 * (d * xcap * xcap + gmv * gmv);
if (ycap - y0 <= m0*xcap) // Lslope(xcap,ycap,-d/2,fmu+a*gmv,gmv*gmv/2)
p = sqrt(2.0 * d * height);
else
{
r = (ycap - y0) - m9 * xcap;
if ( r <= 0.0 )
p = (ycap - y0) / xcap;
else
{
s = (ycap - y2) - m2 * (xcap - x2);
if ( s <= 0.0 ) // Lslope(xcap,ycap,-d/2,fpu+a*gmv,gmv*gmv/2)
p = (fpu - fmu) + sqrt(d * (2.0 * r + d * xcap * xcap));
else
{
t = (ycap - y1) - m1 * (xcap - x1);
if ( t <= 0.0 )
{ // Lslope(xcap,ycap,-1/2.,fpu,0)
u = 2.0 * s - 2.0 * xcap * x2 + x2 * x2;
p = fpu + u / (xcap + sqrt(u + xcap * xcap));
}
else
{ // Lslope(xcap,ycap,-d/2,fpu+a*gpv,gpv*gpv/2)
u = fmu + a * gmv + d * gpv / a;
p = ((fpu - fmu) + a * (gpv - gmv))
+ sqrt(2.0 * d * t + u * u);
}
}
}
} // Rslope(xcap,ycap,-d/2,fmu+a*gmv,gmv*gmv/2)
q = -sqrt(2.0 * d * height);
}
*xc = xcap;
*p0 = p;
*q0 = q;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Posneg2B
//
// Purpose: Set bi-exponential sampler for Posneg2 in case a > 0, g <= v
//
// | exp - x^2 / 2 + f x - u x + (g - v + a x)^2 / 2
// x2 = (v-g)/a |
// | exp - x^2 / 2 + f x - u x
// x = 0 |
// | exp - x^2 / 2 + f x + u x
// x1 = -(v+g)/a |
// | exp - x^2 / 2 + f x + u x + (g + v + a x)^2 / 2
//
// History: JS 31 Dec 2001, 3 Oct 2002
//-----------------------------------------------------------------------------
//
static void Posneg2B(
double fpu, // I f + u > 0
double fmu, // I f - u <= gmv
double gpv, // I g + v > 0
double gmv, // I g - v <= 0
double a, // I > 0
double height, // I height of sampler cusp above target maximum
double* xc, // O target maximum
double* p0, // O sampler exp( yc + p0 * (x-xc) ), x < xc (p0 > 0)
double* q0) // O sampler exp( yc + q0 * (x-xc) ), x > xc (q0 < 0)
{
double x1, x2, y1, y2, m1, m2;
double d, p, q, t;
d = 1.0 - a * a;
if ( d < DBL_EPSILON )
d = DBL_EPSILON;
// Set boundaries ...(x1,y1)...(0,y0)...(x2,y2)...
// and slopes m1 +ve,-ve m2
x1 = -gpv / a;
y1 = x1 * (fpu - 0.5 * x1);
m1 = fpu - x1;
x2 = -gmv / a;
y2 = x2 * (fmu - 0.5 * x2);
m2 = fmu - x2;
// Apex necessarily at 0
t = m1 * x1 - (y1 - height);
if ( t <= 0.0 ) // Lslope(0,height,-1/2.,fpu,0)
p = fpu + sqrt(2.0 * height);
else // Lslope(0,height,-d/2,fpu+a*gpv,gpv*gpv/2)
p = (fpu + a * gpv) + sqrt(d * (2.0 * t + d * x1 * x1));
t = m2 * x2 - (y2 - height);
if ( t <= 0.0 ) // Rslope(0,height,-1/2.,fmu,0)
q = fmu - sqrt(2.0 * height);
else // Rslope(0,height,-d/2,fmu+a*gmv,gmv*gmv/2)
q = (fmu + a * gmv) - sqrt(d * (2.0 * t + d * x2 * x2));
*xc = 0.0;
*p0 = p;
*q0 = q;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Posneg2C
//
// Purpose: Set bi-exponential sampler for Posneg2 in case a < 0, g >= v
//
// | exp - x^2 / 2 + f x - u x + (g + v + a x)^2 / 2
// x2 = (g+v)/-a |
// | exp - x^2 / 2 + f x - u x
// x1 = (g-v)/-a |
// | exp - x^2 / 2 + f x - u x + (g - v + a x)^2 / 2
// x = 0 |
// | exp - x^2 / 2 + f x + u x + (g - v + a x)^2 / 2
//
// History: JS 31 Dec 2001, 3 Oct 2002
//-----------------------------------------------------------------------------
//
static void Posneg2C(
double fpu, // I f + u > 0
double fmu, // I f - u <= gmv
double gpv, // I g + v > 0
double gmv, // I g - v >= 0
double a, // I < 0
double height, // I height of sampler cusp above target maximum
double* xc, // O target maximum
double* p0, // O sampler exp( yc + p0 * (x-xc) ), x < xc (p0 > 0)
double* q0) // O sampler exp( yc + q0 * (x-xc) ), x > xc (q0 < 0)
{
double x1, x2, y0, y1, y2, m0, m1, m2, m9, xcap, ycap;
double d, p, q, r, s, t, u, v, w;
d = 1.0 - a * a;
if ( d < DBL_EPSILON )
d = DBL_EPSILON;
// Set boundaries ...(0,y0)...(x1,y1)...(x2,y2)...
// and slopes m9,m0 m1 m2
x1 = -gmv / a;
y1 = x1 * (fmu - 0.5 * x1);
m1 = fmu - x1; // -ve
x2 = -gpv / a;
y2 = x2 * (fmu - 0.5 * x2);
m2 = fmu - x2;
y0 = 0.5 * gmv * gmv;
m9 = fpu + a * gmv;
m0 = fmu + a * gmv;
// Find apex from slope=0
if ( m9 < 0.0 ) // apex in (-inf,0)
{
xcap = m9 / d;
ycap = height + 0.5 * (d * xcap * xcap + gmv * gmv);
p = sqrt(2. * d * height);// Lslope(xcap,ycap,-d/2,fpu+a*gmv,gmv*gmv/2)
r = (ycap - y0) - m9 * xcap;
if ( r <= 0.0 ) // Rslope(xcap,ycap,-d/2,fpu+a*gmv,gmv*gmv/2)
q = -sqrt(2.0 * d * height);
else
{
s = ycap - y0 - m0 * xcap;
if ( s <= 0.0 )
q = (ycap - y0) / xcap;
else
{
t = (ycap - y1) - m1 * (xcap - x1);
if ( t <= 0.0 ) // Rslope(xcap,ycap,-d/2,fmu+a*gmv,gmv*gmv/2)
q = (fmu - fpu) - sqrt(2.0 * d * s + m9 * m9);
else
{
u = (ycap - y2) - m2 * (xcap - x2);
if ( u <= 0.0 )
{ // Rslope(xcap,ycap,-1/2.,fmu,0)
v = 2.0 * t + (x1 - xcap) * (x1 - xcap);
w = (x1 * (1.0 - a) - 2.0 * xcap) * x1 * (1.0 + a);
q = (fmu - gmv)
- (2.0 * t + w) / (gmv - xcap + sqrt(v));
}
else
{ // Rslope(xcap,ycap,-d/2,fmu+a*gpv,gpv*gpv/2)
v = d * (2.0 * u + d * (x2 - xcap) * (x2 - xcap));
w = (fmu - fpu) - a * (gmv - gpv);
q = w - sqrt(v);
}
}
}
}
}
else if ( m0 <= 0.0 ) // apex at 0
{
xcap = 0.0;
ycap = height + 0.5 * gmv * gmv;
// Lslope(xcap,ycap,-d/2,fpu+a*gmv,gmv*gmv/2)
p = m9 + sqrt(2.0 * d * height);
r = ycap - y1 + m1 * x1;
if ( r <= 0.0 ) // Rslope(xcap,ycap,-d/2,fmu+a*gmv,gmv*gmv/2)
q = m0 - sqrt(2.0 * d * height);
else
{
s = ycap - y2 + m2 * x2;
if ( s <= 0.0 ) // Rslope(xcap,ycap,-1/2.,fmu,0)
q = (fmu - gmv) - 2.0 * height / (gmv + sqrt(2.0 * ycap));
else // Rslope(xcap,ycap,-d/2,fmu+a*gpv,gpv*gpv/2)
q = (a * (gpv - gmv) + m0) - sqrt(d * (2.0 * s + d * x2 * x2));
}
}
else // apex in (0,x1)
{
xcap = m0 / d;
ycap = height + 0.5 * (d * xcap * xcap + gmv * gmv);
r = ycap - y0 - m0 * xcap;
if ( r <= 0.0 ) // Lslope(xcap,ycap,-d/2,fmu+a*gmv,gmv*gmv/2)
p = sqrt(2.0 * d * height);
else
{
s = ycap - y0 - m9 * xcap;
if ( s <= 0.0 )
p = (ycap - y0) / xcap;
else // Lslope(xcap,ycap,-d/2,fpu+a*gmv,gmv*gmv/2)
p = (fpu - fmu) + sqrt(d * (2.0 * s + d * xcap * xcap));
}
r = ycap - y1 - m1 * (xcap - x1);
if ( r <= 0.0 ) // Rslope(xcap,ycap,-d/2,fmu+a*gmv,gmv*gmv/2)
q = -sqrt(2.0 * d * height);
else
{
s = ycap - y2 - m2 * (xcap - x2);
if ( s <= 0.0 )
{ // Rslope(xcap,ycap,-1/2.,fmu,0)
v = 2.0 * r + (fmu - x1) * (fmu - x1) * (1.0 + a * a) / d;
w = (a * (gmv - fmu) - (1.0 + a) * gmv) * a / d;
q = -v / (w + sqrt(2.0 * r + (xcap - x1) * (xcap - x1)));
}
else // Rslope(xcap,ycap,-d/2,fmu+a*gpv,gpv*gpv/2)
q = a * (gpv - gmv)
- sqrt(d * (2.0 * s + d * (xcap - x2) * (xcap - x2)));
}
}
*xc = xcap;
*p0 = p;
*q0 = q;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Posneg2D
//
// Purpose: Set bi-exponential sampler for Posneg2 in case a < 0, g <= v
//
// | exp - x^2 / 2 + f x - u x + (g + v + a x)^2 / 2
// x2 = (v+g)/-a |
// | exp - x^2 / 2 + f x - u x
// x = 0 |
// | exp - x^2 / 2 + f x + u x
// x1 = -(v-g)/-a |
// | exp - x^2 / 2 + f x + u x + (g - v + a x)^2 / 2
//
// History: JS 31 Dec 2001, 3 Oct 2002
//-----------------------------------------------------------------------------
//
static void Posneg2D(
double fpu, // I f + u > 0
double fmu, // I f - u <= gmv
double gpv, // I g + v > 0
double gmv, // I g - v <= 0
double a, // I < 0
double height, // I height of sampler cusp above target maximum
double* xc, // O target maximum
double* p0, // O sampler exp( yc + p0 * (x-xc) ), x < xc (p0 > 0)
double* q0) // O sampler exp( yc + q0 * (x-xc) ), x > xc (q0 < 0)
{
double x1, x2, y1, y2, m1, m2;
double d, p, q, t;
d = 1.0 - a * a;
if ( d < DBL_EPSILON )
d = DBL_EPSILON;
// Set boundaries ...(x1,y1)...(0,y0)...(x2,y2)...
// and slopes m1 +ve,-ve m2
x1 = -gmv / a;
y1 = x1 * (fpu - 0.5 * x1);
m1 = fpu - x1;
x2 = -gpv / a;
y2 = x2 * (fmu - 0.5 * x2);
m2 = fmu - x2;
// Apex necessarily at 0
t = m1 * x1 - (y1 - height);
if ( t <= 0.0 ) // Lslope(0, height, -1/2., fpu, 0)
p = fpu + sqrt(2.0 * height);
else // Lslope(0,height,-d/2,fpu+a*gmv,gmv*gmv/2)
p = (fpu + a * gmv) + sqrt(d * (2.0 * t + d * x1 * x1));
t = m2 * x2 - (y2 - height);
if ( t <= 0.0 ) // Rslope(0, height, -1/2., fmu, 0)
q = fmu - sqrt(2.0 * height);
else // Rslope(0,height,-d/2,fmu+a*gpv,gpv*gpv/2)
q = (fmu + a * gpv) - sqrt(d * (2.0 * t + d * x2 * x2));
*xc = 0.0;
*p0 = p;
*q0 = q;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: RanPos1
//
// Purpose: Draw sample in x >= 0 from normalised form of p(x) exp(-L(x))
//
// p(x) = s * delta(x) + 1
//
// L(x) = g * x + A * x * x / 2
//
// where g = gradL(0)
// A = gradgradL
//
// History: JS 29 Oct 1997, 30 Nov 1997, 3 Oct 2002
//-----------------------------------------------------------------------------
//
double RanPos1( // O Sample value on exit
Rand_t Rand, // I O Random generator state
double s, // I Spike amplitude
double g, // I Gaussian gradient at origin
double A) // I Gaussian curvature >= 0
{
double acc, mu, prob0, z;
acc = sqrt(A);
if ( 0.3 * acc > g ) // Reject from completed normal curve
{
mu = -g / A;
prob0 = exp(g * mu / 2.0) * sqrt(A / TwoxPi);
prob0 = 1.0 / (1.0 + s * prob0);
do
{
if ( Randouble(Rand) > prob0 )
z = 0.0;
else
z = mu + Rangauss(Rand) / acc;
}
while ( z < 0.0 );
}
else // Reject from bounding exponential
{
prob0 = 1.0 / (1.0 + s * g);
do
{
if ( Randouble(Rand) > prob0 )
{
z = 0.0;
break;
}
else
{
z = -log(Randouble(Rand)) / g;
}
}
while ( -log(Randouble(Rand)) < A * z * z / 2.0 );
}
return z;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: RanPos01
//
// Purpose: Draw sample in 0 < x < 1 from normalised form of
//
// exp( - g * x - A * x * x / 2 )
//
// History: JS 9 Jun 1998
//-----------------------------------------------------------------------------
//
double RanPos01( // O Sample value on exit
Rand_t Rand, // I O Random generator state
double g, // I Gaussian gradient at origin
double A) // I Gaussian curvature >= 0
{
double a, b, E, x, x0;
int flag = 0;
if ( g < -A / 2.0 )
{
g = -A - g;
flag = 1;
}
if ( A <= sqrt(DBL_EPSILON) )
{
if ( g * g < DBL_EPSILON )
x = Randouble(Rand);
else
{
E = 1.0 - exp(-g);
do x = - log(1.0 - E * Randouble(Rand)) / g;
while ( x >= 1.0 );
}
}
else
{
A = sqrt(A);
a = g / A;
if ( g > 0.0 )
{
x0 = 1.0 / (sqrt(1.0 + 0.25 * a * a) + 0.5 * a);
if ( x0 > A )
x0 = A;
b = x0 + a;
E = 1.0 - exp(-A * b);
if ( E * E < DBL_EPSILON )
do
{
do x = A * Randouble(Rand);
while ( log(Randouble(Rand)) > -0.5 * (x - x0) * (x - x0) );
}
while ( x >= A );
else
do
{
do x = - log(1.0 - E * Randouble(Rand)) / b;
while ( log(Randouble(Rand)) > -0.5 * (x - x0) * (x - x0) );
}
while ( x >= A );
}
else
{
b = a + A;
x0 = (b < 1.0) ? b : 1.0;
E = 1.0 - exp(-b * x0);
if ( E * E < DBL_EPSILON )
do
{
do x = b * Randouble(Rand);
while ( log(Randouble(Rand)) > -0.5 * (x - x0) * (x - x0) );
x = (Ranint(Rand) < 0) ? - x - a : x - a;
}
while ( x * (x - A) > 0.0 );
else
do
{
do x = -log(1.0 - E * Randouble(Rand)) / x0;
while ( log(Randouble(Rand)) > -0.5 * (x - x0) * (x - x0) );
x = (Ranint(Rand) < 0) ? - x - a : x - a;
}
while ( x * (x - A) > 0.0 );
}
x /= A;
}
return flag ? 1.0 - x : x;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: Ran1posX
//
// Purpose: Draw sample in x >= 0 from normalised form of
//
// x * exp( - g * x - A * x * x / 2 )
//
// History: JS 14 Jan 2003
//-----------------------------------------------------------------------------
//
double Ran1posX( // O Sample value on exit
Rand_t Rand, // I O Random generator state
double g, // I Gaussian gradient at origin
double A) // I Gaussian curvature >= 0
{
double a, x, y, xcap, accept;
if ( A < 0.0 )
return 0.0;
if ( A == 0.0 && g <= 0.0 )
return 0.0;
xcap = (g >= 0.0) ? 2.0 / (sqrt(g * g + 4.0 * A) + g)
: (sqrt(g * g + 4.0 * A) - g) / (2.0 * A); // Apex
a = 1.7000 / sqrt(A + 1.0 / (xcap * xcap)); // Adequate Cauchy width
do // Reject from bounding Cauchy
{
do
{
y = Rancauchy(Rand);
x = xcap + y * a;
}
while ( x <= 0.0 );
accept = log((1.0 + y * y) * x / xcap)
+ (xcap - x) * (g + 0.5 * A * (xcap + x));
}
while ( accept < log(Randouble(Rand)) );
return x;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function:
// infinity - g*x - A*x*x/2
// logerf := log INTEGRAL e dx
// x=0
//
// = log( sqrt(pi/2A) exp(g*g/2A) (1 - erf(g/sqrt(2A)) )
//
// History: JS 25 Nov 1997 From "erf" code
// 31 Mar 1998, 9 Jun 1998
// 23 Jun 1998 Polish
//-----------------------------------------------------------------------------
//
double logerf( // O Output value
double g, // I Gradient at origin
double A) // I Curvature at origin
{
double a, a0, a1, b0, b1, f, q, r, t, y;
if ( A <= 0.0 )
return -log(g);
a = sqrt(g * g / A);
if ( a < 2.0 ) // before which continued fraction too slow
{
// Power series, proportional error = DBL_EPSILON * exp(a*a/2)
t = a * a / 2.0;
q = r = a;
for ( f = 1.5; q > r * DBL_EPSILON; f += 1.0 )
r += q *= t / f;
if ( g >= 0.0 )
y = log(SqrPi2 * exp(t) - r);
else
y = log(SqrPi2 * exp(t) + r);
}
else if ( a < 8.6 ) // after which asymptotic series is fully accurate
{
// Continued fraction, proportional error = DBL_EPSILON
b0 = q = 0.0;
a0 = b1 = f = 1.0;
a1 = t = a * a / 2.0;
for ( f = 1.0; a0 / a1 - b0 / b1 > DBL_EPSILON; f = 1.0 / a1 )
{
q += 0.5;
a0 = (a1 + a0 * q) * f;
b0 = (b1 + b0 * q) * f;
q += 0.5;
r = q * f;
a1 = t * a0 + r * a1;
b1 = t * b0 + r * b1;
}
y = b1 * a / (2.0 * a1);
if ( g >= 0.0 )
y = log(y);
else
y = log(2.0 * SqrPi2 * exp(t) - y);
}
else
{
// Asymptotic series, proportional error = MAX(e(-a*a/2), DBL_EPSILON)
if ( g >= 0.0 )
{
t = 2.0 / (a * a);
q = r = 1.0;
for ( f = 0.5 * t; fabs(q) > DBL_EPSILON; f += t )
{
r += q *= -f;
if ( f > 1.0 ) break; // unnecessary if range OK
}
y = log((r - q * f / 2.0) / a);
}
else
y = log(2.0 * SqrPi2) + a * a / 2.0;
}
return y - log(A) / 2.0;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function:
// inf, inf - g.x - x.A.x/2
// logerf2 := log INTEGRAL dx dy e (A non-negative)
// x=0, y=0
//
// where g.x = g1*x + g2*y, x.A.x = A11*x*x + 2*A12*x*y + A22*y*y
//
// History: JS 12 Jul 1998
//-----------------------------------------------------------------------------
//
double logerf2( // O Output value
double g1, // I x gradient at origin
double g2, // I y gradient at origin
double A11, // I xx curvature >= 0
double A12, // I xy curvature, A12*A12 <= A11*A22
double A22) // I yy curvature >= 0
{
double ctheta; // x coord of ivec = y coord of jvec
double stheta; // y coord of ivec = -x coord of jvec
double val_i; // Eigenvalue for ivec
double val_j; // Eigenvalue for jvec
double origi, origj; // Origin relative to eigencentre
double xveci, xvecj; // x-axis relative to eigencoords
double yveci, yvecj; // y-axis relative to eigencoords
double u, v; // Eigencoords
double a; // Radius to wedge corner in eigencoords
double s, t; // local
double TINY = pow(DBL_EPSILON, 2.0 / 3.0);
// Separable if |A12| * <x(separable)> * <y(separable)> <= sqrt(EPSILON)
u = (g1 > 0.0) ? 1.0 / (A11 + g1 * g1) : (A11 + g1 * g1) / (A11 * A11);
v = (g2 > 0.0) ? 1.0 / (A22 + g2 * g2) : (A22 + g2 * g2) / (A22 * A22);
if ( A12 * A12 * u * v <= DBL_EPSILON )
return logerf(g1, A11) + logerf(g2, A22);
// Generic case ....
// Scale Gaussian to standard form exp(-u*u/2-v*v/2)
if ( A11 >= A22 )
{
t = (A11 - A22) / 2.0;
t += sqrt(t * t + A12 * A12);
s = sqrt(t * t + A12 * A12);
val_i = t + A22;
ctheta = t / s;
stheta = A12 / s;
}
else
{
t = (A22 - A11) / 2.0;
t += sqrt(t * t + A12 * A12);
s = sqrt(t * t + A12 * A12);
val_i = t + A11;
ctheta = A12 / s;
stheta = t / s;
}
val_j = (A11 * A22 - A12 * A12) / val_i;
if ( val_j < TINY * sqrt(A11 * A22) )
val_j = TINY * sqrt(A11 * A22); // Protect singular eval
val_i = sqrt(val_i);
val_j = sqrt(val_j);
origi = ( g1 * ctheta + g2 * stheta) / val_i;
origj = (-g1 * stheta + g2 * ctheta) / val_j;
xveci = val_i * ctheta;
xvecj = -val_j * stheta;
yveci = val_i * stheta;
yvecj = val_j * ctheta;
a = sqrt(origi * origi + origj * origj);
if ( a > 0.0 )
{
origi /= a;
origj /= a;
}
s = eigenerf2(a,
origi * xveci + origj * xvecj, -origj * xveci + origi * xvecj,
origi * yveci + origj * yvecj, -origj * yveci + origi * yvecj);
s = s + a * a / 2.0 - log(val_i * val_j);
return s;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function:
// -r*r/2
// eigenerf2 := log INTEGRAL e dArea
// wedge
// yyy..
// yyy.....
// yyy........
// yyy...........
// | yyy..............
// --O--> a..................
// | xxxxx............
// xxxxx.......
// xxxxx..
//
// 0 < Angle(xxxx, yyyy) < Pi
//
// History: JS 12 Jul 1998
//-----------------------------------------------------------------------------
//
static double eigenerf2(// Output value
double a, // I Radius to corner of wedge
double xcos, // I x-edge direction is (xcos,xsin) relative to radius a
double xsin, // I x-edge direction is (xcos,xsin) relative to radius a
double ycos, // I y-edge direction is (ycos,ysin) relative to radius a
double ysin) // I y-edge direction is (ycos,ysin) relative to radius a
{
#undef PLUS
#define PLUS(x,y) ((x>y) ? x+log(1.0+exp(y-x)) : y+log(1.0+exp(x-y)))
#undef MINUS
#define MINUS(x,y) ((x>y) ? x+log(1.0-exp(y-x)) : log(DBL_MIN))
#undef erfint
#define erfint(x) (logerf((x), 1.0) - (x) * (x) / 2.0)
double t, u, v;
// Normalisation to unit vectors
t = sqrt(xcos * xcos + xsin * xsin);
xcos /= t;
xsin /= t;
t = sqrt(ycos * ycos + ysin * ysin);
ycos /= t;
ysin /= t;
// Force upward orientation
if ( xsin + ysin < 0.0 )
{
t = xcos;
xcos = ycos;
ycos = t;
t = xsin;
xsin = -ysin;
ysin = -t;
}
// Select case
if ( ycos > 0.5 )
{ // case P
u = wedge(a, xsin, ysin);
}
else if ( xcos < -0.5 )
{ // case R
u = wedge(a, -xsin, -ysin);
t = LogSqr2Pi + erfint2(a * ysin, a * xsin);
u = PLUS(u, t);
}
else if ( ycos + 1.732 * ysin < 0.0 )
{
if ( ysin < -0.866 )
{ // case W
v = wedge(a, xcos, -ycos);
t = erfint(a * xsin) + erfint(a * xcos);
v = PLUS(v, t);
t = erfint(-a * ysin) + erfint(a * ycos);
v = PLUS(v, t);
u = 2.0 * LogSqr2Pi;
u = MINUS(u, v);
}
else if ( 1.732 * xsin < xcos )
{ // case V
u = LogSqr2Pi + erfint(a * ysin);
t = wedge(a, -xsin, ysin);
u = MINUS(u, t);
}
else
{ // case T
u = LogSqr2Pi + erfint(a * ysin);
v = erfint(a * xsin) + erfint(a * xcos);
if ( -ysin > -xcos )
{
t = wedge(a, -xcos, -ysin);
u = PLUS(u, t);
}
else
{
t = wedge(a, -ysin, -xcos);
v = PLUS(v, t);
}
u = MINUS(u, v);
}
}
else
{
if ( xsin < -0.866 )
{ // case U
u = erfint(a * ysin) + erfint(a * ycos);
t = erfint(-a * xsin) + erfint(a * xcos);
u = PLUS(u, t);
t = wedge(a, -xcos, ycos);
u = MINUS(u, t);
}
else if ( 1.732 * xsin > xcos )
{ // case Q
u = wedge(a, -xcos, -ycos);
t = erfint(a * ysin) + erfint2(a * ycos, a * xcos);
u = PLUS(u, t);
if ( ysin > xsin )
{
t = erfint(a * xcos) + erfint2(a * xsin, a * ysin);
u = MINUS(u, t);
}
else
{
t = erfint(a * xcos) + erfint2(a * ysin, a * xsin);
u = PLUS(u, t);
}
}
else
{ // case S
u = erfint(a * ysin) + erfint(a * ycos);
if ( -ycos >= xsin )
{
t = wedge(a, xsin, -ycos);
u = PLUS(u, t);
}
else
{
t = wedge(a, -ycos, xsin);
u = MINUS(u, t);
}
}
}
return u;
#undef erfint
#undef MINUS
#undef PLUS
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function:
// x=b -x*x/2
// erfint2 := log INTEGRAL e dx, a < b
// x=a
//
// History: JS 12 Jul 1998
//-----------------------------------------------------------------------------
//
static double erfint2( // O Output value
double a, // I Lower limit
double b) // I Upper limit
{
double aa, bb, e1, e2, ee, s, t;
aa = fabs(a);
bb = fabs(b);
if ( aa < bb )
{
s = aa;
aa = bb;
bb = s;
}
e1 = DBL_EPSILON / (aa + 1.0);
t = b - a;
ee = (aa + fabs(t)) * t;
e2 = ee * ee * fabs(t);
if ( e2 < e1 )
return log((1.0 - (a + t / 3.0) * t / 2.0) * t) - a * a / 2.0;
s = logerf(aa, 1.0) - aa * aa / 2.0;
t = logerf(bb, 1.0) - bb * bb / 2.0;
if ( a * b >= 0.0 )
return t + log(1.0 - exp(s - t));
else
return log(Sqr2Pi - exp(s) - exp(t));
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function:
//
// wedge := log(w(a,t) - w(a,s)) (a >= 0, -1 < s < t < 1) where
//
// infinity
// w(a,x) := INTEGRAL (arcsin(x) - arcsin(a*x/r)) exp(-r*r/2) r dr
// r=a
//
// Notes: Series abs cgt for all |s| < 1, |t| < 1, but cgce slow
// and more storage would be needed if |s| ~ 1 or |t| ~ 1 .
// This version allows values up to sqrt(3)/2, as from eigenerf2.
//
// History: JS 12 Jul 1998, 4 Sep 1999, 12 Sep 1999
//-----------------------------------------------------------------------------
//
static double wedge( // O Output value
double a, // I Input radius
double s, // I Lower angle (as sine)
double t) // I Upper angle (as sine)
{
#define STORE 120 // Want s^STORE < DBL_EPSILON for full accuracy
double w[STORE]; // arcsin_terms(s,t) = SUM w[k] (a/r)^(k+k+1)
double p; // p[k] = INT[a,inf] (1 - (a/r)^(k+k+1)) exp(a*a/2-r*r/2) r dr
double q; // max p[k] when recurrence relation for p started internally
double b, m, r, u, v, sum;
int j, k, n;
// Series {x, (1/2)x^3/3, (1*3/2*4)x^5/5, (1*3*5/2*4*6)x^7/7),..} difference
n = 0;
m = 1.0;
if ( s * t > 0.0 )
{ // Implicit difference between s and t
r = u = v = 1.0;
while ( (w[n++] = r * u * (t - s) / m) > DBL_EPSILON )
{
if ( n == STORE )
break; // Memory overflow trap
r *= 1.0 - 0.5 / n;
v *= t;
u = u * s + v;
v *= t;
u = u * s + v;
m += 2.0;
}
}
else
{ // Explicit difference between s and t
r = 1.0;
u = s;
v = t;
while ( (w[n++] = r * (v - u) / m) > DBL_EPSILON )
{
if ( n == STORE )
break; // Memory overflow trap
r *= 1.0 - 0.5 / n;
u *= s * s;
v *= t * t;
m += 2.0;
}
}
// Initialise recurrence relation for exponential parts
b = a * a / 2.0;
sum = 0.0;
if ( a < 7.0 ) // Balance point for error control
{
// Start at beginning unless errors would amplify too far
p = 1.0 - a * exp(logerf(a, 1.0));
for ( k = 0; k < n; ++k )
{
sum += w[k] * p;
p = 1.0 - b * p / (k + 0.5);
}
}
else
{
// Start in middle at maximum term if errors would otherwise amplify
if ( b < STORE ) // (= dimension limit)
{
k = (int)b;
u = k * k;
p = 0.5 + (0.031 - 0.4 / u) / u; // Phenomenological asymptote
j = k + 1;
u = j * j;
q = 0.5 + (0.031 - 0.4 / u) / u; // Phenomenological asymptote
q = (j - 0.5) * (1.0 - q) / j;
u = b - k;
q = u * q + (1.0 - u) * p; // Interpolated maximum term
}
else
{
j = STORE;
q = (j + 0.5) / (j + b); // Phenomenological approximant
}
// Count down from maximum term
p = q;
for ( k = j - 1; k >= n; --k )
p = (k - 0.5) * (1.0 - p) / b;
for ( ; k >= 0; --k )
{
sum += w[k] * p;
p = (k - 0.5) * (1.0 - p) / b;
}
// Count up from maximum term
p = q;
for ( k = j; k < n; ++k )
{
p = 1.0 - b * p / (k - 0.5);
sum += w[k] * p;
}
}
return log(sum) - b;
#undef STORE
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: logfactorial
//
// Purpose: log( k! ) = lookup table up to 99, then logGamma(k+1)
//
// History: JS 15 May 1998, 24 Mar 2001, 3 Oct 2002, 18 Aug 2003
//-----------------------------------------------------------------------------
//
double logfactorial( // O Value = log(k!)
unsigned k) // I Argument
{
static const double logfact[100] = { 0.0000000000000000,
0.0000000000000000, 0.6931471805599453, 1.7917594692280550,
3.1780538303479456, 4.7874917427820460, 6.5792512120101010,
8.5251613610654143, 10.6046029027452502, 12.8018274800814696,
15.1044125730755153, 17.5023078458738858, 19.9872144956618861,
22.5521638531234229, 25.1912211827386815, 27.8992713838408916,
30.6718601060806728, 33.5050734501368889, 36.3954452080330536,
39.3398841871994940, 42.3356164607534850, 45.3801388984769080,
48.4711813518352239, 51.6066755677643736, 54.7847293981123192,
58.0036052229805199, 61.2617017610020020, 64.5575386270063311,
67.8897431371815350, 71.2570389671680090, 74.6582363488301644,
78.0922235533153106, 81.5579594561150372, 85.0544670175815174,
88.5808275421976788, 92.1361756036870925, 95.7196945421432025,
99.3306124547874269, 102.9681986145138126, 106.6317602606434591,
110.3206397147573954, 114.0342117814617032, 117.7718813997450715,
121.5330815154386340, 125.3172711493568951, 129.1239336391272149,
132.9525750356163099, 136.8027226373263685, 140.6739236482342594,
144.5657439463448860, 148.4777669517730321, 152.4095925844973578,
156.3608363030787852, 160.3311282166309070, 164.3201122631951814,
168.3274454484276523, 172.3527971391628016, 176.3958484069973517,
180.4562914175437711, 184.5338288614494905, 188.6281734236715912,
192.7390472878449024, 196.8661816728899940, 201.0093163992815267,
205.1681994826411985, 209.3425867525368356, 213.5322414945632612,
217.7369341139542273, 221.9564418191303340, 226.1905483237275933,
230.4390435657769523, 234.7017234428182677, 238.9783895618343230,
243.2688490029827142, 247.5729140961868839, 251.8904022097231944,
256.2211355500095255, 260.5649409718632093, 264.9216497985528010,
269.2910976510198225, 273.6731242856937041, 278.0675734403661429,
282.4742926876303960, 286.8931332954269940, 291.3239500942703076,
295.7666013507606240, 300.2209486470141318, 304.6868567656687155,
309.1641935801469219, 313.6528299498790618, 318.1526396202093268,
322.6634991267261769, 327.1852877037752172, 331.7178871969284731,
336.2611819791984770, 340.8150588707990179, 345.3794070622668541,
349.9541180407702369, 354.5390855194408088, 359.1342053695753988
};
double s, y;
if ( k < 100 )
return logfact[k];
y = k + 1.0;
s = y + 2.269488974204959960;
s = y + 1.517473649153287398 / s;
s = y + 1.011523068126841711 / s;
s = y + 0.525606469002695417 / s;
s = y + 0.252380952380952380 / s;
s = y + 0.033333333333333333 / s;
s = 0.083333333333333333 / s;
s = s + 0.91893853320467 - y + (y - 0.5) * log(y);
return s;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: logGamma
//
// Purpose: log( Gamma(x) )
//
// History: JS 18 Aug 2003 From gammln 8 Dec 1994
// Continued fraction (Abramowitz and Stegun)
//-----------------------------------------------------------------------------
//
double logGamma( // O Value = log(Gamma(x))
double x) // I Argument
{
int k;
double s, t, y;
y = x;
for ( k = 16; y < 16.0; --k )
{
y += 1.0;
}
// Continued fraction for s = log(Gamma(y))
s = y + 2.269488974204959960;
s = y + 1.517473649153287398 / s;
s = y + 1.011523068126841711 / s;
s = y + 0.525606469002695417 / s;
s = y + 0.252380952380952380 / s;
s = y + 0.033333333333333333 / s;
s = 0.083333333333333333 / s;
s = s + 0.91893853320467 - y + (y - 0.5) * log(y);
// Return to s = log(Gamma(original x))
t = 1.0;
for ( ++k; k <= 16; ++k )
{
y -= 1.0;
t *= y;
}
s -= log(t);
// Required output
return s;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function: InvNorm
//
// Purpose: Inverse of normal distribution, returning x(y) where
// y(x) = Normal(x)
// x
// = INTEGRAL exp(-u*u/2) du / sqrt(2*pi)
// -inf
// = ( 1 + erf(x/sqrt(2)) ) / 2
//
// Rational approximations claimed to be correct to 1.15e-9
//
// History: JS 13 Sep 2003
// From Peter J Acklam www//home.online.no/~pjacklam/notes/invnorm
//-----------------------------------------------------------------------------
//
double InvNorm( // O Inverse normal (= number of standard deviations)
double y) // I Argument (= cumulative probability)
{
double r, s;
if ( y < 0.02425 )
{
s = sqrt(-2.0 * log(y));
return + (2.938163982698783 +
(4.374664141464968 -
(2.549732539343734 +
(2.400758277161838 +
(0.3223964580411365 +
0.007784894002430293 * s) * s) * s) * s) * s)
/ (1.0 +
(3.754408661907416 +
(2.445134137142996 +
(0.3224671290700398 +
0.007784695709041462 * s) * s) * s) * s);
}
else if ( y > 0.97575 )
{
s = sqrt(-2.0 * log(1.0 - y));
return - (2.938163982698783 +
(4.374664141464968 -
(2.549732539343734 +
(2.400758277161838 +
(0.3223964580411365 +
0.007784894002430293 * s) * s) * s) * s) * s)
/ (1.0 +
(3.754408661907416 +
(2.445134137142996 +
(0.3224671290700398 +
0.007784695709041462 * s) * s) * s) * s);
}
else
{
s = y - 0.5;
r = s * s;
return s * (2.506628277459239 -
(30.66479806614716 -
(138.3577518672690 -
(275.9285104469687 -
(220.9460984245205 -
39.69683028665376 * r) * r) * r) * r) * r)
/ (1.0 -
(13.28068155288572 -
(66.80131188771972 -
(155.6989798598866 -
(161.5858368580409 -
54.47609879822406 * r) * r) * r) * r) * r);
}
}
Event Timeline
Log In to Comment