diff --git a/ChangeLog b/ChangeLog
index 2716926b4a3745150aff6cfd36d63281d5f9ee3f..4cc565de5306bb40a3264dd6eb219fa4a42a2f17 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,20 @@
Changes since NIFTy 5:
+MPI parallelisation over samples in MetricGaussianKL
+====================================================
+
+The classes `MetricGaussianKL` and `MetricGaussianKL_MPI` have been unified
+into one `MetricGaussianKL` class which has MPI support built in.
+
+New approach for random number generation
+=========================================
+
+The code now uses `numpy`'s new `SeedSequence` and `Generator` classes for the
+production of random numbers (introduced in numpy 1.17. This greatly simplifies
+the generation of reproducible random numbers in the presence of MPI parallelism
+and leads to cleaner code overall. Please see the documentation of
+`nifty6.random` for details.
+
Interface Change for non-linear Operators
=========================================
@@ -17,7 +32,6 @@ behaviour since both `Operator._check_input()` and
`extra.check_jacobian_consistency()` tests for the new conditions to be
fulfilled.
-
Special functions for complete Field reduction operations
=========================================================
@@ -66,12 +80,3 @@ User-visible changes:
replaced by a single function called `makeField`
- the property `local_shape` has been removed from `Domain` (and subclasses)
and `DomainTuple`.
-
-Transfer of MPI parallelization into operators:
-===============================================
-
-As was already the case with the `MetricGaussianKL_MPI` in NIFTy5, MPI
-parallelization in NIFTy6 is handled by specialized MPI-enabled operators.
-
-They are accessible via the `nifty6.mpi` namespace, from which they can be
-imported directly: `from nifty6.mpi import MPIenabledOperator`.
diff --git a/demos/Wiener_Filter.ipynb b/demos/Wiener_Filter.ipynb
index b0ef1f8b38a3e372d0c120a45bceaabe287e35c0..ba46b6958af7cb8283eb71f5b1d401f166fc9447 100644
--- a/demos/Wiener_Filter.ipynb
+++ b/demos/Wiener_Filter.ipynb
@@ -140,7 +140,6 @@
"outputs": [],
"source": [
"import numpy as np\n",
- "np.random.seed(40)\n",
"import nifty6 as ift\n",
"import matplotlib.pyplot as plt\n",
"%matplotlib inline"
diff --git a/demos/bench_gridder.py b/demos/bench_gridder.py
index 9bf476737238bc400566ce8e118aee9db3272977..d07b823c4d81938536ba3d4085f113f9c6141de1 100644
--- a/demos/bench_gridder.py
+++ b/demos/bench_gridder.py
@@ -5,8 +5,6 @@ import numpy as np
import nifty6 as ift
-np.random.seed(40)
-
N0s, a0s, b0s, c0s = [], [], [], []
for ii in range(10, 26):
@@ -15,15 +13,16 @@ for ii in range(10, 26):
N = int(2**ii)
print('N = {}'.format(N))
- uv = np.random.rand(N, 2) - 0.5
- vis = np.random.randn(N) + 1j*np.random.randn(N)
+ rng = ift.random.current_rng()
+ uv = rng.uniform(-.5, .5, (N,2))
+ vis = rng.normal(0., 1., N) + 1j*rng.normal(0., 1., N)
uvspace = ift.RGSpace((nu, nv))
visspace = ift.TMP_UnstructuredSpace(N)
- img = np.random.randn(nu*nv)
- img = img.reshape((nu, nv))
+ img = rng.standard_normal((nu, nv))
+ img = ift.makeField(uvspace, img)
img = ift.makeTMP_fld(uvspace, img)
t0 = time()
diff --git a/demos/bernoulli_demo.py b/demos/bernoulli_demo.py
index fc761fb18e3cacd209fc93daf4424bab8318d612..de728a4695096b03cd48951af08150873b7387ff 100644
--- a/demos/bernoulli_demo.py
+++ b/demos/bernoulli_demo.py
@@ -27,8 +27,6 @@ import numpy as np
import nifty6 as ift
if __name__ == '__main__':
- np.random.seed(41)
-
# Set up the position space of the signal
mode = 2
if mode == 0:
@@ -62,7 +60,7 @@ if __name__ == '__main__':
p = R(sky)
mock_position = ift.from_random('normal', harmonic_space)
tmp = p(mock_position).val.astype(np.float64)
- data = np.random.binomial(1, tmp)
+ data = ift.random.current_rng().binomial(1, tmp)
data = ift.TMP_fld.from_raw(R.target, data)
# Compute likelihood and Hamiltonian
diff --git a/demos/getting_started_1.py b/demos/getting_started_1.py
index 6fb71b5cf52cfb1973ac7e73c5da7921bbf88842..7a02bbd4542a17146480a36784e76781471947ae 100644
--- a/demos/getting_started_1.py
+++ b/demos/getting_started_1.py
@@ -46,8 +46,6 @@ def make_random_mask():
if __name__ == '__main__':
- np.random.seed(42)
-
# Choose space on which the signal field is defined
if len(sys.argv) == 2:
mode = int(sys.argv[1])
diff --git a/demos/getting_started_2.py b/demos/getting_started_2.py
index 44d3e507401fe4d0bed394a4eca87b19c0460e0d..e1da73ef28fa55052fe39cf0599eb841f2a1d87e 100644
--- a/demos/getting_started_2.py
+++ b/demos/getting_started_2.py
@@ -44,8 +44,6 @@ def exposure_2d():
if __name__ == '__main__':
- np.random.seed(42)
-
# Choose space on which the signal field is defined
if len(sys.argv) == 2:
mode = int(sys.argv[1])
@@ -94,7 +92,7 @@ if __name__ == '__main__':
lamb = R(sky)
mock_position = ift.from_random('normal', domain)
data = lamb(mock_position)
- data = np.random.poisson(data.val.astype(np.float64))
+ data = ift.random.current_rng().poisson(data.val.astype(np.float64))
data = ift.TMP_fld.from_raw(d_space, data)
likelihood = ift.PoissonianEnergy(data) @ lamb
diff --git a/demos/getting_started_3.py b/demos/getting_started_3.py
index ff2241a2c98127c211d810182e8d2e9885f00ce5..ac252905bea3c798c7a40315f00da4bd3a0484f2 100644
--- a/demos/getting_started_3.py
+++ b/demos/getting_started_3.py
@@ -33,20 +33,18 @@ import nifty6 as ift
def random_los(n_los):
- starts = list(np.random.uniform(0, 1, (n_los, 2)).T)
- ends = list(np.random.uniform(0, 1, (n_los, 2)).T)
+ starts = list(ift.random.current_rng().random((n_los, 2)).T)
+ ends = list(ift.random.current_rng().random((n_los, 2)).T)
return starts, ends
def radial_los(n_los):
- starts = list(np.random.uniform(0, 1, (n_los, 2)).T)
- ends = list(0.5 + 0*np.random.uniform(0, 1, (n_los, 2)).T)
+ starts = list(ift.random.current_rng().random((n_los, 2)).T)
+ ends = list(0.5 + 0*ift.random.current_rng().random((n_los, 2)).T)
return starts, ends
if __name__ == '__main__':
- np.random.seed(420)
-
# Choose between random line-of-sight response (mode=0) and radial lines
# of sight (mode=1)
if len(sys.argv) == 2:
diff --git a/demos/getting_started_mf.py b/demos/getting_started_mf.py
index b7ad94432981ce77205d36cab6123fb46534c5fb..97cc035ed71d258d6155a6097185e6797721967e 100644
--- a/demos/getting_started_mf.py
+++ b/demos/getting_started_mf.py
@@ -44,20 +44,18 @@ class SingleTMP_Space(ift.LinearOperator):
def random_los(n_los):
- starts = list(np.random.uniform(0, 1, (n_los, 2)).T)
- ends = list(np.random.uniform(0, 1, (n_los, 2)).T)
+ starts = list(ift.random.current_rng().random((n_los, 2)).T)
+ ends = list(ift.random.current_rng().random((n_los, 2)).T)
return starts, ends
def radial_los(n_los):
- starts = list(np.random.uniform(0, 1, (n_los, 2)).T)
- ends = list(0.5 + 0*np.random.uniform(0, 1, (n_los, 2)).T)
+ starts = list(ift.random.current_rng().random((n_los, 2)).T)
+ ends = list(0.5 + 0*ift.random.current_rng().random((n_los, 2)).T)
return starts, ends
if __name__ == '__main__':
- np.random.seed(43)
-
# Choose between random line-of-sight response (mode=0) and radial lines
# of sight (mode=1)
if len(sys.argv) == 2:
diff --git a/demos/polynomial_fit.py b/demos/polynomial_fit.py
index e49a3fb22b47fa38b20975281e78595fffafd1e3..ceb5e7d458eabbec5a84ff9cf34ff2607ec9c8fa 100644
--- a/demos/polynomial_fit.py
+++ b/demos/polynomial_fit.py
@@ -19,7 +19,6 @@ import matplotlib.pyplot as plt
import numpy as np
import nifty6 as ift
-np.random.seed(12)
def polynomial(coefficients, sampling_points):
@@ -86,7 +85,7 @@ if __name__ == '__main__':
N_params = 10
N_samples = 100
size = (12,)
- x = np.random.random(size) * 10
+ x = ift.random.current_rng().random(size) * 10
y = np.sin(x**2) * x**3
var = np.full_like(y, y.var() / 10)
var[-2] *= 4
diff --git a/nifty6/__init__.py b/nifty6/__init__.py
index ece070d7cf01385b180adcc0b3762b5fe97b8a24..a68839a60ef8aaacb06cb7bdf37faaaf576071b8 100644
--- a/nifty6/__init__.py
+++ b/nifty6/__init__.py
@@ -1,5 +1,7 @@
from .version import __version__
+from . import random
+
from .domains.domain import TMP_Space
from .domains.structured_domain import TMP_StructuredSpace
from .domains.unstructured_domain import TMP_UnstructuredSpace
diff --git a/nifty6/extra.py b/nifty6/extra.py
index 60d411b79a9686c2e436c6c29a55eb03c173a54c..7523547206fb2ee2d05d5d025a5c6de4d9bef60d 100644
--- a/nifty6/extra.py
+++ b/nifty6/extra.py
@@ -278,17 +278,21 @@ def check_jacobian_consistency(op, loc, tol=1e-8, ntries=100, perf_check=True):
dir = loc2-loc
locnext = loc2
dirnorm = dir.norm()
+ hist = []
for i in range(50):
locmid = loc + 0.5*dir
linmid = op(Linearization.make_var(locmid))
dirder = linmid.jac(dir)
numgrad = (lin2.val-lin.val)
xtol = tol * dirder.norm() / np.sqrt(dirder.size)
+ hist.append((numgrad-dirder).norm())
+# print(len(hist),hist[-1])
if (abs(numgrad-dirder) <= xtol).s_all():
break
dir = dir*0.5
dirnorm *= 0.5
loc2, lin2 = locmid, linmid
else:
+ print(hist)
raise ValueError("gradient and value seem inconsistent")
loc = locnext
diff --git a/nifty6/library/special_distributions.py b/nifty6/library/special_distributions.py
index 4f115c0e70ec0b58070ef244acd6e1f468a5da09..95d9775080d51c8598818038b13583502ccac4a3 100644
--- a/nifty6/library/special_distributions.py
+++ b/nifty6/library/special_distributions.py
@@ -25,6 +25,7 @@ from ..field import TMP_fld
from ..linearization import Linearization
from ..operators.operator import Operator
from ..sugar import makeOp
+from .. import random
def _f_on_np(f, arr):
@@ -67,7 +68,8 @@ class _InterpolationOperator(Operator):
if table_func is not None:
if inv_table_func is None:
raise ValueError
- a = func(np.random.randn(10))
+# MR FIXME: not sure whether we should have this in production code
+ a = func(random.current_rng().random(10))
a1 = _f_on_np(lambda x: inv_table_func(table_func(x)), a)
np.testing.assert_allclose(a, a1)
self._table = _f_on_np(table_func, self._table)
diff --git a/nifty6/minimization/metric_gaussian_kl.py b/nifty6/minimization/metric_gaussian_kl.py
index 85b1696eb78c54357f46eb328bcb3b59ce692222..7ca0c06e00d511c93cd14710d803e6bce2fb038e 100644
--- a/nifty6/minimization/metric_gaussian_kl.py
+++ b/nifty6/minimization/metric_gaussian_kl.py
@@ -11,19 +11,66 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-# Copyright(C) 2013-2019 Max-Planck-Society
+# Copyright(C) 2013-2020 Max-Planck-Society
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
+
import numpy as np
-from .. import utilities
+from .. import random, utilities
+from ..field import TMP_fld
from ..linearization import Linearization
+from ..multi_field import TMP_Field
+from ..operators.endomorphic_operator import EndomorphicOperator
from ..operators.energy_operators import StandardHamiltonian
from ..probing import approximation2endo
-from ..sugar import makeOp
+from ..sugar import full, makeOp
from .energy import Energy
+def _shareRange(nwork, nshares, myshare):
+ nbase = nwork//nshares
+ additional = nwork % nshares
+ lo = myshare*nbase + min(myshare, additional)
+ hi = lo + nbase + int(myshare < additional)
+ return lo, hi
+
+
+def _np_allreduce_sum(comm, arr):
+ if comm is None:
+ return arr
+ from mpi4py import MPI
+ arr = np.array(arr)
+ res = np.empty_like(arr)
+ comm.Allreduce(arr, res, MPI.SUM)
+ return res
+
+
+def _allreduce_sum_field(comm, fld):
+ if comm is None:
+ return fld
+ if isinstance(fld, TMP_fld):
+ return TMP_fld(fld.domain, _np_allreduce_sum(fld.val))
+ res = tuple(
+ TMP_fld(f.domain, _np_allreduce_sum(comm, f.val))
+ for f in fld.values())
+ return TMP_Field(fld.domain, res)
+
+
+class _KLMetric(EndomorphicOperator):
+ def __init__(self, KL):
+ self._KL = KL
+ self._capability = self.TIMES | self.ADJOINT_TIMES
+ self._domain = KL.position.domain
+
+ def apply(self, x, mode):
+ self._check_input(x, mode)
+ return self._KL.apply_metric(x)
+
+ def draw_sample(self, from_inverse=False, dtype=np.float64):
+ return self._KL._metric_sample(from_inverse, dtype)
+
+
class MetricGaussianKL(Energy):
"""Provides the sampled Kullback-Leibler divergence between a distribution
and a Metric Gaussian.
@@ -38,6 +85,7 @@ class MetricGaussianKL(Energy):
typically nonlinear structure of the true distribution these samples have
to be updated eventually by intantiating `MetricGaussianKL` again. For the
true probability distribution the standard parametrization is assumed.
+ The samples of this class can be distributed among MPI tasks.
Parameters
----------
@@ -62,6 +110,17 @@ class MetricGaussianKL(Energy):
napprox : int
Number of samples for computing preconditioner for sampling. No
preconditioning is done by default.
+ comm : MPI communicator or None
+ If not None, samples will be distributed as evenly as possible
+ across this communicator. If `mirror_samples` is set, then a sample and
+ its mirror image will always reside on the same task.
+ lh_sampling_dtype : type
+ Determines which dtype in data space shall be used for drawing samples
+ from the metric. If the inference is based on complex data,
+ lh_sampling_dtype shall be set to complex accordingly. The reason for
+ the presence of this parameter is that metric of the likelihood energy
+ is just an `Operator` which does not know anything about the dtype of
+ the fields on which it acts. Default is float64.
_samples : None
Only a parameter for internal uses. Typically not to be set by users.
@@ -79,7 +138,8 @@ class MetricGaussianKL(Energy):
def __init__(self, mean, hamiltonian, n_samples, constants=[],
point_estimates=[], mirror_samples=False,
- napprox=0, _samples=None, lh_sampling_dtype=np.float64):
+ napprox=0, comm=None, _samples=None,
+ lh_sampling_dtype=np.float64):
super(MetricGaussianKL, self).__init__(mean)
if not isinstance(hamiltonian, StandardHamiltonian):
@@ -88,47 +148,72 @@ class MetricGaussianKL(Energy):
raise ValueError
if not isinstance(n_samples, int):
raise TypeError
- self._constants = list(constants)
- self._point_estimates = list(point_estimates)
+ self._constants = tuple(constants)
+ self._point_estimates = tuple(point_estimates)
if not isinstance(mirror_samples, bool):
raise TypeError
self._hamiltonian = hamiltonian
+ self._n_samples = int(n_samples)
+ if comm is not None:
+ self._comm = comm
+ ntask = self._comm.Get_size()
+ rank = self._comm.Get_rank()
+ self._lo, self._hi = _shareRange(self._n_samples, ntask, rank)
+ else:
+ self._comm = None
+ self._lo, self._hi = 0, self._n_samples
+
+ self._mirror_samples = bool(mirror_samples)
+ self._n_eff_samples = self._n_samples
+ if self._mirror_samples:
+ self._n_eff_samples *= 2
+
if _samples is None:
met = hamiltonian(Linearization.make_partial_var(
- mean, point_estimates, True)).metric
- if napprox > 1:
+ mean, self._point_estimates, True)).metric
+ if napprox >= 1:
met._approximation = makeOp(approximation2endo(met, napprox))
- _samples = tuple(met.draw_sample(from_inverse=True,
- dtype=lh_sampling_dtype)
- for _ in range(n_samples))
- if mirror_samples:
- _samples += tuple(-s for s in _samples)
+ _samples = []
+ sseq = random.spawn_sseq(self._n_samples)
+ for i in range(self._lo, self._hi):
+ random.push_sseq(sseq[i])
+ _samples.append(met.draw_sample(from_inverse=True,
+ dtype=lh_sampling_dtype))
+ random.pop_sseq()
+ _samples = tuple(_samples)
+ else:
+ if len(_samples) != self._hi-self._lo:
+ raise ValueError("# of samples mismatch")
self._samples = _samples
-
- # FIXME Use simplify for constant input instead
- self._lin = Linearization.make_partial_var(mean, constants)
+ self._lin = Linearization.make_partial_var(mean, self._constants)
v, g = None, None
- for s in self._samples:
- tmp = self._hamiltonian(self._lin+s)
- if v is None:
- v = tmp.val.val[()]
- g = tmp.gradient
- else:
- v += tmp.val.val[()]
- g = g + tmp.gradient
- self._val = v / len(self._samples)
- self._grad = g * (1./len(self._samples))
+ if len(self._samples) == 0: # hack if there are too many MPI tasks
+ tmp = self._hamiltonian(self._lin)
+ v = 0. * tmp.val.val
+ g = 0. * tmp.gradient
+ else:
+ for s in self._samples:
+ tmp = self._hamiltonian(self._lin+s)
+ if self._mirror_samples:
+ tmp = tmp + self._hamiltonian(self._lin-s)
+ if v is None:
+ v = tmp.val.val_rw()
+ g = tmp.gradient
+ else:
+ v += tmp.val.val
+ g = g + tmp.gradient
+ self._val = _np_allreduce_sum(self._comm, v)[()] / self._n_eff_samples
+ self._grad = _allreduce_sum_field(self._comm, g) / self._n_eff_samples
self._metric = None
- self._napprox = napprox
self._sampdt = lh_sampling_dtype
def at(self, position):
- return MetricGaussianKL(position, self._hamiltonian, 0,
- self._constants, self._point_estimates,
- napprox=self._napprox, _samples=self._samples,
- lh_sampling_dtype=self._sampdt)
+ return MetricGaussianKL(
+ position, self._hamiltonian, self._n_samples, self._constants,
+ self._point_estimates, self._mirror_samples, comm=self._comm,
+ _samples=self._samples, lh_sampling_dtype=self._sampdt)
@property
def value(self):
@@ -139,30 +224,48 @@ class MetricGaussianKL(Energy):
return self._grad
def _get_metric(self):
+ lin = self._lin.with_want_metric()
if self._metric is None:
- lin = self._lin.with_want_metric()
- mymap = map(lambda v: self._hamiltonian(lin+v).metric,
- self._samples)
- self._unscaled_metric = utilities.my_sum(mymap)
- self._metric = self._unscaled_metric.scale(1./len(self._samples))
-
- def unscaled_metric(self):
- self._get_metric()
- return self._unscaled_metric, 1/len(self._samples)
+ if len(self._samples) == 0: # hack if there are too many MPI tasks
+ self._metric = self._hamiltonian(lin).metric.scale(0.)
+ else:
+ mymap = map(lambda v: self._hamiltonian(lin+v).metric,
+ self._samples)
+ self.unscaled_metric = utilities.my_sum(mymap)
+ self._metric = self.unscaled_metric.scale(1./self._n_eff_samples)
def apply_metric(self, x):
self._get_metric()
- return self._metric(x)
+ return _allreduce_sum_field(self._comm, self._metric(x))
@property
def metric(self):
- self._get_metric()
- return self._metric
+ return _KLMetric(self)
@property
def samples(self):
- return self._samples
+ if self._comm is not None:
+ res = self._comm.allgather(self._samples)
+ res = [item for sublist in res for item in sublist]
+ else:
+ res = self._samples
+ if self._mirror_samples:
+ res = res + tuple(-item for item in res)
+ return res
+
+ def _unscaled_metric_sample(self, from_inverse=False, dtype=np.float64):
+ if from_inverse:
+ raise NotImplementedError()
+ lin = self._lin.with_want_metric()
+ samp = full(self._hamiltonian.domain, 0.)
+ sseq = random.spawn_sseq(self._n_samples)
+ for i, v in enumerate(self._samples):
+ random.push_sseq(sseq[self._lo+i])
+ samp = samp + self._hamiltonian(lin+v).metric.draw_sample(from_inverse=False, dtype=dtype)
+ if self._mirror_samples:
+ samp = samp + self._hamiltonian(lin-v).metric.draw_sample(from_inverse=False, dtype=dtype)
+ random.pop_sseq()
+ return _allreduce_sum_field(self._comm, samp)
- def __repr__(self):
- return 'KL ({} samples):\n'.format(len(
- self._samples)) + utilities.indent(self._hamiltonian.__repr__())
+ def _metric_sample(self, from_inverse=False, dtype=np.float64):
+ return self._unscaled_metric_sample(from_inverse, dtype)/self._n_eff_samples
diff --git a/nifty6/minimization/metric_gaussian_kl_mpi.py b/nifty6/minimization/metric_gaussian_kl_mpi.py
deleted file mode 100644
index 615a5cbc7bac0e2254692ec364de772ab3a4f04a..0000000000000000000000000000000000000000
--- a/nifty6/minimization/metric_gaussian_kl_mpi.py
+++ /dev/null
@@ -1,256 +0,0 @@
-# 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. If not, see .
-#
-# Copyright(C) 2013-2019 Max-Planck-Society
-#
-# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
-
-from .. import utilities
-from ..linearization import Linearization
-from ..operators.energy_operators import StandardHamiltonian
-from ..operators.endomorphic_operator import EndomorphicOperator
-from .energy import Energy
-from mpi4py import MPI
-import numpy as np
-from ..probing import approximation2endo
-from ..sugar import makeOp, full
-from ..field import TMP_fld
-from ..multi_field import TMP_Field
-
-
-_comm = MPI.COMM_WORLD
-ntask = _comm.Get_size()
-rank = _comm.Get_rank()
-master = (rank == 0)
-
-
-def _shareRange(nwork, nshares, myshare):
- nbase = nwork//nshares
- additional = nwork % nshares
- lo = myshare*nbase + min(myshare, additional)
- hi = lo + nbase + int(myshare < additional)
- return lo, hi
-
-
-def np_allreduce_sum(arr):
- arr = np.array(arr)
- res = np.empty_like(arr)
- _comm.Allreduce(arr, res, MPI.SUM)
- return res
-
-
-def allreduce_sum_field(fld):
- if isinstance(fld, TMP_fld):
- return TMP_fld(fld.domain, np_allreduce_sum(fld.val))
- res = tuple(
- TMP_fld(f.domain, np_allreduce_sum(f.val))
- for f in fld.values())
- return TMP_Field(fld.domain, res)
-
-
-class KLMetric(EndomorphicOperator):
- def __init__(self, KL):
- self._KL = KL
- self._capability = self.TIMES | self.ADJOINT_TIMES
- self._domain = KL.position.domain
-
- def apply(self, x, mode):
- self._check_input(x, mode)
- return self._KL.apply_metric(x)
-
- def draw_sample(self, from_inverse=False, dtype=np.float64):
- return self._KL.metric_sample(from_inverse, dtype)
-
-
-class MetricGaussianKL_MPI(Energy):
- """Provides the sampled Kullback-Leibler divergence between a distribution
- and a Metric Gaussian.
-
- A Metric Gaussian is used to approximate another probability distribution.
- It is a Gaussian distribution that uses the Fisher information metric of
- the other distribution at the location of its mean to approximate the
- variance. In order to infer the mean, a stochastic estimate of the
- Kullback-Leibler divergence is minimized. This estimate is obtained by
- sampling the Metric Gaussian at the current mean. During minimization
- these samples are kept constant; only the mean is updated. Due to the
- typically nonlinear structure of the true distribution these samples have
- to be updated eventually by intantiating `MetricGaussianKL` again. For the
- true probability distribution the standard parametrization is assumed.
- The samples of this class are distributed among MPI tasks.
-
- Parameters
- ----------
- mean : TMP_fld
- Mean of the Gaussian probability distribution.
- hamiltonian : StandardHamiltonian
- Hamiltonian of the approximated probability distribution.
- n_samples : integer
- Number of samples used to stochastically estimate the KL.
- constants : list
- List of parameter keys that are kept constant during optimization.
- Default is no constants.
- point_estimates : list
- List of parameter keys for which no samples are drawn, but that are
- (possibly) optimized for, corresponding to point estimates of these.
- Default is to draw samples for the complete domain.
- mirror_samples : boolean
- Whether the negative of the drawn samples are also used,
- as they are equally legitimate samples. If true, the number of used
- samples doubles. Mirroring samples stabilizes the KL estimate as
- extreme sample variation is counterbalanced. Default is False.
- napprox : int
- Number of samples for computing preconditioner for sampling. No
- preconditioning is done by default.
- _samples : None
- Only a parameter for internal uses. Typically not to be set by users.
- seed_offset : int
- A parameter with which one can controll from which seed the samples
- are drawn. Per default, the seed is different for MPI tasks, but the
- same every time this class is initialized.
-
- Note
- ----
- The two lists `constants` and `point_estimates` are independent from each
- other. It is possible to sample along domains which are kept constant
- during minimization and vice versa.
-
- See also
- --------
- `Metric Gaussian Variational Inference`, Jakob Knollmüller,
- Torsten A. Enßlin, ``_
- """
-
- def __init__(self, mean, hamiltonian, n_samples, constants=[],
- point_estimates=[], mirror_samples=False,
- napprox=0, _samples=None, seed_offset=0,
- lh_sampling_dtype=np.float64):
- super(MetricGaussianKL_MPI, self).__init__(mean)
-
- if not isinstance(hamiltonian, StandardHamiltonian):
- raise TypeError
- if hamiltonian.domain is not mean.domain:
- raise ValueError
- if not isinstance(n_samples, int):
- raise TypeError
- self._constants = list(constants)
- self._point_estimates = list(point_estimates)
- if not isinstance(mirror_samples, bool):
- raise TypeError
-
- self._hamiltonian = hamiltonian
-
- if _samples is None:
- if mirror_samples:
- lo, hi = _shareRange(n_samples*2, ntask, rank)
- else:
- lo, hi = _shareRange(n_samples, ntask, rank)
- met = hamiltonian(Linearization.make_partial_var(
- mean, point_estimates, True)).metric
- if napprox > 1:
- met._approximation = makeOp(approximation2endo(met, napprox))
- _samples = []
- rand_state = np.random.get_state()
- for i in range(lo, hi):
- if mirror_samples:
- np.random.seed(i//2+seed_offset)
- if (i % 2) and (i-1 >= lo):
- _samples.append(-_samples[-1])
-
- else:
- _samples.append(((i % 2)*2-1) *
- met.draw_sample(from_inverse=True,
- dtype=lh_sampling_dtype))
- else:
- np.random.seed(i+seed_offset)
- _samples.append(met.draw_sample(from_inverse=True,
- dtype=lh_sampling_dtype))
- np.random.set_state(rand_state)
- _samples = tuple(_samples)
- if mirror_samples:
- n_samples *= 2
- self._samples = _samples
- self._seed_offset = seed_offset
- self._n_samples = n_samples
- self._lin = Linearization.make_partial_var(mean, constants)
- v, g = None, None
- if len(self._samples) == 0: # hack if there are too many MPI tasks
- tmp = self._hamiltonian(self._lin)
- v = 0. * tmp.val.val
- g = 0. * tmp.gradient
- else:
- for s in self._samples:
- tmp = self._hamiltonian(self._lin+s)
- if v is None:
- v = tmp.val.val_rw()
- g = tmp.gradient
- else:
- v += tmp.val.val
- g = g + tmp.gradient
- self._val = np_allreduce_sum(v)[()] / self._n_samples
- self._grad = allreduce_sum_field(g) / self._n_samples
- self._metric = None
- self._sampdt = lh_sampling_dtype
-
- def at(self, position):
- return MetricGaussianKL_MPI(
- position, self._hamiltonian, self._n_samples, self._constants,
- self._point_estimates, _samples=self._samples,
- seed_offset=self._seed_offset, lh_sampling_dtype=self._sampdt)
-
- @property
- def value(self):
- return self._val
-
- @property
- def gradient(self):
- return self._grad
-
- def _get_metric(self):
- lin = self._lin.with_want_metric()
- if self._metric is None:
- if len(self._samples) == 0: # hack if there are too many MPI tasks
- self._metric = self._hamiltonian(lin).metric.scale(0.)
- else:
- mymap = map(lambda v: self._hamiltonian(lin+v).metric,
- self._samples)
- self.unscaled_metric = utilities.my_sum(mymap)
- self._metric = self.unscaled_metric.scale(1./self._n_samples)
-
- def apply_metric(self, x):
- self._get_metric()
- return allreduce_sum_field(self._metric(x))
-
- @property
- def metric(self):
- return KLMetric(self)
-
- @property
- def samples(self):
- res = _comm.allgather(self._samples)
- res = [item for sublist in res for item in sublist]
- return res
-
- def unscaled_metric_sample(self, from_inverse=False, dtype=np.float64):
- if from_inverse:
- raise NotImplementedError()
- lin = self._lin.with_want_metric()
- samp = full(self._hamiltonian.domain, 0.)
- rand_state = np.random.get_state()
- np.random.seed(rank+np.random.randint(99999))
- for v in self._samples:
- samp = samp + self._hamiltonian(lin+v).metric.draw_sample(from_inverse=False, dtype=dtype)
- np.random.set_state(rand_state)
- return allreduce_sum_field(samp)
-
- def metric_sample(self, from_inverse=False, dtype=np.float64):
- return self.unscaled_metric_sample(from_inverse, dtype)/self._n_samples
diff --git a/nifty6/mpi.py b/nifty6/mpi.py
deleted file mode 100644
index b5a3d58ff23faaabf691f31d6ae3ff2164f033c7..0000000000000000000000000000000000000000
--- a/nifty6/mpi.py
+++ /dev/null
@@ -1 +0,0 @@
-from .minimization.metric_gaussian_kl_mpi import MetricGaussianKL_MPI
diff --git a/nifty6/operators/operator.py b/nifty6/operators/operator.py
index ccc6433f4bea4496e5ad107fc117ce26a468576b..b92f02b589380a1e600ba5397d0088433c7f3075 100644
--- a/nifty6/operators/operator.py
+++ b/nifty6/operators/operator.py
@@ -27,10 +27,6 @@ class Operator(metaclass=NiftyMeta):
domain, and can also provide the Jacobian.
"""
- VALUE_ONLY = 0
- WITH_JAC = 1
- WITH_METRIC = 2
-
@property
def domain(self):
"""The domain on which the Operator's input TMP_fld is defined.
@@ -202,7 +198,7 @@ class Operator(metaclass=NiftyMeta):
return self.apply(x.trivial_jac()).prepend_jac(x.jac)
elif isinstance(x, (TMP_fld, TMP_Field)):
return self.apply(x)
- raise TypeError('Operator can only consume TMP_fld, TMP_Fields and Linearizations')
+ return self @ x
def ducktape(self, name):
from .simple_linear_operators import ducktape
diff --git a/nifty6/random.py b/nifty6/random.py
index 673bf6596444d826f149520a26759f8dd423a603..37b0d414343c8e46ac78c9de81fa12e76c846c24 100644
--- a/nifty6/random.py
+++ b/nifty6/random.py
@@ -11,21 +11,150 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-# Copyright(C) 2013-2019 Max-Planck-Society
+# Copyright(C) 2013-2020 Max-Planck-Society
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
+"""
+Some remarks on NIFTy's treatment of random numbers
+
+NIFTy makes use of the `Generator` and `SeedSequence` classes introduced to
+`numpy.random` in numpy 1.17.
+
+On first load of the `nifty6.random` module, it creates a stack of
+`SeedSequence` objects which contains a single `SeedSequence` with a fixed seed,
+and also a stack of `Generator` objects, which contains a single generator
+derived from the above seed sequence. Without user intervention, this generator
+will be used for all random number generation tasks within NIFTy. This means
+
+- that random numbers drawn by NIFTy will be reproducible across multiple runs
+ (assuming there are no complications like MPI-enabled runs with a varying
+ number of tasks), and
+- that trying to change random seeds via `numpy.random.seed` will have no
+ effect on the random numbers drawn by NIFTy.
+
+Users who want to change the random seed for a given run can achieve this
+by calling `push_sseq_from_seed()` with a seed of their choice. This will push
+a new seed sequence generated from that seed onto the seed sequence stack, and a
+generator derived from this seed sequence onto the generator stack. Since all
+NIFTy RNG-related calls will use the generator on the top of the stack, all
+calls from this point on will use the new generator.
+If the user already has a `SeedSequence` object at hand, they can pass this to
+NIFTy via `push_sseq`. A new generator derived from this sequence will then also
+be pushed onto the generator stack.
+These operations can be reverted (and should be, as soon as the new generator is
+no longer needed) by a call to `pop_sseq()`.
+When users need direct access to the RNG currently in use, they can access it
+via the `current_rng` function.
+
+
+Example for using multiple seed sequences:
+
+Assume that N samples are needed to compute a KL, which are distributed over
+a variable number of MPI tasks. In this situation, whenever random numbers
+need to be drawn for these samples:
+- each MPI task should spawn as many seed sequences as there are samples
+ _in total_, using `sseq = spawn_sseq(N)`
+- each task loops over the local samples
+ - first pushing the seed sequence for the global(!) index of the
+ current sample via `push_sseq(sseq[iglob])`
+ - drawing the required random numbers
+ - then popping the seed sequence again via `pop_sseq()`
+
+That way, random numbers should be reproducible and independent of the number
+of MPI tasks.
+
+WARNING: do not push/pop the same `SeedSequence` object more than once - this
+will lead to repeated random sequences! Whenever you have to push `SeedSequence`
+objects, generate new ones via `spawn_sseq()`.
+"""
+
import numpy as np
+# Stack of SeedSequence objects. Will always start out with a well-defined
+# default. Users can change the "random seed" used by a calculation by pushing
+# a different SeedSequence before invoking any other nifty6.random calls
+_sseq = [np.random.SeedSequence(42)]
+# Stack of random number generators associated with _sseq.
+_rng = [np.random.default_rng(_sseq[-1])]
+
+
+def spawn_sseq(n, parent=None):
+ """Returns a list of `n` SeedSequence objects which are children of `parent`
+
+ Parameters
+ ----------
+ n : int
+ number of requested SeedSequence objects
+ parent : SeedSequence
+ the object from which the returned objects will be derived
+ If `None`, the top of the current SeedSequence stack will be used
+
+ Returns
+ -------
+ list(SeedSequence)
+ the requested SeedSequence objects
+ """
+ if parent is None:
+ global _sseq
+ parent = _sseq[-1]
+ return parent.spawn(n)
+
+
+def current_rng():
+ """Returns the RNG object currently in use by NIFTy
+
+ Returns
+ -------
+ Generator
+ the current Generator object (top of the generatir stack)
+ """
+ return _rng[-1]
+
+
+def push_sseq(sseq):
+ """Pushes a new SeedSequence object onto the SeedSequence stack.
+ This also pushes a new Generator object built from the new SeedSequence
+ to the generator stack.
+
+ Parameters
+ ----------
+ sseq: SeedSequence
+ the SeedSequence object to be used from this point
+ """
+ _sseq.append(sseq)
+ _rng.append(np.random.default_rng(_sseq[-1]))
+
+
+def push_sseq_from_seed(seed):
+ """Pushes a new SeedSequence object derived from an integer seed onto the
+ SeedSequence stack.
+ This also pushes a new Generator object built from the new SeedSequence
+ to the generator stack.
+
+ Parameters
+ ----------
+ seed: int
+ the seed from which the new SeedSequence will be built
+ """
+ _sseq.append(np.random.SeedSequence(seed))
+ _rng.append(np.random.default_rng(_sseq[-1]))
+
+
+def pop_sseq():
+ """Pops the top of the SeedSequence and generator stacks."""
+ _sseq.pop()
+ _rng.pop()
+
class Random(object):
@staticmethod
def pm1(dtype, shape):
if np.issubdtype(dtype, np.complexfloating):
x = np.array([1+0j, 0+1j, -1+0j, 0-1j], dtype=dtype)
- x = x[np.random.randint(4, size=shape)]
+ x = x[_rng[-1].integers(0, 4, size=shape)]
else:
- x = 2*np.random.randint(2, size=shape) - 1
+ x = 2*_rng[-1].integers(0, 2, size=shape)-1
return x.astype(dtype, copy=False)
@staticmethod
@@ -42,10 +171,10 @@ class Random(object):
raise TypeError("mean must not be complex for a real result field")
if np.issubdtype(dtype, np.complexfloating):
x = np.empty(shape, dtype=dtype)
- x.real = np.random.normal(mean.real, std*np.sqrt(0.5), shape)
- x.imag = np.random.normal(mean.imag, std*np.sqrt(0.5), shape)
+ x.real = _rng[-1].normal(mean.real, std*np.sqrt(0.5), shape)
+ x.imag = _rng[-1].normal(mean.imag, std*np.sqrt(0.5), shape)
else:
- x = np.random.normal(mean, std, shape).astype(dtype, copy=False)
+ x = _rng[-1].normal(mean, std, shape).astype(dtype, copy=False)
return x
@staticmethod
@@ -57,13 +186,13 @@ class Random(object):
raise TypeError("low and high must not be complex")
if np.issubdtype(dtype, np.complexfloating):
x = np.empty(shape, dtype=dtype)
- x.real = np.random.uniform(low, high, shape)
- x.imag = np.random.uniform(low, high, shape)
+ x.real = _rng[-1].uniform(low, high, shape)
+ x.imag = _rng[-1].uniform(low, high, shape)
elif np.issubdtype(dtype, np.integer):
if not (np.issubdtype(type(low), np.integer) and
np.issubdtype(type(high), np.integer)):
raise TypeError("low and high must be integer")
- x = np.random.randint(low, high+1, shape)
+ x = _rng[-1].integers(low, high+1, shape)
else:
- x = np.random.uniform(low, high, shape)
+ x = _rng[-1].uniform(low, high, shape)
return x.astype(dtype, copy=False)
diff --git a/setup.py b/setup.py
index f909590dcc64d07e03d03ced3a89608e3af76b48..f90a59031a1039c69408275c7f707a95f62eeb32 100644
--- a/setup.py
+++ b/setup.py
@@ -39,8 +39,8 @@ setup(name="nifty6",
packages=find_packages(include=["nifty6", "nifty6.*"]),
zip_safe=True,
license="GPLv3",
- setup_requires=['scipy>=1.4.1'],
- install_requires=['scipy>=1.4.1'],
+ setup_requires=['scipy>=1.4.1', 'numpy>=1.17'],
+ install_requires=['scipy>=1.4.1', 'numpy>=1.17'],
python_requires='>=3.5',
classifiers=[
"Development Status :: 4 - Beta",
diff --git a/test/common.py b/test/common.py
index 9b95150d7ad0ebf1ea0922348fae3fba3a791fd1..ba5224fe61a222cd9ba87f9ac5d6c6f46d78116d 100644
--- a/test/common.py
+++ b/test/common.py
@@ -11,7 +11,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-# Copyright(C) 2013-2019 Max-Planck-Society
+# Copyright(C) 2013-2020 Max-Planck-Society
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
@@ -24,3 +24,13 @@ def list2fixture(lst):
return request.param
return myfixture
+
+
+def setup_function():
+ import nifty6 as ift
+ ift.random.push_sseq_from_seed(42)
+
+
+def teardown_function():
+ import nifty6 as ift
+ ift.random.pop_sseq()
diff --git a/test/test_energy_gradients.py b/test/test_energy_gradients.py
index 0cd8490fc9225794fea24ec9f4d7b69a74af3e7a..7e78bc1b5452822e1929509ecd599fa325f3b3c6 100644
--- a/test/test_energy_gradients.py
+++ b/test/test_energy_gradients.py
@@ -11,7 +11,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-# Copyright(C) 2013-2019 Max-Planck-Society
+# Copyright(C) 2013-2020 Max-Planck-Society
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
@@ -20,6 +20,7 @@ import pytest
import nifty6 as ift
from itertools import product
+from .common import setup_function, teardown_function
# Currently it is not possible to parametrize fixtures. But this will
# hopefully be fixed in the future.
@@ -37,9 +38,11 @@ pmp = pytest.mark.parametrize
@pytest.fixture(params=PARAMS)
def field(request):
- np.random.seed(request.param[0])
+ ift.random.push_sseq_from_seed(request.param[0])
S = ift.ScalingOperator(request.param[1], 1.)
- return S.draw_sample()
+ res = S.draw_sample()
+ ift.random.pop_sseq()
+ return res
def test_gaussian(field):
@@ -102,7 +105,7 @@ def test_inverse_gamma(field):
return
field = field.exp()
space = field.domain
- d = np.random.normal(10, size=space.shape)**2
+ d = ift.random.current_rng().normal(10, size=space.shape)**2
d = ift.TMP_fld(space, d)
energy = ift.InverseGammaLikelihood(d)
ift.extra.check_jacobian_consistency(energy, field, tol=1e-5)
@@ -113,10 +116,10 @@ def testPoissonian(field):
return
field = field.exp()
space = field.domain
- d = np.random.poisson(120, size=space.shape)
+ d = ift.random.current_rng().poisson(120, size=space.shape)
d = ift.TMP_fld(space, d)
energy = ift.PoissonianEnergy(d)
- ift.extra.check_jacobian_consistency(energy, field, tol=1e-7)
+ ift.extra.check_jacobian_consistency(energy, field, tol=1e-6)
def test_bernoulli(field):
@@ -124,7 +127,7 @@ def test_bernoulli(field):
return
field = field.sigmoid()
space = field.domain
- d = np.random.binomial(1, 0.1, size=space.shape)
+ d = ift.random.current_rng().binomial(1, 0.1, size=space.shape)
d = ift.TMP_fld(space, d)
energy = ift.BernoulliEnergy(d)
ift.extra.check_jacobian_consistency(energy, field, tol=1e-5)
diff --git a/test/test_field.py b/test/test_field.py
index 5a33dd0dd87efcf5e7c02c2ce36062ead045d907..c8ac577ba9ce015c251944161a848f8f4d5b88ba 100644
--- a/test/test_field.py
+++ b/test/test_field.py
@@ -20,6 +20,7 @@ import pytest
from numpy.testing import assert_allclose, assert_equal, assert_raises
import nifty6 as ift
+from .common import setup_function, teardown_function
pmp = pytest.mark.parametrize
SPACES = [ift.RGSpace((4,)), ift.RGSpace((5))]
@@ -51,8 +52,6 @@ def _spec2(k):
])
@pmp('space2', [ift.RGSpace((8,), harmonic=True), ift.LMSpace(12)])
def test_power_synthesize_analyze(space1, space2):
- np.random.seed(11)
-
p1 = ift.PowerSpace(space1)
fp1 = ift.PS_field(p1, _spec1)
p2 = ift.PowerSpace(space2)
@@ -82,8 +81,6 @@ def test_power_synthesize_analyze(space1, space2):
])
@pmp('space2', [ift.RGSpace((8,), harmonic=True), ift.LMSpace(12)])
def test_DiagonalOperator_power_analyze2(space1, space2):
- np.random.seed(11)
-
fp1 = ift.PS_field(ift.PowerSpace(space1), _spec1)
fp2 = ift.PS_field(ift.PowerSpace(space2), _spec2)
diff --git a/test/test_gaussian_energy.py b/test/test_gaussian_energy.py
index d216f7a4e78b469d1429a74dd15f2258f57901ff..e2cd2535497613508d3d1c89c79e3104ef8a9a78 100644
--- a/test/test_gaussian_energy.py
+++ b/test/test_gaussian_energy.py
@@ -19,6 +19,7 @@ import numpy as np
import pytest
import nifty6 as ift
+from .common import setup_function, teardown_function
def _flat_PS(k):
@@ -37,7 +38,7 @@ pmp = pytest.mark.parametrize
@pmp('noise', [1, 1e-2, 1e2])
@pmp('seed', [4, 78, 23])
def test_gaussian_energy(space, nonlinearity, noise, seed):
- np.random.seed(seed)
+ ift.random.push_sseq_from_seed(seed)
dim = len(space.shape)
hspace = space.get_default_codomain()
ht = ift.HarmonicTransformOperator(hspace, target=space)
@@ -70,4 +71,5 @@ def test_gaussian_energy(space, nonlinearity, noise, seed):
energy = ift.GaussianEnergy(d, N) @ d_model()
ift.extra.check_jacobian_consistency(
- energy, xi0, ntries=10, tol=5e-8)
+ energy, xi0, ntries=10, tol=1e-6)
+ ift.random.pop_sseq()
diff --git a/test/test_kl.py b/test/test_kl.py
index 31ff187558ca7562aeb119626849f2c310a6b257..425da1ca61efda1179cc8ae86002312940dfbd2d 100644
--- a/test/test_kl.py
+++ b/test/test_kl.py
@@ -20,6 +20,7 @@ import numpy as np
import nifty6 as ift
from numpy.testing import assert_, assert_allclose
import pytest
+from .common import setup_function, teardown_function
pmp = pytest.mark.parametrize
@@ -28,7 +29,6 @@ pmp = pytest.mark.parametrize
@pmp('point_estimates', ([], ['a'], ['b'], ['a', 'b']))
@pmp('mirror_samples', (True, False))
def test_kl(constants, point_estimates, mirror_samples):
- np.random.seed(42)
dom = ift.RGSpace((12,), (2.12))
op0 = ift.HarmonicSmoothingOperator(dom, 3)
op = ift.ducktape(dom, None, 'a')*(op0.ducktape('b'))
@@ -45,12 +45,13 @@ def test_kl(constants, point_estimates, mirror_samples):
point_estimates=point_estimates,
mirror_samples=mirror_samples,
napprox=0)
+ samp_full = kl.samples
klpure = ift.MetricGaussianKL(mean0,
h,
- nsamps,
- mirror_samples=mirror_samples,
+ len(samp_full),
+ mirror_samples=False,
napprox=0,
- _samples=kl.samples)
+ _samples=samp_full)
# Test value
assert_allclose(kl.value, klpure.value)
diff --git a/test/test_linearization.py b/test/test_linearization.py
index 3e2605e765533a443c17be52abf87683c4f45347..b44e5b09765db9e01a9d68eb8865307c21f555c2 100644
--- a/test/test_linearization.py
+++ b/test/test_linearization.py
@@ -20,6 +20,7 @@ import pytest
from numpy.testing import assert_, assert_allclose
import nifty6 as ift
+from .common import setup_function, teardown_function
pmp = pytest.mark.parametrize
diff --git a/test/test_minimizers.py b/test/test_minimizers.py
index 9ae0491f53b2013da95f46ec814ce104ba99916b..01bfcbefe3c64002dba1c813b7c596d6acc667c8 100644
--- a/test/test_minimizers.py
+++ b/test/test_minimizers.py
@@ -22,6 +22,7 @@ import pytest
from numpy.testing import assert_allclose, assert_equal
import nifty6 as ift
+from .common import setup_function, teardown_function
pmp = pytest.mark.parametrize
IC = ift.GradientNormController(tol_abs_gradnorm=1e-5, iteration_limit=1000)
@@ -51,9 +52,14 @@ slow_minimizers = ['ift.SteepestDescent(IC)']
slow_minimizers)
@pmp('space', spaces)
def test_quadratic_minimization(minimizer, space):
+<<<<<<< HEAD
np.random.seed(42)
starting_point = ift.TMP_fld.from_random('normal', domain=space)*10
covariance_diagonal = ift.TMP_fld.from_random('uniform', domain=space) + 0.5
+=======
+ starting_point = ift.Field.from_random('normal', domain=space)*10
+ covariance_diagonal = ift.Field.from_random('uniform', domain=space) + 0.5
+>>>>>>> NIFTy_6
covariance = ift.DiagonalOperator(covariance_diagonal)
required_result = ift.full(space, 1.)
@@ -76,7 +82,6 @@ def test_quadratic_minimization(minimizer, space):
@pmp('space', spaces)
def test_WF_curvature(space):
- np.random.seed(42)
required_result = ift.full(space, 1.)
s = ift.TMP_fld.from_random('uniform', domain=space) + 0.5
@@ -121,10 +126,8 @@ def test_rosenbrock(minimizer):
from scipy.optimize import rosen, rosen_der, rosen_hess_prod
except ImportError:
raise SkipTest
- np.random.seed(42)
space = ift.TMP_domtup.make(ift.TMP_UnstructuredSpace((2,)))
starting_point = ift.TMP_fld.from_random('normal', domain=space)*10
-
class RBEnergy(ift.Energy):
def __init__(self, position):
super(RBEnergy, self).__init__(position)
diff --git a/test/test_multi_field.py b/test/test_multi_field.py
index 5251c6638f721f3b0f04387ba31a9e1c3292f2e6..46f09b877b6ca4795bf069a2dbcfa618eb9ab6b2 100644
--- a/test/test_multi_field.py
+++ b/test/test_multi_field.py
@@ -19,6 +19,7 @@ import numpy as np
from numpy.testing import assert_allclose, assert_equal
import nifty6 as ift
+from .common import setup_function, teardown_function
dom = ift.makeTMP_domtup({"d1": ift.RGSpace(10)})
diff --git a/test/test_operators/test_adjoint.py b/test/test_operators/test_adjoint.py
index caca3fe1a7770c5786f12d6b10beb234cb1caffd..91462f1d1790af2e98d5713c28bf073a22cf7e5e 100644
--- a/test/test_operators/test_adjoint.py
+++ b/test/test_operators/test_adjoint.py
@@ -20,7 +20,7 @@ import pytest
import nifty6 as ift
-from ..common import list2fixture
+from ..common import list2fixture, setup_function, teardown_function
_h_RG_spaces = [
ift.RGSpace(7, distances=0.2, harmonic=True),
@@ -41,15 +41,13 @@ _pow_spaces = [
pmp = pytest.mark.parametrize
dtype = list2fixture([np.float64, np.complex128])
-np.random.seed(42)
-
@pmp('sp', _p_RG_spaces)
def testLOSResponse(sp, dtype):
- starts = np.random.randn(len(sp.shape), 10)
- ends = np.random.randn(len(sp.shape), 10)
- sigma_low = 1e-4*np.random.randn(10)
- sigma_ups = 1e-5*np.random.randn(10)
+ starts = ift.random.current_rng().standard_normal((len(sp.shape), 10))
+ ends = ift.random.current_rng().standard_normal((len(sp.shape), 10))
+ sigma_low = 1e-4*ift.random.current_rng().standard_normal(10)
+ sigma_ups = 1e-5*ift.random.current_rng().standard_normal(10)
op = ift.LOSResponse(sp, starts, ends, sigma_low, sigma_ups)
ift.extra.consistency_check(op, dtype, dtype)
@@ -70,7 +68,7 @@ def testOperatorCombinations(sp, dtype):
def testLinearInterpolator():
sp = ift.RGSpace((10, 8), distances=(0.1, 3.5))
- pos = np.random.rand(2, 23)
+ pos = ift.random.current_rng().random((2, 23))
pos[0, :] *= 0.9
pos[1, :] *= 7*3.5
op = ift.LinearInterpolator(sp, pos)
@@ -250,15 +248,16 @@ def testOuter(fdomain, domain):
@pmp('sp', _h_spaces + _p_spaces + _pow_spaces)
@pmp('seed', [12, 3])
def testValueInserter(sp, seed):
- np.random.seed(seed)
+ ift.random.push_sseq_from_seed(seed)
ind = []
for ss in sp.shape:
if ss == 1:
ind.append(0)
else:
- ind.append(np.random.randint(0, ss-1))
+ ind.append(int(ift.random.current_rng().integers(0, ss-1)))
op = ift.ValueInserter(sp, ind)
ift.extra.consistency_check(op)
+ ift.random.pop_sseq()
@pmp('sp', _pow_spaces)
@@ -282,18 +281,19 @@ def testSpecialSum(sp):
@pmp('sp', [ift.RGSpace(10)])
@pmp('seed', [12, 3])
def testMatrixProductOperator(sp, seed):
- np.random.seed(seed)
- mat = np.random.randn(*sp.shape, *sp.shape)
+ ift.random.push_sseq_from_seed(seed)
+ mat = ift.random.current_rng().standard_normal((*sp.shape, *sp.shape))
op = ift.MatrixProductOperator(sp, mat)
ift.extra.consistency_check(op)
- mat = mat + 1j*np.random.randn(*sp.shape, *sp.shape)
+ mat = mat + 1j*ift.random.current_rng().standard_normal((*sp.shape, *sp.shape))
op = ift.MatrixProductOperator(sp, mat)
ift.extra.consistency_check(op)
+ ift.random.pop_sseq()
@pmp('seed', [12, 3])
def testPartialExtractor(seed):
- np.random.seed(seed)
+ ift.random.push_sseq_from_seed(seed)
tgt = {'a': ift.RGSpace(1), 'b': ift.RGSpace(2)}
dom = tgt.copy()
dom['c'] = ift.RGSpace(3)
@@ -301,6 +301,7 @@ def testPartialExtractor(seed):
tgt = ift.TMP_Domain.make(tgt)
op = ift.PartialExtractor(dom, tgt)
ift.extra.consistency_check(op)
+ ift.random.pop_sseq()
@pmp('seed', [12, 3])
diff --git a/test/test_operators/test_composed_operator.py b/test/test_operators/test_composed_operator.py
index dd3fc27e0769e680c7b4ca726ed893c42f3f152a..265d53890a5959ed201ee5224dff4674cfbacb44 100644
--- a/test/test_operators/test_composed_operator.py
+++ b/test/test_operators/test_composed_operator.py
@@ -19,7 +19,7 @@ from numpy.testing import assert_allclose, assert_equal
import nifty6 as ift
-from ..common import list2fixture
+from ..common import list2fixture, setup_function, teardown_function
space1 = list2fixture([
ift.RGSpace(4),
diff --git a/test/test_operators/test_convolution_operators.py b/test/test_operators/test_convolution_operators.py
index e542ec0cd351540050e51dc26666986cd7637384..7e66e4f3edb5839083a217bcc46b5141081a8e7f 100644
--- a/test/test_operators/test_convolution_operators.py
+++ b/test/test_operators/test_convolution_operators.py
@@ -20,7 +20,7 @@ from numpy.testing import assert_allclose
import nifty6 as ift
import numpy as np
-from ..common import list2fixture
+from ..common import list2fixture, setup_function, teardown_function
space = list2fixture([
ift.RGSpace(4),
diff --git a/test/test_operators/test_correlated_fields.py b/test/test_operators/test_correlated_fields.py
index 95203965ec48abc2d772b2fda890e8152f30e12e..a662181d64fe5904462cf05251fb7efd5b212f43 100644
--- a/test/test_operators/test_correlated_fields.py
+++ b/test/test_operators/test_correlated_fields.py
@@ -16,10 +16,10 @@
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
import pytest
-from numpy.random import seed
from numpy.testing import assert_allclose
import nifty6 as ift
+from ..common import setup_function, teardown_function
@pytest.mark.parametrize('sspace', [
@@ -39,7 +39,7 @@ def testAmplitudesConsistency(rseed, sspace, Astds, offset_std, N):
sc.add(op(s.extract(op.domain)))
return sc.mean.val, sc.var.sqrt().val
- seed(rseed)
+ ift.random.push_sseq_from_seed(rseed)
nsam = 100
fsspace = ift.RGSpace((12,), (0.4,))
@@ -91,6 +91,7 @@ def testAmplitudesConsistency(rseed, sspace, Astds, offset_std, N):
em, estd = stats(fa.slice_fluctuation(0), samples)
assert_allclose(m, em, rtol=0.5)
+ ift.random.pop_sseq()
assert op.target[-2] == sspace
assert op.target[-1] == fsspace
diff --git a/test/test_operators/test_diagonal_operator.py b/test/test_operators/test_diagonal_operator.py
index afc8437f4b7cedbef6c7cc242ae984ecd3d9459e..d474d59db2a8c6e4e7b7e01f2879b99fb7c0320b 100644
--- a/test/test_operators/test_diagonal_operator.py
+++ b/test/test_operators/test_diagonal_operator.py
@@ -19,7 +19,7 @@ from numpy.testing import assert_allclose, assert_equal
import nifty6 as ift
-from ..common import list2fixture
+from ..common import list2fixture, setup_function, teardown_function
space = list2fixture([
ift.RGSpace(4),
diff --git a/test/test_operators/test_fft_operator.py b/test/test_operators/test_fft_operator.py
index 45d9b3004b50b717d80b6656203083a9ef0c2f74..d94a96fc4f7628d6383df02b7edf0cd7a0691204 100644
--- a/test/test_operators/test_fft_operator.py
+++ b/test/test_operators/test_fft_operator.py
@@ -21,7 +21,7 @@ from numpy.testing import assert_, assert_allclose
import nifty6 as ift
-from ..common import list2fixture
+from ..common import list2fixture, setup_function, teardown_function
def _get_rtol(tp):
@@ -42,7 +42,6 @@ def test_fft1D(d, dtype, op):
tol = _get_rtol(dtype)
a = ift.RGSpace(dim1, distances=d)
b = ift.RGSpace(dim1, distances=1./(dim1*d), harmonic=True)
- np.random.seed(16)
fft = op(domain=a, target=b)
inp = ift.TMP_fld.from_random(
diff --git a/test/test_operators/test_harmonic_transform_operator.py b/test/test_operators/test_harmonic_transform_operator.py
index 99c0708a82a9f48e94f91845b57a56a8fb93f310..59e6d05b48f24d89fdad8fcac944f6a84aa5975e 100644
--- a/test/test_operators/test_harmonic_transform_operator.py
+++ b/test/test_operators/test_harmonic_transform_operator.py
@@ -21,7 +21,7 @@ from numpy.testing import assert_allclose
import nifty6 as ift
-from ..common import list2fixture
+from ..common import list2fixture, setup_function, teardown_function
def _get_rtol(tp):
diff --git a/test/test_operators/test_interpolated.py b/test/test_operators/test_interpolated.py
index 66dd437d581b43ddd7b632c3b7558a4c4e648787..e88bdabc09527087674daa17d72ee194115fcda9 100644
--- a/test/test_operators/test_interpolated.py
+++ b/test/test_operators/test_interpolated.py
@@ -22,7 +22,7 @@ from scipy.stats import invgamma, norm
import nifty6 as ift
-from ..common import list2fixture
+from ..common import list2fixture, setup_function, teardown_function
pmp = pytest.mark.parametrize
pmp = pytest.mark.parametrize
diff --git a/test/test_operators/test_jacobian.py b/test/test_operators/test_jacobian.py
index befe9f4d19b7562f677ebba6c554e88ee623c200..5eee79281f2f9fe1c791f7eecf04fd2d5152331b 100644
--- a/test/test_operators/test_jacobian.py
+++ b/test/test_operators/test_jacobian.py
@@ -20,7 +20,7 @@ import pytest
import nifty6 as ift
-from ..common import list2fixture
+from ..common import list2fixture, setup_function, teardown_function
pmp = pytest.mark.parametrize
space = list2fixture([
@@ -38,18 +38,19 @@ seed = list2fixture([4, 78, 23])
def testBasics(space, seed):
- np.random.seed(seed)
+ ift.random.push_sseq_from_seed(seed)
S = ift.ScalingOperator(space, 1.)
s = S.draw_sample()
var = ift.Linearization.make_var(s)
model = ift.ScalingOperator(var.target, 6.)
ift.extra.check_jacobian_consistency(model, var.val)
+ ift.random.pop_sseq()
@pmp('type1', ['Variable', 'Constant'])
@pmp('type2', ['Variable'])
def testBinary(type1, type2, space, seed):
- np.random.seed(seed)
+ ift.random.push_sseq_from_seed(seed)
dom1 = ift.TMP_Domain.make({'s1': space})
dom2 = ift.TMP_Domain.make({'s2': space})
dom = ift.TMP_Domain.union((dom1, dom2))
@@ -87,10 +88,11 @@ def testBinary(type1, type2, space, seed):
model = ift.FFTOperator(space)(select_s1*select_s2)
pos = ift.from_random("normal", dom)
ift.extra.check_jacobian_consistency(model, pos, ntries=20)
+ ift.random.pop_sseq()
def testSpecialDistributionOps(space, seed):
- np.random.seed(seed)
+ ift.random.push_sseq_from_seed(seed)
S = ift.ScalingOperator(space, 1.)
pos = S.draw_sample()
alpha = 1.5
@@ -99,11 +101,12 @@ def testSpecialDistributionOps(space, seed):
ift.extra.check_jacobian_consistency(model, pos, ntries=20)
model = ift.UniformOperator(space, alpha, q)
ift.extra.check_jacobian_consistency(model, pos, ntries=20)
+ ift.random.pop_sseq()
@pmp('neg', [True, False])
def testAdder(space, seed, neg):
- np.random.seed(seed)
+ ift.random.push_sseq_from_seed(seed)
S = ift.ScalingOperator(space, 1.)
f = S.draw_sample()
f1 = S.draw_sample()
@@ -111,6 +114,7 @@ def testAdder(space, seed, neg):
ift.extra.check_jacobian_consistency(op, f)
op = ift.Adder(f1.val.ravel()[0], neg=neg, domain=space)
ift.extra.check_jacobian_consistency(op, f)
+ ift.random.pop_sseq()
@pmp('target', [ift.RGSpace(64, distances=.789, harmonic=True),
@@ -119,7 +123,7 @@ def testAdder(space, seed, neg):
@pmp('causal', [True, False])
@pmp('minimum_phase', [True, False])
def testDynamicModel(target, causal, minimum_phase, seed):
- np.random.seed(seed)
+ ift.random.push_sseq_from_seed(seed)
dct = {
'target': target,
'harmonic_padding': None,
@@ -156,6 +160,7 @@ def testDynamicModel(target, causal, minimum_phase, seed):
# FIXME I dont know why smaller tol fails for 3D example
ift.extra.check_jacobian_consistency(
model, pos, tol=1e-5, ntries=20)
+ ift.random.pop_sseq()
@pmp('h_space', _h_spaces)
diff --git a/test/test_operators/test_nft.py b/test/test_operators/test_nft.py
index d3d950f151985248ffad522fae11ec0410f8886e..811d43ff398c98cd21280806dc4a5eb7535ab358 100644
--- a/test/test_operators/test_nft.py
+++ b/test/test_operators/test_nft.py
@@ -20,8 +20,7 @@ import pytest
from numpy.testing import assert_
import nifty6 as ift
-
-np.random.seed(40)
+from ..common import setup_function, teardown_function
pmp = pytest.mark.parametrize
@@ -35,8 +34,9 @@ def _l2error(a, b):
@pmp('nv', [4, 12, 128])
@pmp('N', [1, 10, 100])
def test_gridding(nu, nv, N, eps):
- uv = np.random.rand(N, 2) - 0.5
- vis = np.random.randn(N) + 1j*np.random.randn(N)
+ uv = ift.random.current_rng().random((N, 2)) - 0.5
+ vis = (ift.random.current_rng().standard_normal(N)
+ + 1j*ift.random.current_rng().standard_normal(N))
# Nifty
dom = ift.RGSpace((nu, nv), distances=(0.2, 1.12))
@@ -92,7 +92,7 @@ def test_cartesian():
@pmp('N', [1, 10, 100])
def test_build(nu, nv, N, eps):
dom = ift.RGSpace([nu, nv])
- uv = np.random.rand(N, 2) - 0.5
+ uv = ift.random.current_rng().random((N, 2)) - 0.5
GM = ift.GridderMaker(dom, uv=uv, eps=eps)
R0 = GM.getGridder()
R1 = GM.getRest()
diff --git a/test/test_operators/test_partial_multifield_insert.py b/test/test_operators/test_partial_multifield_insert.py
index 0d8a80047fc63fed7a16140ad9073b1173353958..3144db389966a73cd406b5dae549bd8fe1f9c3c1 100644
--- a/test/test_operators/test_partial_multifield_insert.py
+++ b/test/test_operators/test_partial_multifield_insert.py
@@ -21,7 +21,7 @@ from numpy.testing import assert_, assert_allclose
import nifty6 as ift
-from ..common import list2fixture
+from ..common import list2fixture, setup_function, teardown_function
pmp = pytest.mark.parametrize
dtype = list2fixture([np.float64, np.float32, np.complex64, np.complex128])
diff --git a/test/test_operators/test_regridding.py b/test/test_operators/test_regridding.py
index 1cb8b3849ef770cf86c6772646181cdb390d61a4..444efdf7092c3ef957de46cc14edf619e94b66a3 100644
--- a/test/test_operators/test_regridding.py
+++ b/test/test_operators/test_regridding.py
@@ -19,7 +19,7 @@ from numpy.testing import assert_allclose
import nifty6 as ift
-from ..common import list2fixture
+from ..common import list2fixture, setup_function, teardown_function
s = list2fixture([
ift.RGSpace(8, distances=12.9),
diff --git a/test/test_operators/test_representation.py b/test/test_operators/test_representation.py
index 1bb2fba8adc487f46457ddaafff157c9779ebae1..b2b3c55b94a1f13b499edac0df78daa88e5d60ff 100644
--- a/test/test_operators/test_representation.py
+++ b/test/test_operators/test_representation.py
@@ -11,7 +11,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-# Copyright(C) 2013-2019 Max-Planck-Society
+# Copyright(C) 2013-2020 Max-Planck-Society
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
@@ -20,7 +20,7 @@ import pytest
import nifty6 as ift
-from ..common import list2fixture
+from ..common import list2fixture, setup_function, teardown_function
_h_RG_spaces = [
ift.RGSpace(7, distances=0.2, harmonic=True),
@@ -44,10 +44,10 @@ def _check_repr(op):
@pmp('sp', _p_RG_spaces)
def testLOSResponse(sp, dtype):
- starts = np.random.randn(len(sp.shape), 10)
- ends = np.random.randn(len(sp.shape), 10)
- sigma_low = 1e-4*np.random.randn(10)
- sigma_ups = 1e-5*np.random.randn(10)
+ starts = ift.random.current_rng().standard_normal((len(sp.shape), 10))
+ ends = ift.random.current_rng().standard_normal((len(sp.shape), 10))
+ sigma_low = 1e-4*ift.random.current_rng().standard_normal(10)
+ sigma_ups = 1e-5*ift.random.current_rng().standard_normal(10)
_check_repr(ift.LOSResponse(sp, starts, ends, sigma_low, sigma_ups))
@@ -65,7 +65,7 @@ def testOperatorCombinations(sp, dtype):
def testLinearInterpolator():
sp = ift.RGSpace((10, 8), distances=(0.1, 3.5))
- pos = np.random.rand(2, 23)
+ pos = ift.random.current_rng().random((2, 23))
pos[0, :] *= 0.9
pos[1, :] *= 7*3.5
_check_repr(ift.LinearInterpolator(sp, pos))
@@ -206,11 +206,12 @@ def testOuter(fdomain, domain):
@pmp('sp', _h_spaces + _p_spaces + _pow_spaces)
@pmp('seed', [12, 3])
def testValueInserter(sp, seed):
- np.random.seed(seed)
+ ift.random.push_sseq_from_seed(seed)
ind = []
for ss in sp.shape:
if ss == 1:
ind.append(0)
else:
- ind.append(np.random.randint(0, ss - 1))
+ ind.append(int(ift.random.current_rng().integers(0, ss - 1)))
_check_repr(ift.ValueInserter(sp, ind))
+ ift.random.pop_sseq()
diff --git a/test/test_operators/test_simplification.py b/test/test_operators/test_simplification.py
index ade3304f23767dce4ecd12abb286a780a5ec7894..94c9be1979b4fa0c3ea1c705e6783eee44658b77 100644
--- a/test/test_operators/test_simplification.py
+++ b/test/test_operators/test_simplification.py
@@ -18,6 +18,7 @@
from numpy.testing import assert_allclose, assert_equal
import nifty6 as ift
+from ..common import setup_function, teardown_function
def test_simplification():
diff --git a/test/test_operators/test_smoothing_operator.py b/test/test_operators/test_smoothing_operator.py
index 4aab68411eb68297cf646c26df2d1be4313890ab..9c92c758fc48be0b93ad0550d64d4fca790ab2ef 100644
--- a/test/test_operators/test_smoothing_operator.py
+++ b/test/test_operators/test_smoothing_operator.py
@@ -21,7 +21,7 @@ from numpy.testing import assert_allclose
import nifty6 as ift
-from ..common import list2fixture
+from ..common import list2fixture, setup_function, teardown_function
def _get_rtol(tp):
diff --git a/test/test_operators/test_value_inserter.py b/test/test_operators/test_value_inserter.py
index d420585b357e0bf79ab1440125b24c9ebea77160..b64daee429446cbffabdc886bad30ffef3089209 100644
--- a/test/test_operators/test_value_inserter.py
+++ b/test/test_operators/test_value_inserter.py
@@ -20,6 +20,7 @@ import pytest
from numpy.testing import assert_
import nifty6 as ift
+from ..common import setup_function, teardown_function
@pytest.mark.parametrize('sp', [
@@ -31,10 +32,11 @@ import nifty6 as ift
])
@pytest.mark.parametrize('seed', [13, 2])
def test_value_inserter(sp, seed):
- np.random.seed(seed)
- ind = tuple([np.random.randint(0, ss - 1) for ss in sp.shape])
+ ift.random.push_sseq_from_seed(seed)
+ ind = tuple([int(ift.random.current_rng().integers(0, ss - 1)) for ss in sp.shape])
op = ift.ValueInserter(sp, ind)
f = ift.from_random('normal', op.domain)
+ ift.random.pop_sseq()
inp = f.val
ret = op(f).val
assert_(ret[ind] == inp)
diff --git a/test/test_plot.py b/test/test_plot.py
index 6298d90496aa45b3754ff3d9376b0999a7c55846..b77a3910437b6592f1cf6abf9c132f5e63a7542a 100644
--- a/test/test_plot.py
+++ b/test/test_plot.py
@@ -18,6 +18,7 @@
import numpy as np
import nifty6 as ift
+from .common import setup_function, teardown_function
def test_plots():
@@ -29,12 +30,12 @@ def test_plots():
fft = ift.FFTOperator(rg_space2)
- field_rg1_1 = ift.TMP_fld(rg_space1, np.random.randn(100))
- field_rg1_2 = ift.TMP_fld(rg_space1, np.random.randn(100))
+ field_rg1_1 = ift.TMP_fld(rg_space1, ift.random.current_rng().standard_normal(100))
+ field_rg1_2 = ift.TMP_fld(rg_space1, ift.random.current_rng().standard_normal(100))
field_rg2 = ift.TMP_fld(
- rg_space2, np.random.randn(80*60).reshape((80, 60)))
- field_hp = ift.TMP_fld(hp_space, np.random.randn(12*64**2))
- field_gl = ift.TMP_fld(gl_space, np.random.randn(32640))
+ rg_space2, ift.random.current_rng().standard_normal((80,60)))
+ field_hp = ift.TMP_fld(hp_space, ift.random.current_rng().standard_normal(12*64**2))
+ field_gl = ift.TMP_fld(gl_space, ift.random.current_rng().standard_normal(32640))
field_ps = ift.power_analyze(fft.times(field_rg2))
plot = ift.Plot()
diff --git a/test/test_random.py b/test/test_random.py
new file mode 100644
index 0000000000000000000000000000000000000000..842d1ca7e1b2b10ac436be9a03afff91adb65f0c
--- /dev/null
+++ b/test/test_random.py
@@ -0,0 +1,83 @@
+# 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. If not, see .
+#
+# Copyright(C) 2020 Max-Planck-Society
+#
+# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
+
+import numpy as np
+
+import nifty6 as ift
+
+
+def test_rand1():
+ ift.random.push_sseq_from_seed(31)
+ a = ift.random.current_rng().integers(0,1000000000)
+ ift.random.pop_sseq()
+ ift.random.push_sseq_from_seed(31)
+ b = ift.random.current_rng().integers(0,1000000000)
+ np.testing.assert_equal(a,b)
+
+
+def test_rand2():
+ ift.random.push_sseq_from_seed(31)
+ sseq = ift.random.spawn_sseq(10)
+ ift.random.push_sseq(sseq[2])
+ a = ift.random.current_rng().integers(0,1000000000)
+ ift.random.pop_sseq()
+ ift.random.push_sseq(sseq[2])
+ b = ift.random.current_rng().integers(0,1000000000)
+ ift.random.pop_sseq()
+ np.testing.assert_equal(a,b)
+ ift.random.pop_sseq()
+
+
+def test_rand3():
+ ift.random.push_sseq_from_seed(31)
+ sseq = ift.random.spawn_sseq(10)
+ ift.random.push_sseq(sseq[2])
+ a = ift.random.current_rng().integers(0,1000000000)
+ ift.random.pop_sseq()
+ ift.random.pop_sseq()
+ ift.random.push_sseq_from_seed(31)
+ sseq = ift.random.spawn_sseq(1)
+ sseq = ift.random.spawn_sseq(1)
+ sseq = ift.random.spawn_sseq(1)
+ ift.random.push_sseq(sseq[0])
+ b = ift.random.current_rng().integers(0,1000000000)
+ ift.random.pop_sseq()
+ np.testing.assert_equal(a,b)
+ ift.random.pop_sseq()
+
+
+def test_rand4():
+ ift.random.push_sseq_from_seed(31)
+ a = ift.random.current_rng().integers(0,1000000000)
+ ift.random.push_sseq_from_seed(31)
+ b = ift.random.current_rng().integers(0,1000000000)
+ ift.random.pop_sseq()
+ ift.random.pop_sseq()
+ np.testing.assert_equal(a,b)
+
+
+def test_rand5():
+ ift.random.push_sseq_from_seed(31)
+ a = ift.random.current_rng().integers(0,1000000000)
+ ift.random.push_sseq_from_seed(31)
+ b = ift.random.current_rng().integers(0,1000000000)
+ c = ift.random.current_rng().integers(0,1000000000)
+ ift.random.pop_sseq()
+ d = ift.random.current_rng().integers(0,1000000000)
+ ift.random.pop_sseq()
+ np.testing.assert_equal(a,b)
+ np.testing.assert_equal(c,d)
diff --git a/test/test_spaces/test_gl_space.py b/test/test_spaces/test_gl_space.py
index 76a07cad1eb2c6078142b79d03fff90718e805e4..b5ac1eec0559b6860a90d50c3b3a80746438c64c 100644
--- a/test/test_spaces/test_gl_space.py
+++ b/test/test_spaces/test_gl_space.py
@@ -23,6 +23,7 @@ from numpy.testing import (assert_, assert_almost_equal, assert_equal,
assert_raises)
from nifty6 import GLSpace
+from ..common import setup_function, teardown_function
pmp = pytest.mark.parametrize
@@ -41,7 +42,6 @@ CONSTRUCTOR_CONFIGS = [[
def get_dvol_configs():
- np.random.seed(42)
wgt = [2.0943951, 2.0943951]
# for GLSpace(nlat=2, nlon=3)
dvol_0 = np.array(
diff --git a/test/test_spaces/test_hp_space.py b/test/test_spaces/test_hp_space.py
index f0b4f5d17deba968075e1448f3aa98bb57b07c15..363d815e7d168691c6ae2a37d3a7c446533d6745 100644
--- a/test/test_spaces/test_hp_space.py
+++ b/test/test_spaces/test_hp_space.py
@@ -21,6 +21,7 @@ from numpy.testing import (assert_, assert_almost_equal, assert_equal,
assert_raises)
from nifty6 import HPSpace
+from ..common import setup_function, teardown_function
pmp = pytest.mark.parametrize
# [nside, expected]
diff --git a/test/test_spaces/test_interface.py b/test/test_spaces/test_interface.py
index 3e23f6ee99f8e556212666158290b20fdfd42568..a6d93ab9b58fea0e658543e3d6fef8d88429504b 100644
--- a/test/test_spaces/test_interface.py
+++ b/test/test_spaces/test_interface.py
@@ -21,6 +21,7 @@ import pytest
from numpy.testing import assert_
import nifty6 as ift
+from ..common import setup_function, teardown_function
pmp = pytest.mark.parametrize
diff --git a/test/test_spaces/test_lm_space.py b/test/test_spaces/test_lm_space.py
index 9cf2f79da47d4fab68ef3c0e691d598457410e63..1c04a27b47dbec1a346733be81e5a379a2529296 100644
--- a/test/test_spaces/test_lm_space.py
+++ b/test/test_spaces/test_lm_space.py
@@ -20,6 +20,7 @@ import pytest
from numpy.testing import assert_, assert_allclose, assert_equal, assert_raises
import nifty6 as ift
+from ..common import setup_function, teardown_function
pmp = pytest.mark.parametrize
# [lmax, expected]
diff --git a/test/test_spaces/test_power_space.py b/test/test_spaces/test_power_space.py
index 0c526843c3d65052aa0fa869212c05382229341c..393fc29509a82fd0b82b06ef99cb359871fcf48d 100644
--- a/test/test_spaces/test_power_space.py
+++ b/test/test_spaces/test_power_space.py
@@ -22,6 +22,7 @@ import pytest
from numpy.testing import assert_, assert_allclose, assert_equal, assert_raises
import nifty6 as ift
+from ..common import setup_function, teardown_function
pmp = pytest.mark.parametrize
diff --git a/test/test_spaces/test_rg_space.py b/test/test_spaces/test_rg_space.py
index 1cb535c6ba30ef51aab8a3a1722aca0e190ed1ed..e95c5d8b9df473a3592d3bda311f77e2a75b8f92 100644
--- a/test/test_spaces/test_rg_space.py
+++ b/test/test_spaces/test_rg_space.py
@@ -20,6 +20,7 @@ import pytest
from numpy.testing import assert_, assert_allclose, assert_equal
import nifty6 as ift
+from ..common import setup_function, teardown_function
pmp = pytest.mark.parametrize
# [shape, distances, harmonic, expected]
@@ -66,7 +67,6 @@ def get_k_length_array_configs():
def get_dvol_configs():
- np.random.seed(42)
return [[(11, 11), None, False, 1], [(11, 11), None, False, 1],
[(11, 11), (1.3, 1.3), False, 1], [(11, 11), (1.3, 1.3), False,
1], [(11, 11), None, True, 1],
diff --git a/test/test_sugar.py b/test/test_sugar.py
index a572c5113784d38885e68f6706a958c5542f4807..0318aef67178760facea7cdb22672fbfe1003f42 100644
--- a/test/test_sugar.py
+++ b/test/test_sugar.py
@@ -19,6 +19,7 @@ import numpy as np
from numpy.testing import assert_equal
import nifty6 as ift
+from .common import setup_function, teardown_function
def test_get_signal_variance():
@@ -52,7 +53,6 @@ def test_exec_time():
def test_calc_pos():
- np.random.seed(42)
dom = ift.RGSpace(12, harmonic=True)
op = ift.HarmonicTransformOperator(dom).exp()
fld = op(0.1*ift.from_random('normal', op.domain))