Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F94101860
random.cpp
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
Tue, Dec 3, 22:23
Size
91 KB
Mime Type
text/x-c
Expires
Thu, Dec 5, 22:23 (2 d)
Engine
blob
Format
Raw Data
Handle
22736208
Attached To
R1448 Lenstool-HPC
random.cpp
View Options
/**
* @file random.c
* @brief 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