Added missing files.

This commit is contained in:
Neil Lawrence 2013-09-24 06:15:09 +02:00
parent c800e0687f
commit 0509b6f9d0
6 changed files with 297 additions and 160 deletions

63
GPy/util/erfcx.py Normal file
View file

@ -0,0 +1,63 @@
## Copyright (C) 2010 Soren Hauberg
##
## Copyright James Hensman 2011
##
## This program is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or (at
## your option) any later version.
##
## This program is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; see the file COPYING. If not, see
## <http://www.gnu.org/licenses/>.
import numpy as np
def erfcx (arg):
arg = np.atleast_1d(arg)
assert(np.all(np.isreal(arg)),"erfcx: input must be real")
## Get precision dependent thresholds -- or not :p
xneg = -26.628;
xmax = 2.53e+307;
## Allocate output
result = np.zeros (arg.shape)
## Find values where erfcx can be evaluated
idx_neg = (arg < xneg);
idx_max = (arg > xmax);
idx = ~(idx_neg | idx_max);
arg = arg [idx];
## Perform the actual computation
t = 3.97886080735226 / (np.abs (arg) + 3.97886080735226);
u = t - 0.5;
y = (((((((((u * 0.00127109764952614092 + 1.19314022838340944e-4) * u \
- 0.003963850973605135) * u - 8.70779635317295828e-4) * u + \
0.00773672528313526668) * u + 0.00383335126264887303) * u - \
0.0127223813782122755) * u - 0.0133823644533460069) * u + \
0.0161315329733252248) * u + 0.0390976845588484035) * u + \
0.00249367200053503304;
y = ((((((((((((y * u - 0.0838864557023001992) * u - \
0.119463959964325415) * u + 0.0166207924969367356) * u + \
0.357524274449531043) * u + 0.805276408752910567) * u + \
1.18902982909273333) * u + 1.37040217682338167) * u + \
1.31314653831023098) * u + 1.07925515155856677) * u + \
0.774368199119538609) * u + 0.490165080585318424) * u + \
0.275374741597376782) * t;
y [arg < 0] = 2 * np.exp (arg [arg < 0]**2) - y [arg < 0];
## Put the results back into something with the same size is the original input
result [idx] = y;
result [idx_neg] = np.inf;
## result (idx_max) = 0; # not needed as we initialise with zeros
return(result)

View file

@ -18,54 +18,93 @@ def ln_diff_erfs(x1, x2, return_sign=False):
:type x2: ndarray
:return: tuple containing (log(abs(erf(x1) - erf(x2))), sign(erf(x1) - erf(x2)))
Based on MATLAB code that was written by Antti Honkela and modified by David Luengo, originally derived from code by Neil Lawrence.
Based on MATLAB code that was written by Antti Honkela and modified by David Luengo and originally derived from code by Neil Lawrence.
"""
x1 = np.require(x1).real
x2 = np.require(x2).real
v = np.zeros(np.max((x1.size, x2.size)))
if x1.size==1:
x1 = np.reshape(x1, (1, 1))
if x2.size==1:
x2 = np.reshape(x2, (1, 1))
if x1.shape==x2.shape:
v = np.zeros_like(x1)
else:
if x1.size==1:
v = np.zeros(x2.shape)
elif x2.size==1:
v = np.zeros(x1.shape)
else:
raise ValueError, "This function does not broadcast unless provided with a scalar."
# if numel(x1) == 1:
# x1 = x1 * ones(size(x2))
if x1.size == 1:
x1 = np.tile(x1, x2.shape)
# if numel(x2) == 1:
# x2 = x2 * ones(size(x1))
if x2.size == 1:
x2 = np.tile(x2, x1.shape)
sign = np.sign(x1 - x2)
I = sign == -1
swap = x1[I]
x1[I] = x2[I]
x2[I] = swap
if x1.size == 1:
if sign== -1:
swap = x1
x1 = x2
x2 = swap
else:
I = sign == -1
swap = x1[I]
x1[I] = x2[I]
x2[I] = swap
# TODO: switch off log of zero warnings.
# Case 1: arguments of different sign, no problems with loss of accuracy
I1 = np.logical_or(np.logical_and(x1>0, x2<0), np.logical_and(x2>0, x1<0)) # I1=(x1*x2)<0
v[I1] = np.log( erf(x1[I1]) - erf(x2[I1]) )
with np.errstate(divide='ignore'):
# switch off log of zero warnings.
# Case 2: x1 = x2 so we have log of zero.
I2 = (x1 == x2)
v[I2] = -np.inf
# Case 0: arguments of different sign, no problems with loss of accuracy
I0 = np.logical_or(np.logical_and(x1>0, x2<0), np.logical_and(x2>0, x1<0)) # I1=(x1*x2)<0
# Case 3: Both arguments are non-negative
I3 = np.logical_and(x1 > 0, np.logical_and(np.logical_not(I1),
np.logical_not(I2)))
v[I3] = np.log(erfcx(x2[I3])
-erfcx(x1[I3])*np.exp(x2[I3]**2
-x1[I3]**2)) - x2[I3]**2
# Case 4: Both arguments are non-positive
I4 = np.logical_and(np.logical_and(np.logical_not(I1),
np.logical_not(I2)),
np.logical_not(I3))
v[I4] = np.log(erfcx(-x1[I4])
-erfcx(-x2[I4])*np.exp(x1[I4]**2
-x2[I4]**2))-x1[I4]**2
# Case 1: x1 = x2 so we have log of zero.
I1 = (x1 == x2)
# Case 2: Both arguments are non-negative
I2 = np.logical_and(x1 > 0, np.logical_and(np.logical_not(I0),
np.logical_not(I1)))
# Case 3: Both arguments are non-positive
I3 = np.logical_and(np.logical_and(np.logical_not(I0),
np.logical_not(I1)),
np.logical_not(I2))
_x2 = x2.flatten()
_x1 = x1.flatten()
for group, flags in zip((0, 1, 2, 3), (I0, I1, I2, I3)):
if np.any(flags):
if not x1.size==1:
_x1 = x1[flags]
if not x2.size==1:
_x2 = x2[flags]
if group==0:
v[flags] = np.log( erf(_x1) - erf(_x2) )
elif group==1:
v[flags] = -np.inf
elif group==2:
v[flags] = np.log(erfcx(_x2)
-erfcx(_x1)*np.exp(_x2**2
-_x1**2)) - _x2**2
elif group==3:
v[flags] = np.log(erfcx(-_x1)
-erfcx(-_x2)*np.exp(_x1**2
-_x2**2))-_x1**2
# TODO: switch back on log of zero warnings.
if return_sign:
return v, sign
else:
# Need to add in a complex part because argument is negative.
v[I] += np.pi*1j
if v.size==1:
if sign==-1:
v = v.view('complex64')
v += np.pi*1j
else:
# Need to add in a complex part because argument is negative.
v = v.view('complex64')
v[I] += np.pi*1j
return v