Skip to content

Commit

Permalink
Merge "Use an instance of a numpy random generator instead of global …
Browse files Browse the repository at this point in the history
…numpy.random"
  • Loading branch information
arnaudon authored and BBP code review committed May 6, 2021
2 parents 6ae29da + 2cbcfe0 commit 754d697
Show file tree
Hide file tree
Showing 16 changed files with 446 additions and 131 deletions.
40 changes: 35 additions & 5 deletions tests/test_diametrizer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

'''Test tns.generate.diametrizer code'''
import os
import copy
from nose.tools import assert_raises
import numpy as np
from numpy.testing import assert_array_almost_equal
Expand Down Expand Up @@ -107,7 +108,7 @@ def test_diametrize_smoothing():
def test_diametrize_from_root():
neu1 = morphio.mut.Morphology(NEU_PATH1) # has to be loaded to start clean
np.random.seed(0) # ensure constant random number for sampling
diametrizer.diametrize_from_root(neu1, MODEL)
diametrizer.diametrize_from_root(neu1, model_all=MODEL)
assert_array_almost_equal(morphio.Morphology(neu1).diameters,
[4. , 3.9 , 3.8 , 3.7 , 3.6 , 3.5 ,
3.4 , 3.4 , 1.202082, 1.182082, 1.162082, 1.142082,
Expand All @@ -116,7 +117,7 @@ def test_diametrize_from_root():

neu2 = morphio.mut.Morphology(NEU_PATH3) # has to be loaded to start clean
np.random.seed(0) # ensure constant random number for sampling
diametrizer.diametrize_from_root(neu2, MODEL, neurite_type=SectionType.axon)
diametrizer.diametrize_from_root(neu2, SectionType.axon, model_all=MODEL)
assert_array_almost_equal(morphio.Morphology(neu2).diameters,
[4., 3.8, 3.6, 3.4, 3.2, 3.,
2.8 , 2.8, 2.8, 2.6, 2.4, 2.2,
Expand All @@ -127,7 +128,7 @@ def test_diametrize_from_root():
def test_diametrize_from_tips():
neu1 = morphio.mut.Morphology(NEU_PATH1) # has to be loaded to start clean
np.random.seed(0) # ensure constant random number for sampling
diametrizer.diametrize_from_tips(neu1, MODEL)
diametrizer.diametrize_from_tips(neu1, model_all=MODEL)
assert_array_almost_equal(morphio.Morphology(neu1).diameters,
[2.52333 , 2.423331, 2.32333 , 2.22333 , 2.12333 , 2.02333 ,
1.92333 , 1.92333 , 0.68 , 0.66 , 0.64 , 0.62 ,
Expand All @@ -136,7 +137,7 @@ def test_diametrize_from_tips():

neu2 = morphio.mut.Morphology(NEU_PATH3) # has to be loaded to start clean
np.random.seed(0) # ensure constant random number for sampling
diametrizer.diametrize_from_tips(neu2, MODEL, neurite_type=SectionType.axon)
diametrizer.diametrize_from_tips(neu2, model_all=MODEL, neurite_type=SectionType.axon)
assert_array_almost_equal(morphio.Morphology(neu2).diameters,
[4., 3.8, 3.6, 3.4, 3.2, 3.,
2.8 , 2.8, 2.8, 2.6, 2.4, 2.2,
Expand All @@ -157,6 +158,7 @@ def test_redefine_diameter_section():


def test_build():
np.random.seed(1) # ensure constant random number for sampling
neuron = morphio.mut.Morphology(NEU_PATH1)
diametrizer.build(neuron, diam_method="M1")
diameters = [i.diameters for i in neuron.sections.values()]
Expand Down Expand Up @@ -198,7 +200,7 @@ def test_build():
assert_array_almost_equal(diameters[1], diameters[2])
assert_array_almost_equal(diameters[2], [1.9233304, 0.68, 0.66, 0.64, 0.62, 0.6])

def diam_method(neuron, input_model, tree_type):
def diam_method(neuron, tree_type, **kwargs):
diametrizer.diametrize_constant_per_neurite(neuron)

neuron = morphio.mut.Morphology(NEU_PATH1)
Expand Down Expand Up @@ -236,6 +238,34 @@ def diam_method(neuron, input_model, tree_type):
assert_array_almost_equal(diameters[3], diameters[4])
assert_array_almost_equal(diameters[4], diameters[5])

# Test with custom random generator
neuron = morphio.mut.Morphology(NEU_PATH1)
test_model = copy.deepcopy(MODEL)
test_model["basal"]["trunk_taper"] = np.arange(0, 10, 0.3)
diametrizer.build(
neuron,
input_model=test_model,
diam_method="M4",
random_generator=np.random.default_rng(3),
)
diameters = [i.diameters for i in neuron.sections.values()]
assert_array_almost_equal(diameters[0], [3, 2.9, 2.8, 2.7, 2.6, 2.5, 2.4])
assert_array_almost_equal(diameters[1], diameters[2])
assert_array_almost_equal(
diameters[2],
[2.4, 0.84852815, 0.82852817, 0.8085281 , 0.78852814, 0.76852816]
)

neuron = morphio.mut.Morphology(NEU_PATH1)
diametrizer.build(neuron, input_model=MODEL, diam_method="M5")
diameters = [i.diameters for i in neuron.sections.values()]
assert_array_almost_equal(
diameters[0],
[2.5233305, 2.4233305, 2.3233304, 2.2233305, 2.1233304, 2.0233305, 1.923330]
)
assert_array_almost_equal(diameters[1], diameters[2])
assert_array_almost_equal(diameters[2], [1.9233304, 0.68, 0.66, 0.64, 0.62, 0.6])

neuron = morphio.mut.Morphology(NEU_PATH1)
assert_raises(KeyError, diametrizer.build, neuron, None, None, "UNKNOWN")

Expand Down
143 changes: 139 additions & 4 deletions tests/test_neuron_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@
_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data')


def build_random_generator(seed=None):
mt = np.random.MT19937()
mt._legacy_seeding(seed) # Use legacy seeding to get the same result as with np.random.seed()
return np.random.RandomState(mt)


def assert_close_persistent_diagram(actual, expected):
# compute distances between points
distances = np.min(cdist(np.array(tmd.analysis.sort_ph(expected)), actual), axis=0)
Expand All @@ -42,11 +48,25 @@ def _load_inputs(distributions, parameters):
return distributions, params


def _test_full(feature, distributions, parameters, ref_cell, ref_persistence_diagram, save=False):

np.random.seed(0)
def _test_full(
feature,
distributions,
parameters,
ref_cell,
ref_persistence_diagram,
save=False,
rng_or_seed=None,
):
distributions, params = _load_inputs(join(_path, distributions), join(_path, parameters))
n = NeuronGrower(input_distributions=distributions, input_parameters=params).grow()
if rng_or_seed is None:
np.random.seed(0)
n = NeuronGrower(input_distributions=distributions, input_parameters=params).grow()
else:
n = NeuronGrower(
input_distributions=distributions,
input_parameters=params,
rng_or_seed=rng_or_seed,
).grow()

with TemporaryDirectory('test_grower') as folder:
out_neuron = os.path.join(folder, 'test_output_neuron_.h5')
Expand Down Expand Up @@ -80,6 +100,25 @@ def test_wrong_filtration():
assert_raises(ValueError, NeuronGrower, parameters, distributions)


def test_seeding():
'''Test seeding of internal random number generator'''
distributions, parameters = _load_inputs(os.path.join(_path, 'bio_path_distribution.json'),
os.path.join(_path, 'bio_path_params.json'))
ng = NeuronGrower(parameters, distributions, rng_or_seed=0)
assert ng._rng.bit_generator.state == {
"bit_generator": "PCG64",
"state": {
"state": 80186449399738619878794082838194943960,
"inc": 87136372517582989555478159403783844777
},
"has_uint32": 0,
"uinteger": 0,
}

ng = NeuronGrower(parameters, distributions, rng_or_seed=None)
assert ng._rng.bit_generator.state["bit_generator"] == "PCG64"


def test_grow_trunk_1_basal():
'''Test NeuronGrower._grow_trunk() with only 1 basal (should raise an Exception)'''
distributions, parameters = _load_inputs(os.path.join(_path, 'bio_path_distribution.json'),
Expand Down Expand Up @@ -203,6 +242,16 @@ def test_breaker_of_tmd_algo():
assert_array_almost_equal(n.sections[169].points[-1], np.array([117.20551, -41.12157, 189.57013]), decimal=5)
assert_array_almost_equal(n.sections[122].points[-1], np.array([ 77.08879, 115.79825, -0.99393]), decimal=5)

# Test with a specific random generator
rng = build_random_generator(3367155)

N = NeuronGrower(input_distributions=distributions, input_parameters=params, rng_or_seed=rng)
n = N.grow()

assert_array_equal(N.apical_sections, [33])
assert_array_almost_equal(n.sections[169].points[-1], np.array([117.20551, -41.12157, 189.57013]), decimal=5)
assert_array_almost_equal(n.sections[122].points[-1], np.array([ 77.08879, 115.79825, -0.99393]), decimal=5)


def test_axon_grower():
'''Test axon grower, which should only grow trunks with 1 section to allow later axon grafting.
Expand All @@ -214,12 +263,24 @@ def test_axon_grower():
'axon_trunk_parameters.json',
'test_axon_grower.h5',
None)
_test_full('radial_distances',
'axon_trunk_distribution.json',
'axon_trunk_parameters.json',
'test_axon_grower.h5',
None,
rng_or_seed=build_random_generator(0))

_test_full('radial_distances',
'axon_trunk_distribution.json',
'axon_trunk_parameters_absolute.json',
'test_axon_grower_absolute.h5',
None)
_test_full('radial_distances',
'axon_trunk_distribution.json',
'axon_trunk_parameters_absolute.json',
'test_axon_grower_absolute.h5',
None,
rng_or_seed=build_random_generator(0))


def test_basic_grower():
Expand All @@ -228,6 +289,43 @@ def test_basic_grower():
'trunk_parameters.json',
'test_trunk_grower.h5',
None)
_test_full('radial_distances',
'bio_trunk_distribution.json',
'trunk_parameters.json',
'test_trunk_grower.h5',
None,
rng_or_seed=build_random_generator(0))


def test_basic_grower_with_generator():
distributions, params = _load_inputs(
join(_path, 'bio_trunk_distribution.json'),
join(_path, 'trunk_parameters.json'),
)
expected_pts = [
[-0.7312348484992981, 7.604228973388672, 11.173797607421875],
[-13.377432823181152, -1.2863954305648804, 2.9336819648742676],
[11.861421585083008, -0.049414388835430145, 6.1279988288879395],
[-2.3804218769073486, 12.54181957244873, 1.118072748184204],
]

rng = np.random.default_rng(0)
rng_or_seeds = [0, rng]

for rng_or_seed in rng_or_seeds:
n = NeuronGrower(
input_distributions=distributions,
input_parameters=params,
rng_or_seed=rng_or_seed,
).grow()
assert len(n.root_sections) == 4
assert_array_almost_equal(
[i.points[-1].tolist() for i in n.root_sections],
expected_pts,
)

assert_raises(TypeError, NeuronGrower, params, distributions, rng_or_seed="NOT A SEED")


def test_path_grower():
'''test tmd_path and tmd_apical_path'''
Expand All @@ -236,6 +334,13 @@ def test_path_grower():
'bio_path_params.json',
'path_grower.h5',
'bio_path_persistence_diagram.json')
_test_full('path_distances',
'bio_distribution.json',
'bio_path_params.json',
'path_grower.h5',
'bio_path_persistence_diagram.json',
rng_or_seed=build_random_generator(0))


def test_gradient_path_grower():
'''test tmd_path'''
Expand All @@ -244,6 +349,12 @@ def test_gradient_path_grower():
'bio_gradient_path_params.json',
'gradient_path_grower.h5',
'gradient_path_persistence_diagram.json')
_test_full('path_distances',
'bio_distribution.json',
'bio_gradient_path_params.json',
'gradient_path_grower.h5',
'gradient_path_persistence_diagram.json',
rng_or_seed=build_random_generator(0))


def test_bio_rat_l5_tpc():
Expand All @@ -252,21 +363,45 @@ def test_bio_rat_l5_tpc():
'params1.json',
'expected_bio_rat_L5_TPC_B_with_params1.h5',
'expected_bio_rat_L5_TPC_B_with_params1_persistence_diagram.json')
_test_full('path_distances',
'bio_rat_L5_TPC_B.json',
'params1.json',
'expected_bio_rat_L5_TPC_B_with_params1.h5',
'expected_bio_rat_L5_TPC_B_with_params1_persistence_diagram.json',
rng_or_seed=build_random_generator(0))

_test_full('path_distances',
'bio_rat_L5_TPC_B.json',
'params2.json',
'expected_bio_rat_L5_TPC_B_with_params2.h5',
'expected_bio_rat_L5_TPC_B_with_params2_persistence_diagram.json')
_test_full('path_distances',
'bio_rat_L5_TPC_B.json',
'params2.json',
'expected_bio_rat_L5_TPC_B_with_params2.h5',
'expected_bio_rat_L5_TPC_B_with_params2_persistence_diagram.json',
rng_or_seed=build_random_generator(0))

_test_full('path_distances',
'bio_rat_L5_TPC_B.json',
'params3.json',
'expected_bio_rat_L5_TPC_B_with_params3.h5',
'expected_bio_rat_L5_TPC_B_with_params3_persistence_diagram.json')
_test_full('path_distances',
'bio_rat_L5_TPC_B.json',
'params3.json',
'expected_bio_rat_L5_TPC_B_with_params3.h5',
'expected_bio_rat_L5_TPC_B_with_params3_persistence_diagram.json',
rng_or_seed=build_random_generator(0))

_test_full('path_distances',
'bio_rat_L5_TPC_B.json',
'params4.json',
'expected_bio_rat_L5_TPC_B_with_params4.h5',
'expected_bio_rat_L5_TPC_B_with_params4_persistence_diagram.json')
_test_full('path_distances',
'bio_rat_L5_TPC_B.json',
'params4.json',
'expected_bio_rat_L5_TPC_B_with_params4.h5',
'expected_bio_rat_L5_TPC_B_with_params4_persistence_diagram.json',
rng_or_seed=build_random_generator(0))
Loading

0 comments on commit 754d697

Please sign in to comment.