Skip to content
This repository has been archived by the owner on Jun 14, 2024. It is now read-only.

Commit

Permalink
Merge pull request #132 from amzn/develop
Browse files Browse the repository at this point in the history
Merge fixes for 0.2.2 into master
  • Loading branch information
meissnereric authored Nov 19, 2018
2 parents 944711d + b45b8e7 commit 9e8e0a0
Show file tree
Hide file tree
Showing 21 changed files with 883 additions and 61 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,4 @@ docs/_autosummary
docs/_build
docs/generated
docs/examples
venv
10 changes: 2 additions & 8 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,6 @@ after_success:
- codecov
jobs:
include:
- os: osx
language: generic
env: PYTHON=3.4.4
- os: osx
language: generic
env: PYTHON=3.5.1
- os: osx
language: generic
env: PYTHON=3.6.6
Expand All @@ -48,8 +42,8 @@ jobs:
deploy:
provider: pypi
user: meissnereric
password:
secure: "jvE8Tkc2a91bJ9FZLxVUUbt85qjX8VvehrMB5wIScHGXzyZ8EemvNfD+2tCBw6k5QbU4QRGBPM29+4e6UWaI8NKwHqUtIu5T8BdXMCNgGIL4EsvXiHLZbnM3srayprT0qGMCzEoBOMCNzskTj0zJSTPFIwXr8o4jiEq5V7eMNlCMdkCRwfejaTXDX5gW+O26IeAEBYWXbM6c0bvoIUlMGH2mg5e35RRTRlVj6ZSoAHS5UnAj05tgq9S+hNBSjBSYuDNXicCdRh9doexxSyvL8eC1coXj9CabL2yXE6EKK+cIsmHCB7XcTzoIF0CyWdm0MDsGB3BT0csz19kMH5RCXZD413d7Vs6h+fo8bS5otxjkKNowOQLQagor8nimnLCrZVuKU/LEl4/KbR1riEJEZgMe4eH+yTFncMLTfa5IDfw+swkpq0L2RDN1RhagGlOjh3k/7BhCKLxvY5iIteBIkJxpZ8FDEEjZ1o2JFM0LqiOogDGHtrGIMLOSey3DIFMvjjbTwjg8H9X3hBVVLtQ26DUMuwAmzRCIpPW25UKARL3KLmpvTm00WEr5hjmIc4BmEwM6XcbLwceiY49bCBKit0dtIE4lg7xV8rdwjZWADwlmTt+BUYktZBNC9gnaOQNirfE6+SIKYEZkVxaer1TIylokwa2D8wQHYWhSjDdjG10="
skip_existing: true
password:
secure: jvE8Tkc2a91bJ9FZLxVUUbt85qjX8VvehrMB5wIScHGXzyZ8EemvNfD+2tCBw6k5QbU4QRGBPM29+4e6UWaI8NKwHqUtIu5T8BdXMCNgGIL4EsvXiHLZbnM3srayprT0qGMCzEoBOMCNzskTj0zJSTPFIwXr8o4jiEq5V7eMNlCMdkCRwfejaTXDX5gW+O26IeAEBYWXbM6c0bvoIUlMGH2mg5e35RRTRlVj6ZSoAHS5UnAj05tgq9S+hNBSjBSYuDNXicCdRh9doexxSyvL8eC1coXj9CabL2yXE6EKK+cIsmHCB7XcTzoIF0CyWdm0MDsGB3BT0csz19kMH5RCXZD413d7Vs6h+fo8bS5otxjkKNowOQLQagor8nimnLCrZVuKU/LEl4/KbR1riEJEZgMe4eH+yTFncMLTfa5IDfw+swkpq0L2RDN1RhagGlOjh3k/7BhCKLxvY5iIteBIkJxpZ8FDEEjZ1o2JFM0LqiOogDGHtrGIMLOSey3DIFMvjjbTwjg8H9X3hBVVLtQ26DUMuwAmzRCIpPW25UKARL3KLmpvTm00WEr5hjmIc4BmEwM6XcbLwceiY49bCBKit0dtIE4lg7xV8rdwjZWADwlmTt+BUYktZBNC9gnaOQNirfE6+SIKYEZkVxaer1TIylokwa2D8wQHYWhSjDdjG10=
on:
branch: master
5 changes: 4 additions & 1 deletion mxfusion/components/distributions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@
random_gen
univariate
gp
laplace
wishart
beta
dirichlet
"""

__all__ = ['bernoulli', 'categorical', 'distribution', 'normal', 'gamma', 'pointmass', 'random_gen',
'univariate', 'gp', 'wishart', 'beta']
'univariate', 'gp', 'wishart', 'beta', 'laplace', 'uniform', 'dirichlet']

from .distribution import Distribution
from .normal import Normal, MultivariateNormal, NormalMeanPrecision, MultivariateNormalMeanPrecision
Expand All @@ -48,3 +49,5 @@
from .wishart import Wishart
from .beta import Beta
from .dirichlet import Dirichlet
from .uniform import Uniform
from .laplace import Laplace
4 changes: 2 additions & 2 deletions mxfusion/components/distributions/beta.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@ def draw_samples(self, a, b, rv_shape, num_samples=1, F=None):
ones = F.ones_like(a)

# Sample X from Gamma(a, 1)
x = self._rand_gen.sample_gamma(alpha=a, beta=ones, shape=out_shape, dtype=self.dtype, ctx=self.ctx)
x = self._rand_gen.sample_gamma(alpha=a, beta=ones, shape=out_shape, dtype=self.dtype, ctx=self.ctx, F=F)

# Sample Y from Gamma(b, 1)
y = self._rand_gen.sample_gamma(alpha=b, beta=ones, shape=out_shape, dtype=self.dtype, ctx=self.ctx)
y = self._rand_gen.sample_gamma(alpha=b, beta=ones, shape=out_shape, dtype=self.dtype, ctx=self.ctx, F=F)

# Return X / (X + Y)
return F.broadcast_div(x, F.broadcast_add(x, y))
Expand Down
102 changes: 102 additions & 0 deletions mxfusion/components/distributions/laplace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
from ...common.config import get_default_MXNet_mode
from ..variables import Variable
from .univariate import UnivariateDistribution, UnivariateLogPDFDecorator, UnivariateDrawSamplesDecorator


class Laplace(UnivariateDistribution):
"""
The one-dimensional Laplace distribution. The Laplace distribution can be defined over a scalar random variable
or an array of random variables. In case of an array of random variables, the location and scale are broadcasted
to the shape of the output random variable (array).
:param location: Location of the Laplace distribution.
:type location: Variable
:param scale: Scale of the Laplace distribution.
:type scale: Variable
:param rand_gen: the random generator (default: MXNetRandomGenerator).
:type rand_gen: RandomGenerator
:param dtype: the data type for float point numbers.
:type dtype: numpy.float32 or numpy.float64
:param ctx: the mxnet context (default: None/current context).
:type ctx: None or mxnet.cpu or mxnet.gpu
"""
def __init__(self, location, scale, rand_gen=None, dtype=None, ctx=None):
if not isinstance(location, Variable):
location = Variable(value=location)
if not isinstance(scale, Variable):
scale = Variable(value=scale)

inputs = [('location', location), ('scale', scale)]
input_names = [k for k, _ in inputs]
output_names = ['random_variable']
super(Laplace, self).__init__(inputs=inputs, outputs=None,
input_names=input_names,
output_names=output_names,
rand_gen=rand_gen, dtype=dtype, ctx=ctx)

@UnivariateLogPDFDecorator()
def log_pdf(self, location, scale, random_variable, F=None):
"""
Computes the logarithm of the probability density function (PDF) of the Laplace distribution.
:param location: the location of the Laplace distribution.
:type location: MXNet NDArray or MXNet Symbol
:param scale: the scale of the Laplace distributions.
:type scale: MXNet NDArray or MXNet Symbol
:param random_variable: the random variable of the Laplace distribution.
:type random_variable: MXNet NDArray or MXNet Symbol
:param F: the MXNet computation mode (mxnet.symbol or mxnet.ndarray).
:returns: log pdf of the distribution.
:rtypes: MXNet NDArray or MXNet Symbol
"""
F = get_default_MXNet_mode() if F is None else F
logvar = -F.log(2 * scale)
logL = F.broadcast_minus(logvar, F.broadcast_div(
F.abs(F.broadcast_minus(random_variable, location)), scale)) * self.log_pdf_scaling
return logL

@UnivariateDrawSamplesDecorator()
def draw_samples(self, location, scale, rv_shape, num_samples=1, F=None):
"""
Draw samples from the Laplace distribution.
:param location: the location of the Laplace distribution.
:type location: MXNet NDArray or MXNet Symbol
:param scale: the scale of the Laplace distributions.
:type scale: MXNet NDArray or MXNet Symbol
:param rv_shape: the shape of each sample.
:type rv_shape: tuple
:param num_samples: the number of drawn samples (default: one).
:int num_samples: int
:param F: the MXNet computation mode (mxnet.symbol or mxnet.ndarray).
:returns: a set samples of the Laplace distribution.
:rtypes: MXNet NDArray or MXNet Symbol
"""
F = get_default_MXNet_mode() if F is None else F
out_shape = (num_samples,) + rv_shape
return F.broadcast_add(F.broadcast_mul(self._rand_gen.sample_laplace(
shape=out_shape, dtype=self.dtype, ctx=self.ctx),
scale), location)

@staticmethod
def define_variable(location=0., scale=1., shape=None, rand_gen=None,
dtype=None, ctx=None):
"""
Creates and returns a random variable drawn from a Laplace distribution.
:param location: Location of the distribution.
:param scale: Scale of the distribution.
:param shape: the shape of the random variable(s).
:type shape: tuple or [tuple]
:param rand_gen: the random generator (default: MXNetRandomGenerator).
:type rand_gen: RandomGenerator
:param dtype: the data type for float point numbers.
:type dtype: numpy.float32 or numpy.float64
:param ctx: the mxnet context (default: None/current context).
:type ctx: None or mxnet.cpu or mxnet.gpu
:returns: the random variables drawn from the Laplace distribution.
:rtypes: Variable
"""
var = Laplace(location=location, scale=scale, rand_gen=rand_gen, dtype=dtype, ctx=ctx)
var._generate_outputs(shape=shape)
return var.random_variable
68 changes: 68 additions & 0 deletions mxfusion/components/distributions/random_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ def sample_bernoulli(prob_true=0.5, dtype='bool', F=None):
pass


@staticmethod
def sample_uniform(low=0., high=1., shape=None, dtype=None, out=None, ctx=None, F=None):
pass

@staticmethod
def sample_laplace(location=0., scale=1., shape=None, dtype=None, out=None, ctx=None, F=None):
pass

class MXNetRandomGenerator(RandomGenerator):
"""
The MXNet pseudo-random number generator.
Expand Down Expand Up @@ -141,6 +149,66 @@ def sample_gamma(alpha=1, beta=1, shape=None, dtype=None, out=None, ctx=None, F=
:return: Array of samples
"""
F = get_default_MXNet_mode() if F is None else F

return MXNetRandomGenerator._sample_univariate(
func=F.random.gamma, alpha=alpha, beta=beta,
shape=shape, dtype=dtype, out=out, ctx=ctx, F=F)

@staticmethod
def sample_uniform(low=0., high=1., shape=None, dtype=None, out=None, ctx=None, F=None):
"""
Sample uniformly distributed variables
Samples are uniformly distributed over the half-open interval [low, high) (includes low, but excludes high).
:param low: lower boundary of output interval
:param high: upper boundary of output interval
:param shape: Array shape of samples
:param dtype: Data type
:param out: output variable
:param ctx: execution context
:param F: MXNet node
:return: Array of samples
"""
F = get_default_MXNet_mode() if F is None else F

samples = MXNetRandomGenerator._sample_univariate(
func=F.random.uniform, shape=shape, dtype=dtype, out=out, ctx=ctx, F=F)
# samples = F.broadcast_add(F.broadcast_mul(samples, F.broadcast_sub(high, low)), low)
samples = samples * (high - low) + low
return samples

@staticmethod
def sample_laplace(location=0., scale=1., shape=None, dtype=None, out=None, ctx=None, F=None):
"""
Sample Laplace distributed variables
:param location: Location parameter (=mean)
:param scale: (>0) Also known as diversity
:param shape: Array shape of samples
:param dtype: Data type
:param out: output variable
:param ctx: execution context
:param F: MXNet node
:return: Array of samples
"""
F = get_default_MXNet_mode() if F is None else F

# Given a random variable U drawn from the uniform distribution in the interval (-1/2,1/2], the random variable
# X =\mu - b\, \sgn(U)\, \ln(1 - 2 | U |)
# has a Laplace distribution with parameters \mu and b

U = MXNetRandomGenerator.sample_uniform(low=-0.5, high=0.5, shape=shape, dtype=dtype, out=out, ctx=ctx, F=F)

if isinstance(scale, F.NDArray):
b_sgn_U = F.broadcast_mul(scale, F.sign(U))
else:
b_sgn_U = scale * F.sign(U)

ln_1_2_U = F.log(1 - 2 * F.abs(U))

if isinstance(location, F.NDArray):
samples = F.broadcast_minus(location, F.broadcast_mul(b_sgn_U, ln_1_2_U))
else:
samples = location - F.broadcast_mul(b_sgn_U, ln_1_2_U)

return samples
109 changes: 109 additions & 0 deletions mxfusion/components/distributions/uniform.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
from ...common.config import get_default_MXNet_mode
from ..variables import Variable
from .univariate import UnivariateDistribution, UnivariateLogPDFDecorator, UnivariateDrawSamplesDecorator


class Uniform(UnivariateDistribution):
"""
The one-dimensional Uniform distribution over the half-open interval [low, high) (includes low, but excludes high).
The Uniform distribution can be defined over a scalar random variable
or an array of random variables. In case of an array of random variables, the low and high are broadcasted
to the shape of the output random variable (array).
:param low: Low boundary of the Uniform distribution.
:type low: Variable
:param high: High boundary of the Uniform distribution.
:type high: Variable
:param rand_gen: the random generator (default: MXNetRandomGenerator).
:type rand_gen: RandomGenerator
:param dtype: the data type for float point numbers.
:type dtype: numpy.float32 or numpy.float64
:param ctx: the mxnet context (default: None/current context).
:type ctx: None or mxnet.cpu or mxnet.gpu
"""
def __init__(self, low, high, rand_gen=None, dtype=None, ctx=None):
if not isinstance(low, Variable):
low = Variable(value=low)
if not isinstance(high, Variable):
high = Variable(value=high)

inputs = [('low', low), ('high', high)]
input_names = [k for k, _ in inputs]
output_names = ['random_variable']
super(Uniform, self).__init__(inputs=inputs, outputs=None,
input_names=input_names,
output_names=output_names,
rand_gen=rand_gen, dtype=dtype, ctx=ctx)

@UnivariateLogPDFDecorator()
def log_pdf(self, low, high, random_variable, F=None):
"""
Computes the logarithm of the probability density function (PDF) of the Uniform distribution.
:param low: the low boundary of the Uniform distribution.
:type low: MXNet NDArray or MXNet Symbol
:param high: the high boundary of the Uniform distributions.
:type high: MXNet NDArray or MXNet Symbol
:param random_variable: the random variable of the Uniform distribution.
:type random_variable: MXNet NDArray or MXNet Symbol
:param F: the MXNet computation mode (mxnet.symbol or mxnet.ndarray).
:returns: log pdf of the distribution.
:rtypes: MXNet NDArray or MXNet Symbol
"""
F = get_default_MXNet_mode() if F is None else F

# next 3 lines are the broadcasting equivalent of clip(random_variable, low, high)
lower_safe = (low - random_variable) <= 0
upper_safe = (high - random_variable) > 0
in_bounds = F.broadcast_mul(lower_safe, upper_safe)
log_likelihood = F.where(
in_bounds,
-F.log(F.broadcast_minus(high, low)),
F.log(F.zeros_like(random_variable))) * self.log_pdf_scaling
return log_likelihood

@UnivariateDrawSamplesDecorator()
def draw_samples(self, low, high, rv_shape, num_samples=1, F=None):
"""
Draw samples from the Uniform distribution over the half-open interval [low, high)
(includes low, but excludes high).
:param low: the low boundary of the Uniform distribution.
:type low: MXNet NDArray or MXNet Symbol
:param high: the high boundary of the Uniform distributions.
:type high: MXNet NDArray or MXNet Symbol
:param rv_shape: the shape of each sample.
:type rv_shape: tuple
:param num_samples: the number of drawn samples (default: one).
:int num_samples: int
:param F: the MXNet computation mode (mxnet.symbol or mxnet.ndarray).
:returns: a set samples of the Uniform distribution.
:rtypes: MXNet NDArray or MXNet Symbol
"""
F = get_default_MXNet_mode() if F is None else F
out_shape = (num_samples,) + rv_shape
return self._rand_gen.sample_uniform(low=low, high=high,
shape=out_shape, dtype=self.dtype, ctx=self.ctx, F=F)

@staticmethod
def define_variable(low=0, high=1, shape=None, rand_gen=None,
dtype=None, ctx=None):
"""
Creates and returns a random variable drawn from a Uniform distribution.
:param low: Low boundary of the distribution.
:param high: High boundary of the distribution.
:param shape: the shape of the random variable(s).
:type shape: tuple or [tuple]
:param rand_gen: the random generator (default: MXNetRandomGenerator).
:type rand_gen: RandomGenerator
:param dtype: the data type for float point numbers.
:type dtype: numpy.float32 or numpy.float64
:param ctx: the mxnet context (default: None/current context).
:type ctx: None or mxnet.cpu or mxnet.gpu
:returns: the random variables drawn from the Uniform distribution.
:rtypes: Variable
"""
var = Uniform(low=low, high=high, rand_gen=rand_gen, dtype=dtype, ctx=ctx)
var._generate_outputs(shape=shape)
return var.random_variable
Loading

0 comments on commit 9e8e0a0

Please sign in to comment.