Commit 739bae57 authored by Philipp Arras's avatar Philipp Arras

Migrate to pytest

parent 4c0bd584
......@@ -9,7 +9,7 @@ RUN apt-get update && apt-get install -y \
# Documentation build dependencies
python3-sphinx python3-sphinx-rtd-theme python3-numpydoc \
# Testing dependencies
python3-coverage python3-parameterized python3-pytest python3-pytest-cov \
python3-coverage python3-pytest python3-pytest-cov \
# Optional NIFTy dependencies
openmpi-bin libopenmpi-dev python3-mpi4py \
# Packages needed for NIFTy
......
......@@ -15,20 +15,12 @@
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
from builtins import str
import pytest
import numpy as np
from parameterized import parameterized
np.seterr(all='raise', under='ignore')
def list2fixture(lst):
@pytest.fixture(params=lst)
def myfixture(request):
return request.param
def _custom_name_func(testcase_func, param_num, param):
return "{}_{}".format(
testcase_func.__name__,
parameterized.to_safe_name("_".join(str(x) for x in param.args)),
)
def expand(*args, **kwargs):
return parameterized.expand(*args, func=_custom_name_func, **kwargs)
return myfixture
# 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 <http://www.gnu.org/licenses/>.
#
# Copyright(C) 2013-2019 Max-Planck-Society
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
import unittest
from itertools import product
from test.common import expand
import nifty5 as ift
import numpy as np
class Energy_Tests(unittest.TestCase):
def make_model(self, **kwargs):
np.random.seed(kwargs['seed'])
S = ift.ScalingOperator(1., kwargs['space'])
s = S.draw_sample()
return ift.MultiField.from_dict({kwargs['space_key']: s})
@expand(product(
[ift.GLSpace(15),
ift.RGSpace(64, distances=.789),
ift.RGSpace([32, 32], distances=.789)],
[4, 78, 23]
))
def testGaussian(self, space, seed):
model = self.make_model(
space_key='s1', space=space, seed=seed)['s1']
energy = ift.GaussianEnergy(domain=space)
ift.extra.check_value_gradient_consistency(energy, model)
# @expand(product(
# [ift.GLSpace(15),
# ift.RGSpace(64, distances=.789),
# ift.RGSpace([32, 32], distances=.789)],
# [4, 78, 23]
# ))
# def testQuadratic(self, type1, space, seed):
# np.random.seed(seed)
# S = ift.ScalingOperator(1., space)
# s = [S.draw_sample() for _ in range(3)]
# energy = ift.QuadraticEnergy(s[0], ift.makeOp(s[1]), s[2])
# ift.extra.check_value_gradient_consistency(energy)
@expand(
product([
ift.GLSpace(15),
ift.RGSpace(64, distances=.789),
ift.RGSpace([32, 32], distances=.789)
], [4, 78, 23]))
def testInverseGammaLikelihood(self, space, seed):
model = self.make_model(space_key='s1', space=space, seed=seed)['s1']
model = model.exp()
d = np.random.normal(10, size=space.shape)**2
d = ift.Field.from_global_data(space, d)
energy = ift.InverseGammaLikelihood(d)
ift.extra.check_value_gradient_consistency(energy, model, tol=1e-7)
@expand(product(
[ift.GLSpace(15),
ift.RGSpace(64, distances=.789),
ift.RGSpace([32, 32], distances=.789)],
[4, 78, 23]
))
def testPoissonian(self, space, seed):
model = self.make_model(
space_key='s1', space=space, seed=seed)['s1']
model = model.exp()
d = np.random.poisson(120, size=space.shape)
d = ift.Field.from_global_data(space, d)
energy = ift.PoissonianEnergy(d)
ift.extra.check_value_gradient_consistency(energy, model, tol=1e-7)
@expand(product(
[ift.GLSpace(15),
ift.RGSpace(64, distances=.789),
ift.RGSpace([32, 32], distances=.789)],
[4, 78, 23]
))
def testHamiltonian_and_KL(self, space, seed):
model = self.make_model(
space_key='s1', space=space, seed=seed)['s1']
model = model.exp()
lh = ift.GaussianEnergy(domain=space)
hamiltonian = ift.Hamiltonian(lh)
ift.extra.check_value_gradient_consistency(hamiltonian, model)
S = ift.ScalingOperator(1., space)
samps = [S.draw_sample() for i in range(3)]
kl = ift.SampledKullbachLeiblerDivergence(hamiltonian, samps)
ift.extra.check_value_gradient_consistency(kl, model)
@expand(product(
[ift.GLSpace(15),
ift.RGSpace(64, distances=.789),
ift.RGSpace([32, 32], distances=.789)],
[4, 78, 23]
))
def testBernoulli(self, space, seed):
model = self.make_model(
space_key='s1', space=space, seed=seed)['s1']
model = model.positive_tanh()
d = np.random.binomial(1, 0.1, size=space.shape)
d = ift.Field.from_global_data(space, d)
energy = ift.BernoulliEnergy(d)
ift.extra.check_value_gradient_consistency(energy, model, tol=1e-6)
# 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 <http://www.gnu.org/licenses/>.
#
# Copyright(C) 2013-2019 Max-Planck-Society
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
import numpy as np
import pytest
import nifty5 as ift
from itertools import product
# Currently it is not possible to parametrize fixtures. But this will
# hopefully be fixed in the future.
# https://docs.pytest.org/en/latest/proposals/parametrize_with_fixtures.html
SPACES = [
ift.GLSpace(15),
ift.RGSpace(64, distances=.789),
ift.RGSpace([32, 32], distances=.789)
]
SEEDS = [4, 78, 23]
PARAMS = product(SEEDS, SPACES)
@pytest.fixture(params=PARAMS)
def field(request):
np.random.seed(request.param[0])
S = ift.ScalingOperator(1., request.param[1])
s = S.draw_sample()
return ift.MultiField.from_dict({'s1': s})['s1']
def test_gaussian(field):
energy = ift.GaussianEnergy(domain=field.domain)
ift.extra.check_value_gradient_consistency(energy, field)
def test_inverse_gamma(field):
field = field.exp()
space = field.domain
d = np.random.normal(10, size=space.shape)**2
d = ift.Field.from_global_data(space, d)
energy = ift.InverseGammaLikelihood(d)
ift.extra.check_value_gradient_consistency(energy, field, tol=1e-7)
def testPoissonian(field):
field = field.exp()
space = field.domain
d = np.random.poisson(120, size=space.shape)
d = ift.Field.from_global_data(space, d)
energy = ift.PoissonianEnergy(d)
ift.extra.check_value_gradient_consistency(energy, field, tol=1e-7)
def test_hamiltonian_and_KL(field):
field = field.exp()
space = field.domain
lh = ift.GaussianEnergy(domain=space)
hamiltonian = ift.Hamiltonian(lh)
ift.extra.check_value_gradient_consistency(hamiltonian, field)
S = ift.ScalingOperator(1., space)
samps = [S.draw_sample() for i in range(3)]
kl = ift.SampledKullbachLeiblerDivergence(hamiltonian, samps)
ift.extra.check_value_gradient_consistency(kl, field)
def test_bernoulli(field):
field = field.positive_tanh()
space = field.domain
d = np.random.binomial(1, 0.1, size=space.shape)
d = ift.Field.from_global_data(space, d)
energy = ift.BernoulliEnergy(d)
ift.extra.check_value_gradient_consistency(energy, field, tol=1e-6)
This diff is collapsed.
......@@ -15,61 +15,67 @@
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
import unittest
from itertools import product
from test.common import expand
import numpy as np
import pytest
import nifty5 as ift
import numpy as np
def _flat_PS(k):
return np.ones_like(k)
class Energy_Tests(unittest.TestCase):
@expand(product([ift.GLSpace(15),
ift.RGSpace(64, distances=.789),
ift.RGSpace([32, 32], distances=.789)],
["tanh", "exp", ""],
[1, 1e-2, 1e2],
[4, 78, 23]))
def testGaussianEnergy(self, space, nonlinearity, noise, seed):
np.random.seed(seed)
dim = len(space.shape)
hspace = space.get_default_codomain()
ht = ift.HarmonicTransformOperator(hspace, target=space)
binbounds = ift.PowerSpace.useful_binbounds(hspace, logarithmic=False)
pspace = ift.PowerSpace(hspace, binbounds=binbounds)
Dist = ift.PowerDistributor(target=hspace, power_space=pspace)
xi0 = ift.Field.from_random(domain=hspace, random_type='normal')
xi0_var = ift.Linearization.make_var(xi0)
pmp = pytest.mark.parametrize
def pspec(k): return 1 / (1 + k**2)**dim
pspec = ift.PS_field(pspace, pspec)
A = Dist(ift.sqrt(pspec))
N = ift.ScalingOperator(noise, space)
n = N.draw_sample()
s = ht(ift.makeOp(A)(xi0_var))
R = ift.ScalingOperator(10., space)
def d_model():
if nonlinearity == "":
return R(ht(ift.makeOp(A)))
else:
tmp = ht(ift.makeOp(A))
nonlin = getattr(tmp, nonlinearity)()
return R(nonlin)
@pmp('space', [
ift.GLSpace(15),
ift.RGSpace(64, distances=.789),
ift.RGSpace([32, 32], distances=.789)
])
@pmp('nonlinearity', ["tanh", "exp", ""])
@pmp('noise', [1, 1e-2, 1e2])
@pmp('seed', [4, 78, 23])
def test_gaussian_energy(space, nonlinearity, noise, seed):
np.random.seed(seed)
dim = len(space.shape)
hspace = space.get_default_codomain()
ht = ift.HarmonicTransformOperator(hspace, target=space)
binbounds = ift.PowerSpace.useful_binbounds(hspace, logarithmic=False)
pspace = ift.PowerSpace(hspace, binbounds=binbounds)
Dist = ift.PowerDistributor(target=hspace, power_space=pspace)
xi0 = ift.Field.from_random(domain=hspace, random_type='normal')
# FIXME Needed?
xi0_var = ift.Linearization.make_var(xi0)
d = d_model()(xi0) + n
def pspec(k):
return 1/(1 + k**2)**dim
if noise == 1:
N = None
pspec = ift.PS_field(pspace, pspec)
A = Dist(ift.sqrt(pspec))
N = ift.ScalingOperator(noise, space)
n = N.draw_sample()
# FIXME Needed?
s = ht(ift.makeOp(A)(xi0_var))
R = ift.ScalingOperator(10., space)
energy = ift.GaussianEnergy(d, N)(d_model())
def d_model():
if nonlinearity == "":
ift.extra.check_value_gradient_metric_consistency(
energy, xi0, ntries=10)
return R(ht(ift.makeOp(A)))
else:
ift.extra.check_value_gradient_consistency(
energy, xi0, ntries=10, tol=5e-8)
tmp = ht(ift.makeOp(A))
nonlin = getattr(tmp, nonlinearity)()
return R(nonlin)
d = d_model()(xi0) + n
if noise == 1:
N = None
energy = ift.GaussianEnergy(d, N)(d_model())
if nonlinearity == "":
ift.extra.check_value_gradient_metric_consistency(
energy, xi0, ntries=10)
else:
ift.extra.check_value_gradient_consistency(
energy, xi0, ntries=10, tol=5e-8)
# 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 <http://www.gnu.org/licenses/>.
#
# Copyright(C) 2013-2019 Max-Planck-Society
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
import unittest
from itertools import product
from test.common import expand
import nifty5 as ift
import numpy as np
from unittest import SkipTest
from numpy.testing import assert_allclose, assert_equal
IC = ift.GradientNormController(tol_abs_gradnorm=1e-5, iteration_limit=1000)
spaces = [ift.RGSpace([1024], distances=0.123), ift.HPSpace(32)]
minimizers = ['ift.VL_BFGS(IC)',
'ift.NonlinearCG(IC, "Polak-Ribiere")',
# 'ift.NonlinearCG(IC, "Hestenes-Stiefel"),
'ift.NonlinearCG(IC, "Fletcher-Reeves")',
'ift.NonlinearCG(IC, "5.49")',
'ift.L_BFGS_B(ftol=1e-10, gtol=1e-5, maxiter=1000)',
'ift.L_BFGS(IC)',
'ift.NewtonCG(IC)']
newton_minimizers = ['ift.RelaxedNewton(IC)']
quadratic_only_minimizers = ['ift.ConjugateGradient(IC)',
'ift.ScipyCG(tol=1e-5, maxiter=300)']
slow_minimizers = ['ift.SteepestDescent(IC)']
class Test_Minimizers(unittest.TestCase):
@expand(product(minimizers + newton_minimizers +
quadratic_only_minimizers + slow_minimizers, spaces))
def test_quadratic_minimization(self, minimizer, space):
np.random.seed(42)
starting_point = ift.Field.from_random('normal', domain=space)*10
covariance_diagonal = ift.Field.from_random(
'uniform', domain=space) + 0.5
covariance = ift.DiagonalOperator(covariance_diagonal)
required_result = ift.full(space, 1.)
try:
minimizer = eval(minimizer)
energy = ift.QuadraticEnergy(A=covariance, b=required_result,
position=starting_point)
(energy, convergence) = minimizer(energy)
except NotImplementedError:
raise SkipTest
assert_equal(convergence, IC.CONVERGED)
assert_allclose(energy.position.local_data,
1./covariance_diagonal.local_data,
rtol=1e-3, atol=1e-3)
@expand(product(minimizers+newton_minimizers))
def test_rosenbrock(self, minimizer):
try:
from scipy.optimize import rosen, rosen_der, rosen_hess_prod
except ImportError:
raise SkipTest
np.random.seed(42)
space = ift.DomainTuple.make(ift.UnstructuredDomain((2,)))
starting_point = ift.Field.from_random('normal', domain=space)*10
class RBEnergy(ift.Energy):
def __init__(self, position):
super(RBEnergy, self).__init__(position)
@property
def value(self):
return rosen(self._position.to_global_data_rw())
@property
def gradient(self):
inp = self._position.to_global_data_rw()
out = ift.Field.from_global_data(space, rosen_der(inp))
return out
@property
def metric(self):
class RBCurv(ift.EndomorphicOperator):
def __init__(self, loc):
self._loc = loc.to_global_data_rw()
self._capability = self.TIMES
self._domain = space
def apply(self, x, mode):
self._check_input(x, mode)
inp = x.to_global_data_rw()
out = ift.Field.from_global_data(
space, rosen_hess_prod(self._loc.copy(), inp))
return out
t1 = ift.GradientNormController(tol_abs_gradnorm=1e-5,
iteration_limit=1000)
return ift.InversionEnabler(RBCurv(self._position), t1)
def apply_metric(self, x):
inp = x.to_global_data_rw()
pos = self._position.to_global_data_rw()
return ift.Field.from_global_data(
space, rosen_hess_prod(pos, inp))
try:
minimizer = eval(minimizer)
energy = RBEnergy(position=starting_point)
(energy, convergence) = minimizer(energy)
except NotImplementedError:
raise SkipTest
assert_equal(convergence, IC.CONVERGED)
assert_allclose(energy.position.local_data, 1.,
rtol=1e-3, atol=1e-3)
@expand(product(minimizers+slow_minimizers))
def test_gauss(self, minimizer):
space = ift.UnstructuredDomain((1,))
starting_point = ift.Field.full(space, 3.)
class ExpEnergy(ift.Energy):
def __init__(self, position):
super(ExpEnergy, self).__init__(position)
@property
def value(self):
x = self.position.to_global_data()[0]
return -np.exp(-(x**2))
@property
def gradient(self):
x = self.position.to_global_data()[0]
return ift.Field.full(self.position.domain,
2*x*np.exp(-(x**2)))
def apply_metric(self, x):
p = self.position.to_global_data()[0]
v = (2 - 4*p*p)*np.exp(-p**2)
return ift.DiagonalOperator(
ift.Field.full(self.position.domain, v))(x)
try:
minimizer = eval(minimizer)
energy = ExpEnergy(position=starting_point)
(energy, convergence) = minimizer(energy)
except NotImplementedError:
raise SkipTest
assert_equal(convergence, IC.CONVERGED)
assert_allclose(energy.position.local_data, 0.,
atol=1e-3)
@expand(product(minimizers+newton_minimizers+slow_minimizers))
def test_cosh(self, minimizer):
space = ift.UnstructuredDomain((1,))
starting_point = ift.Field.full(space, 3.)
class CoshEnergy(ift.Energy):
def __init__(self, position):
super(CoshEnergy, self).__init__(position)
@property
def value(self):
x = self.position.to_global_data()[0]
return np.cosh(x)
@property
def gradient(self):
x = self.position.to_global_data()[0]
return ift.Field.full(self.position.domain, np.sinh(x))
@property
def metric(self):
x = self.position.to_global_data()[0]
v = np.cosh(x)
return ift.DiagonalOperator(
ift.Field.full(self.position.domain, v))
def apply_metric(self, x):
p = self.position.to_global_data()[0]
v = np.cosh(p)
return ift.DiagonalOperator(
ift.Field.full(self.position.domain, v))(x)
try:
minimizer = eval(minimizer)
energy = CoshEnergy(position=starting_point)
(energy, convergence) = minimizer(energy)
except NotImplementedError:
raise SkipTest
assert_equal(convergence, IC.CONVERGED)
assert_allclose(energy.position.local_data, 0., atol=1e-3)
# 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 <http://www.gnu.org/licenses/>.
#
# Copyright(C) 2013-2019 Max-Planck-Society
#
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
from unittest import SkipTest
import numpy as np
import pytest
from numpy.testing import assert_allclose, assert_equal
import nifty5 as ift
pmp = pytest.mark.parametrize
IC = ift.GradientNormController(tol_abs_gradnorm=1e-5, iteration_limit=1000)
spaces = [ift.RGSpace([1024], distances=0.123), ift.HPSpace(32)]
minimizers = [
'ift.VL_BFGS(IC)',
'ift.NonlinearCG(IC, "Polak-Ribiere")',
# 'ift.NonlinearCG(IC, "Hestenes-Stiefel"),
'ift.NonlinearCG(IC, "Fletcher-Reeves")',
'ift.NonlinearCG(IC, "5.49")',
'ift.L_BFGS_B(ftol=1e-10, gtol=1e-5, maxiter=1000)',
'ift.L_BFGS(IC)',
'ift.NewtonCG(IC)'
]
newton_minimizers = ['ift.RelaxedNewton(IC)']
quadratic_only_minimizers = [
'ift.ConjugateGradient(IC)', 'ift.ScipyCG(tol=1e-5, maxiter=300)'
]
slow_minimizers = ['ift.SteepestDescent(IC)']