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

Migrate to pytest

parent 4c0bd584
...@@ -9,7 +9,7 @@ RUN apt-get update && apt-get install -y \ ...@@ -9,7 +9,7 @@ RUN apt-get update && apt-get install -y \
# Documentation build dependencies # Documentation build dependencies
python3-sphinx python3-sphinx-rtd-theme python3-numpydoc \ python3-sphinx python3-sphinx-rtd-theme python3-numpydoc \
# Testing dependencies # Testing dependencies
python3-coverage python3-parameterized python3-pytest python3-pytest-cov \ python3-coverage python3-pytest python3-pytest-cov \
# Optional NIFTy dependencies # Optional NIFTy dependencies
openmpi-bin libopenmpi-dev python3-mpi4py \ openmpi-bin libopenmpi-dev python3-mpi4py \
# Packages needed for NIFTy # Packages needed for NIFTy
......
...@@ -15,20 +15,12 @@ ...@@ -15,20 +15,12 @@
# #
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik. # 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
return myfixture
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)
# 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)
...@@ -15,25 +15,22 @@ ...@@ -15,25 +15,22 @@
# #
# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik. # 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 import numpy as np
import pytest
from numpy.testing import assert_allclose, assert_equal, assert_raises from numpy.testing import assert_allclose, assert_equal, assert_raises
import nifty5 as ift
pmp = pytest.mark.parametrize
SPACES = [ift.RGSpace((4,)), ift.RGSpace((5))] SPACES = [ift.RGSpace((4,)), ift.RGSpace((5))]
SPACE_COMBINATIONS = [(), SPACES[0], SPACES[1], SPACES] SPACE_COMBINATIONS = [(), SPACES[0], SPACES[1], SPACES]
class Test_Interface(unittest.TestCase): @pmp('domain', SPACE_COMBINATIONS)
@expand(product(SPACE_COMBINATIONS, @pmp('attribute_desired_type',
[['domain', ift.DomainTuple], [['domain', ift.DomainTuple], ['val', ift.dobj.data_object],
['val', ift.dobj.data_object], ['shape', tuple], ['size', (np.int, np.int64)]])
['shape', tuple], def test_return_types(domain, attribute_desired_type):
['size', (np.int, np.int64)]]))
def test_return_types(self, domain, attribute_desired_type):
attribute = attribute_desired_type[0] attribute = attribute_desired_type[0]
desired_type = attribute_desired_type[1] desired_type = attribute_desired_type[1]
f = ift.Field.full(domain, 1.) f = ift.Field.full(domain, 1.)
...@@ -41,19 +38,19 @@ class Test_Interface(unittest.TestCase): ...@@ -41,19 +38,19 @@ class Test_Interface(unittest.TestCase):
def _spec1(k): def _spec1(k):
return 42/(1.+k)**2 return 42/(1. + k)**2
def _spec2(k): def _spec2(k):
return 42/(1.+k)**3 return 42/(1. + k)**3
class Test_Functionality(unittest.TestCase): @pmp('space1', [
@expand(product([ift.RGSpace((8,), harmonic=True), ift.RGSpace((8,), harmonic=True),
ift.RGSpace((8, 8), harmonic=True, distances=0.123)], ift.RGSpace((8, 8), harmonic=True, distances=0.123)
[ift.RGSpace((8,), harmonic=True), ])
ift.LMSpace(12)])) @pmp('space2', [ift.RGSpace((8,), harmonic=True), ift.LMSpace(12)])
def test_power_synthesize_analyze(self, space1, space2): def test_power_synthesize_analyze(space1, space2):
np.random.seed(11) np.random.seed(11)
p1 = ift.PowerSpace(space1) p1 = ift.PowerSpace(space1)
...@@ -73,19 +70,20 @@ class Test_Functionality(unittest.TestCase): ...@@ -73,19 +70,20 @@ class Test_Functionality(unittest.TestCase):
for ii in range(samples): for ii in range(samples):
sk = opfull.draw_sample() sk = opfull.draw_sample()
sp = ift.power_analyze(sk, spaces=(0, 1), sp = ift.power_analyze(sk, spaces=(0, 1), keep_phase_information=False)
keep_phase_information=False)
sc1.add(sp.sum(spaces=1)/fp2.sum()) sc1.add(sp.sum(spaces=1)/fp2.sum())
sc2.add(sp.sum(spaces=0)/fp1.sum()) sc2.add(sp.sum(spaces=0)/fp1.sum())
assert_allclose(sc1.mean.local_data, fp1.local_data, rtol=0.2) assert_allclose(sc1.mean.local_data, fp1.local_data, rtol=0.2)
assert_allclose(sc2.mean.local_data, fp2.local_data, rtol=0.2) assert_allclose(sc2.mean.local_data, fp2.local_data, rtol=0.2)
@expand(product([ift.RGSpace((8,), harmonic=True),
ift.RGSpace((8, 8), harmonic=True, distances=0.123)], @pmp('space1', [
[ift.RGSpace((8,), harmonic=True), ift.RGSpace((8,), harmonic=True),
ift.LMSpace(12)])) ift.RGSpace((8, 8), harmonic=True, distances=0.123)
def test_DiagonalOperator_power_analyze2(self, space1, space2): ])
@pmp('space2', [ift.RGSpace((8,), harmonic=True), ift.LMSpace(12)])
def test_DiagonalOperator_power_analyze2(space1, space2):
np.random.seed(11) np.random.seed(11)
fp1 = ift.PS_field(ift.PowerSpace(space1), _spec1) fp1 = ift.PS_field(ift.PowerSpace(space1), _spec1)
...@@ -101,18 +99,20 @@ class Test_Functionality(unittest.TestCase): ...@@ -101,18 +99,20 @@ class Test_Functionality(unittest.TestCase):
for ii in range(samples): for ii in range(samples):
sk = S_full.draw_sample() sk = S_full.draw_sample()
sp = ift.power_analyze(sk, spaces=(0, 1), sp = ift.power_analyze(sk, spaces=(0, 1), keep_phase_information=False)
keep_phase_information=False)
sc1.add(sp.sum(spaces=1)/fp2.sum()) sc1.add(sp.sum(spaces=1)/fp2.sum())
sc2.add(sp.sum(spaces=0)/fp1.sum()) sc2.add(sp.sum(spaces=0)/fp1.sum())
assert_allclose(sc1.mean.local_data, fp1.local_data, rtol=0.2) assert_allclose(sc1.mean.local_data, fp1.local_data, rtol=0.2)
assert_allclose(sc2.mean.local_data, fp2.local_data, rtol=0.2) assert_allclose(sc2.mean.local_data, fp2.local_data, rtol=0.2)
@expand(product([ift.RGSpace((8,), harmonic=True), (),
@pmp('space', [
ift.RGSpace((8,), harmonic=True), (),
ift.RGSpace((8, 8), harmonic=True, distances=0.123), ift.RGSpace((8, 8), harmonic=True, distances=0.123),
ift.RGSpace((2, 3, 7))])) ift.RGSpace((2, 3, 7))
def test_norm(self, space): ])
def test_norm(space):
f = ift.Field.from_random("normal", domain=space, dtype=np.complex128) f = ift.Field.from_random("normal", domain=space, dtype=np.complex128)
gd = f.to_global_data().reshape(-1) gd = f.to_global_data().reshape(-1)
assert_allclose(f.norm(), np.linalg.norm(gd)) assert_allclose(f.norm(), np.linalg.norm(gd))
...@@ -121,31 +121,39 @@ class Test_Functionality(unittest.TestCase): ...@@ -121,31 +121,39 @@ class Test_Functionality(unittest.TestCase):
assert_allclose(f.norm(3), np.linalg.norm(gd, ord=3)) assert_allclose(f.norm(3), np.linalg.norm(gd, ord=3))
assert_allclose(f.norm(np.inf), np.linalg.norm(gd, ord=np.inf)) assert_allclose(f.norm(np.inf), np.linalg.norm(gd, ord=np.inf))
def test_vdot(self):
def test_vdot(self):
s = ift.RGSpace((10,)) s = ift.RGSpace((10,))
f1 = ift.Field.from_random("normal", domain=s, dtype=np.complex128) f1 = ift.Field.from_random("normal", domain=s, dtype=np.complex128)
f2 = ift.Field.from_random("normal", domain=s, dtype=np.complex128) f2 = ift.Field.from_random("normal", domain=s, dtype=np.complex128)
assert_allclose(f1.vdot(f2), f1.vdot(f2, spaces=0)) assert_allclose(f1.vdot(f2), f1.vdot(f2, spaces=0))
assert_allclose(f1.vdot(f2), np.conj(f2.vdot(f1))) assert_allclose(f1.vdot(f2), np.conj(f2.vdot(f1)))
def test_vdot2(self):
def test_vdot2(self):
x1 = ift.RGSpace((200,)) x1 = ift.RGSpace((200,))
x2 = ift.RGSpace((150,)) x2 = ift.RGSpace((150,))
m = ift.Field.full((x1, x2), .5) m = ift.Field.full((x1, x2), .5)
res = m.vdot(m, spaces=1) res = m.vdot(m, spaces=1)
assert_allclose(res.local_data, 37.5) assert_allclose(res.local_data, 37.5)
def test_outer(self):
def test_outer(self):
x1 = ift.RGSpace((9,)) x1 = ift.RGSpace((9,))
x2 = ift.RGSpace((3,)) x2 = ift.RGSpace((3,))
m1 = ift.Field.full(x1, .5) m1 = ift.Field.full(x1, .5)
m2 = ift.Field.full(x2, 3.) m2 = ift.Field.full(x2, 3.)
res = m1.outer(m2) res = m1.outer(m2)
assert_allclose(res.to_global_data(), np.full((9, 3,), 1.5)) assert_allclose(res.to_global_data(), np.full((9, 3), 1.5))
def test_sum(self):
def test_sum(self):
x1 = ift.RGSpace((9,), distances=2.) x1 = ift.RGSpace((9,), distances=2.)
x2 = ift.RGSpace((2, 12,), distances=(0.3,)) x2 = ift.RGSpace(
(
2,
12,
), distances=(0.3,))
m1 = ift.Field.from_global_data(ift.makeDomain(x1), np.arange(9)) m1 = ift.Field.from_global_data(ift.makeDomain(x1), np.arange(9))
m2 = ift.Field.full(ift.makeDomain((x1, x2)), 0.45) m2 = ift.Field.full(ift.makeDomain((x1, x2)), 0.45)
res1 = m1.sum() res1 = m1.sum()
...@@ -153,9 +161,10 @@ class Test_Functionality(unittest.TestCase): ...@@ -153,9 +161,10 @@ class Test_Functionality(unittest.TestCase):
assert_allclose(res1, 36) assert_allclose(res1, 36)
assert_allclose(res2.to_global_data(), np.full(9, 2*12*0.45)) assert_allclose(res2.to_global_data(), np.full(9, 2*12*0.45))
def test_integrate(self):
def test_integrate(self):
x1 = ift.RGSpace((9,), distances=2.) x1 = ift.RGSpace((9,), distances=2.)
x2 = ift.RGSpace((2, 12,), distances=(0.3,)) x2 = ift.RGSpace((2, 12), distances=(0.3,))
m1 = ift.Field.from_global_data(ift.makeDomain(x1), np.arange(9)) m1 = ift.Field.from_global_data(ift.makeDomain(x1), np.arange(9))
m2 = ift.Field.full(ift.makeDomain((x1, x2)), 0.45) m2 = ift.Field.full(ift.makeDomain((x1, x2)), 0.45)
res1 = m1.integrate() res1 = m1.integrate()
...@@ -163,41 +172,46 @@ class Test_Functionality(unittest.TestCase): ...@@ -163,41 +172,46 @@ class Test_Functionality(unittest.TestCase):
assert_allclose(res1, 36*2) assert_allclose(res1, 36*2)
assert_allclose(res2.to_global_data(), np.full(9, 2*12*0.45*0.3**2)) assert_allclose(res2.to_global_data(), np.full(9, 2*12*0.45*0.3**2))
def test_dataconv(self):
def test_dataconv(self):
s1 = ift.RGSpace((10,)) s1 = ift.RGSpace((10,))
ld = np.arange(ift.dobj.local_shape(s1.shape)[0]) ld = np.arange(ift.dobj.local_shape(s1.shape)[0])
gd = np.arange(s1.shape[0]) gd = np.arange(s1.shape[0])
assert_equal(ld, ift.from_local_data(s1, ld).local_data) assert_equal(ld, ift.from_local_data(s1, ld).local_data)
assert_equal(gd, ift.from_global_data(s1, gd).to_global_data()) assert_equal(gd, ift.from_global_data(s1, gd).to_global_data())
def test_cast_domain(self):
def test_cast_domain(self):
s1 = ift.RGSpace((10,)) s1 = ift.RGSpace((10,))
s2 = ift.RGSpace((10,), distances=20.) s2 = ift.RGSpace((10,), distances=20.)
d = np.arange(s1.shape[0]) d = np.arange(s1.shape[0])
d2 = ift.from_global_data(s1, d).cast_domain(s2).to_global_data() d2 = ift.from_global_data(s1, d).cast_domain(s2).to_global_data()
assert_equal(d, d2) assert_equal(d, d2)
def test_empty_domain(self):
def test_empty_domain(self):
f = ift.Field.full((), 5) f = ift.Field.full((), 5)
assert_equal(f.local_data, 5) assert_equal(f.local_data, 5)
f = ift.Field.full(None, 5) f = ift.Field.full(None, 5)
assert_equal(f.local_data, 5) assert_equal(f.local_data, 5)
def test_trivialities(self):
def test_trivialities(self):
s1 = ift.RGSpace((10,)) s1 = ift.RGSpace((10,))
f1 = ift.Field.full(s1, 27) f1 = ift.Field.full(s1, 27)
assert_equal(f1.local_data, f1.real.local_data) assert_equal(f1.local_data, f1.real.local_data)
f1 = ift.Field.full(s1, 27.+3j) f1 = ift.Field.full(s1, 27. + 3j)
assert_equal(f1.real.local_data, 27.) assert_equal(f1.real.local_data, 27.)
assert_equal(f1.imag.local_data, 3.) assert_equal(f1.imag.local_data, 3.)
assert_equal(f1.local_data, +f1.local_data) assert_equal(f1.local_data, +f1.local_data)
assert_equal(f1.sum(), f1.sum(0)) assert_equal(f1.sum(), f1.sum(0))
f1 = ift.from_global_data(s1, np.arange(10)) f1 = ift.from_global_data(s1, np.arange(10))
# assert_equal(f1.min(), 0) # assert_equal(f1.min(), 0)
# assert_equal(f1.max(), 9) # assert_equal(f1.max(), 9)
assert_equal(f1.prod(), 0) assert_equal(f1.prod(), 0)
def test_weight(self):
def test_weight(self):
s1 = ift.RGSpace((10,)) s1 = ift.RGSpace((10,))
f = ift.Field.full(s1, 10.) f = ift.Field.full(s1, 10.)
f2 = f.weight(1) f2 = f.weight(1)
...@@ -214,9 +228,10 @@ class Test_Functionality(unittest.TestCase): ...@@ -214,9 +228,10 @@ class Test_Functionality(unittest.TestCase):
assert_equal(f.scalar_weight(0), None) assert_equal(f.scalar_weight(0), None)
assert_equal(f.scalar_weight((0,)), None) assert_equal(f.scalar_weight((0,)), None)
@expand(product([ift.RGSpace(10), ift.GLSpace(10)],
[np.float64, np.complex128])) @pmp('dom', [ift.RGSpace(10), ift.GLSpace(10)])
def test_reduction(self, dom, dt): @pmp('dt', [np.float64, np.complex128])
def test_reduction(dom, dt):
s1 = ift.Field.full(dom, dt(1.)) s1 = ift.Field.full(dom, dt(1.))
assert_allclose(s1.mean(), 1.) assert_allclose(s1.mean(), 1.)
assert_allclose(s1.mean(0), 1.) assert_allclose(s1.mean(0), 1.)
...@@ -225,7 +240,8 @@ class Test_Functionality(unittest.TestCase): ...@@ -225,7 +240,8 @@ class Test_Functionality(unittest.TestCase):
assert_allclose(s1.std(), 0., atol=1e-14) assert_allclose(s1.std(), 0., atol=1e-14)
assert_allclose(s1.std(0), 0., atol=1e-14) assert_allclose(s1.std(0), 0., atol=1e-14)
def test_err(self):
def test_err(self):
s1 = ift.RGSpace((10,))