Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ Release History
- Added a new example showing how adjusting ensemble tuning curves can
improve function approximation.
(`#1129 <https://github.com/nengo/nengo/pull/1129>`_)
- Added a minimum magnitude option to ``UniformHypersphere``.
(`#799 <https://github.com/nengo/nengo/pull/799>`_)

**Changed**

Expand Down
24 changes: 20 additions & 4 deletions nengo/dists.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from __future__ import absolute_import

import warnings

import numpy as np

from nengo.exceptions import ValidationError
Expand Down Expand Up @@ -222,17 +225,29 @@ class UniformHypersphere(Distribution):
Whether sample points should be distributed uniformly
over the surface of the hyperphere (True),
or within the hypersphere (False).
min_magnitude : Number, optional (Default: 0)
Lower bound on the returned vector magnitudes (such that they are in
the range ``[min_magnitude, 1]``). Must be in the range [0, 1).
Ignored if ``surface`` is ``True``.
"""

surface = BoolParam('surface')
min_magnitude = NumberParam('min_magnitude', low=0, high=1, high_open=True)

def __init__(self, surface=False):
def __init__(self, surface=False, min_magnitude=0):
super(UniformHypersphere, self).__init__()
if surface and min_magnitude > 0:
warnings.warn("min_magnitude ignored because surface is True")
self.surface = surface
self.min_magnitude = min_magnitude

def __repr__(self):
return "UniformHypersphere(%s)" % (
"surface=True" if self.surface else "")
args = []
if self.surface:
args.append("surface=%s" % self.surface)
if self.min_magnitude > 0:
args.append("min_magnitude=%r" % self.min_magnitude)
return "%s(%s)" % (type(self).__name__, ', '.join(args))

def sample(self, n, d, rng=np.random):
if d is None or d < 1: # check this, since other dists allow d = None
Expand All @@ -247,7 +262,8 @@ def sample(self, n, d, rng=np.random):
# Generate magnitudes for vectors from uniform distribution.
# The (1 / d) exponent ensures that samples are uniformly distributed
# in n-space and not all bunched up at the centre of the sphere.
samples *= rng.rand(n, 1) ** (1.0 / d)
samples *= rng.uniform(
low=self.min_magnitude**d, high=1, size=(n, 1)) ** (1. / d)

return samples

Expand Down
33 changes: 20 additions & 13 deletions nengo/tests/test_dists.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import nengo.dists as dists
import nengo.utils.numpy as npext
from nengo.utils.testing import warns
from nengo.exceptions import ValidationError


Expand Down Expand Up @@ -69,19 +70,15 @@ def test_exponential(scale, shift, high, rng):
assert abs(np.mean(samples - shift) - scale) < ci


@pytest.mark.parametrize("dimensions", [0, 1, 2, 5])
def test_hypersphere(dimensions, rng):
n = 150 * dimensions
if dimensions < 1:
with pytest.raises(ValueError):
dist = dists.UniformHypersphere().sample(1, dimensions)
else:
dist = dists.UniformHypersphere()
samples = dist.sample(n, dimensions, rng=rng)
assert samples.shape == (n, dimensions)
assert np.allclose(np.mean(samples, axis=0), 0, atol=0.1)
hist, _ = np.histogramdd(samples, bins=5)
assert np.allclose(hist - np.mean(hist), 0, atol=0.1 * n)
@pytest.mark.parametrize(
"min_magnitude,d", [(0, 1), (0, 2), (0, 5), (0.6, 1), (0.3, 2), (0.4, 5)])
def test_hypersphere_volume(min_magnitude, d, rng):
n = 150 * d
dist = dists.UniformHypersphere(min_magnitude=min_magnitude)
samples = dist.sample(n, d, rng=rng)
assert samples.shape == (n, d)
assert np.allclose(np.mean(samples, axis=0), 0, atol=0.1)
assert np.all(npext.norm(samples, axis=1) >= min_magnitude)


@pytest.mark.parametrize("dimensions", [1, 2, 5])
Expand All @@ -94,6 +91,16 @@ def test_hypersphere_surface(dimensions, rng):
assert np.allclose(np.mean(samples, axis=0), 0, atol=0.25 / dimensions)


def test_hypersphere_dimension_fail(rng):
with pytest.raises(ValueError):
dists.UniformHypersphere(0).sample(1, 0)


def test_hypersphere_warns(rng):
with warns(UserWarning):
dists.UniformHypersphere(surface=True, min_magnitude=0.1)


@pytest.mark.parametrize("weights", [None, [5, 1, 2, 9], [3, 2, 1, 0]])
def test_choice(weights, rng):
n = 1000
Expand Down