Commit 8e196bc9 authored by René Fritze's avatar René Fritze Committed by René Fritze

[test] move grid fixtures and tests to hypothesis

parent 64daf399
......@@ -5,10 +5,11 @@
import numpy as np
import pytest
from hypothesis import given, settings
from pymor.discretizers.builtin.grids.interfaces import ReferenceElement
from pymortests.base import runmodule
from pymortests.fixtures.grid import grid, grid_with_orthogonal_centers
from pymortests.fixtures.grid import hy_grid, hy_grid_with_orthogonal_centers
# monkey np.testing.assert_allclose to behave the same as np.allclose
# for some reason, the default atol of np.testing.assert_allclose is 0
......@@ -22,6 +23,7 @@ def monkey_allclose(a, b, rtol=1.e-5, atol=1.e-8):
np.testing.assert_allclose = monkey_allclose
@given(hy_grid)
def test_reference_element_wrong_arguments(grid):
g = grid
with pytest.raises(AssertionError):
......@@ -30,18 +32,21 @@ def test_reference_element_wrong_arguments(grid):
g.reference_element(g.dim + 1)
@given(hy_grid)
def test_reference_element_type(grid):
g = grid
for d in range(g.dim + 1):
assert isinstance(g.reference_element(d), ReferenceElement)
@given(hy_grid)
def test_reference_element_transitivity(grid):
g = grid
for d in range(1, g.dim + 1):
assert g.reference_element(d) is g.reference_element(0).sub_reference_element(d)
@given(hy_grid)
def test_embeddings_wrong_arguments(grid):
g = grid
with pytest.raises(AssertionError):
......@@ -50,6 +55,7 @@ def test_embeddings_wrong_arguments(grid):
g.embeddings(g.dim + 1)
@given(hy_grid)
def test_embeddings_shape(grid):
g = grid
for d in range(g.dim + 1):
......@@ -60,6 +66,8 @@ def test_embeddings_shape(grid):
assert B.shape == (g.size(d), g.dim)
@settings(deadline=None)
@given(hy_grid)
def test_embeddings_transitivity(grid):
g = grid
for d in range(1, g.dim + 1):
......@@ -73,6 +81,7 @@ def test_embeddings_transitivity(grid):
np.testing.assert_allclose(BD[e], np.dot(AD1[SE[e, 0]], BSUB[SEI[e, 0]]) + BD1[SE[e, 0]])
@given(hy_grid)
def test_jacobian_inverse_transposed_wrong_arguments(grid):
g = grid
with pytest.raises(AssertionError):
......@@ -83,12 +92,16 @@ def test_jacobian_inverse_transposed_wrong_arguments(grid):
g.jacobian_inverse_transposed(g.dim)
@settings(deadline=None)
@given(hy_grid)
def test_jacobian_inverse_transposed_shape(grid):
g = grid
for d in range(g.dim):
assert g.jacobian_inverse_transposed(d).shape == (g.size(d), g.dim, g.dim - d)
@settings(deadline=None)
@given(hy_grid)
def test_jacobian_inverse_transposed_values(grid):
g = grid
for d in range(g.dim):
......@@ -98,6 +111,7 @@ def test_jacobian_inverse_transposed_values(grid):
np.testing.assert_allclose(JIT[e], np.linalg.pinv(A[e]).T)
@given(hy_grid)
def test_integration_elements_wrong_arguments(grid):
g = grid
with pytest.raises(AssertionError):
......@@ -106,12 +120,15 @@ def test_integration_elements_wrong_arguments(grid):
g.integration_elements(g.dim + 1)
@given(hy_grid)
def test_integration_elements_shape(grid):
g = grid
for d in range(g.dim):
assert g.integration_elements(d).shape == (g.size(d),)
@settings(deadline=500)
@given(hy_grid)
def test_integration_elements_values(grid):
g = grid
for d in range(g.dim - 1):
......@@ -122,6 +139,7 @@ def test_integration_elements_values(grid):
np.testing.assert_allclose(g.integration_elements(g.dim), 1)
@given(hy_grid)
def test_volumes_wrong_arguments(grid):
g = grid
with pytest.raises(AssertionError):
......@@ -130,12 +148,14 @@ def test_volumes_wrong_arguments(grid):
g.volumes(g.dim + 1)
@given(hy_grid)
def test_volumes_shape(grid):
g = grid
for d in range(g.dim):
assert g.volumes(d).shape == (g.size(d),)
@given(hy_grid)
def test_volumes_values(grid):
g = grid
for d in range(g.dim - 1):
......@@ -144,6 +164,7 @@ def test_volumes_values(grid):
np.testing.assert_allclose(V, IE * g.reference_element(d).volume)
@given(hy_grid)
def test_volumes_inverse_wrong_arguments(grid):
g = grid
with pytest.raises(AssertionError):
......@@ -152,12 +173,14 @@ def test_volumes_inverse_wrong_arguments(grid):
g.volumes_inverse(g.dim + 1)
@given(hy_grid)
def test_volumes_inverse_shape(grid):
g = grid
for d in range(g.dim):
assert g.volumes_inverse(d).shape == (g.size(d),)
@given(hy_grid)
def test_volumes_inverse_values(grid):
g = grid
for d in range(g.dim - 1):
......@@ -166,18 +189,23 @@ def test_volumes_inverse_values(grid):
np.testing.assert_allclose(VI, np.reciprocal(V))
@given(hy_grid)
def test_unit_outer_normals_shape(grid):
g = grid
SE = g.subentities(0, 1)
assert g.unit_outer_normals().shape == SE.shape + (g.dim,)
@settings(deadline=None)
@given(hy_grid)
def test_unit_outer_normals_normed(grid):
g = grid
UON = g.unit_outer_normals()
np.testing.assert_allclose(np.sum(UON ** 2, axis=-1), 1)
@settings(deadline=None)
@given(hy_grid)
def test_unit_outer_normals_normal(grid):
g = grid
SE = g.subentities(0, 1)
......@@ -187,6 +215,8 @@ def test_unit_outer_normals_normal(grid):
np.testing.assert_allclose(np.sum(SEE * UON[..., np.newaxis], axis=-2), 0)
@settings(deadline=None)
@given(hy_grid)
def test_unit_outer_normals_neighbours(grid):
g = grid
UON = g.unit_outer_normals()
......@@ -200,6 +230,7 @@ def test_unit_outer_normals_neighbours(grid):
np.testing.assert_allclose(UON[se[0], sei[0]], -UON[se[1], sei[1]])
@given(hy_grid)
def test_centers_wrong_arguments(grid):
g = grid
with pytest.raises(AssertionError):
......@@ -208,12 +239,14 @@ def test_centers_wrong_arguments(grid):
g.centers(g.dim + 1)
@given(hy_grid)
def test_centers_shape(grid):
g = grid
for d in range(g.dim):
assert g.centers(d).shape == (g.size(d), g.dim)
@given(hy_grid)
def test_centers_values(grid):
g = grid
for d in range(g.dim):
......@@ -221,6 +254,7 @@ def test_centers_values(grid):
np.testing.assert_allclose(g.centers(d), B + A.dot(g.reference_element(d).center()))
@given(hy_grid)
def test_diameters_wrong_arguments(grid):
g = grid
with pytest.raises(AssertionError):
......@@ -229,18 +263,21 @@ def test_diameters_wrong_arguments(grid):
g.diameters(g.dim + 1)
@given(hy_grid)
def test_diameters_shape(grid):
g = grid
for d in range(g.dim):
assert g.diameters(d).shape == (g.size(d),)
@given(hy_grid)
def test_diameters_non_negative(grid):
g = grid
for d in range(g.dim - 1):
assert np.min(g.diameters(d)) >= 0
@given(hy_grid)
def test_diameters_values(grid):
g = grid
for d in range(g.dim - 1):
......@@ -248,6 +285,7 @@ def test_diameters_values(grid):
np.testing.assert_allclose(g.diameters(d), g.reference_element(d).mapped_diameter(A))
@given(hy_grid)
def test_quadrature_points_wrong_arguments(grid):
g = grid
for d in range(g.dim):
......@@ -263,6 +301,7 @@ def test_quadrature_points_wrong_arguments(grid):
g.quadrature_points(d, npoints=max(ps[t]) + 1, quadrature_type=t)
@given(hy_grid)
def test_quadrature_points_shape(grid):
g = grid
for d in range(g.dim):
......@@ -273,6 +312,7 @@ def test_quadrature_points_shape(grid):
assert g.quadrature_points(d, npoints=p, quadrature_type=t).shape == (g.size(d), p, g.dim)
@given(hy_grid)
def test_quadrature_points_values(grid):
g = grid
for d in range(g.dim):
......@@ -286,6 +326,7 @@ def test_quadrature_points_values(grid):
np.testing.assert_allclose(Q, B[:, np.newaxis, :] + np.einsum('eij,qj->eqi', A, q))
@given(hy_grid)
def test_bounding_box(grid):
g = grid
bbox = g.bounding_box()
......@@ -295,6 +336,8 @@ def test_bounding_box(grid):
assert np.all(g.centers(g.dim) <= bbox[1])
@settings(deadline=None)
@given(hy_grid_with_orthogonal_centers)
def test_orthogonal_centers(grid_with_orthogonal_centers):
g = grid_with_orthogonal_centers
C = g.orthogonal_centers()
......@@ -309,5 +352,6 @@ def test_orthogonal_centers(grid_with_orthogonal_centers):
SPROD = EMB[s].dot(SEGMENT)
np.testing.assert_allclose(SPROD, 0)
if __name__ == "__main__":
runmodule(filename=__file__)
......@@ -3,8 +3,7 @@
# License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
import math as m
import random
from hypothesis import strategies as hyst
import numpy as np
import pytest
......@@ -15,99 +14,57 @@ from pymor.discretizers.builtin.grids.tria import TriaGrid
from pymor.discretizers.builtin.grids.unstructured import UnstructuredTriangleGrid
rect_grid_generators = [lambda arg=arg, kwargs=kwargs: RectGrid(arg, **kwargs) for arg, kwargs in
[((2, 4), {}),
((1, 1), {}),
((42, 42), {}),
((2, 4), dict(identify_left_right=True)),
((2, 4), dict(identify_bottom_top=True)),
((2, 4), dict(identify_left_right=True, identify_bottom_top=True)),
((2, 1), dict(identify_left_right=True)),
((1, 2), dict(identify_bottom_top=True)),
((2, 2), dict(identify_left_right=True, identify_bottom_top=True)),
((42, 30), dict(identify_left_right=True)),
((42, 30), dict(identify_bottom_top=True)),
((42, 30), dict(identify_left_right=True, identify_bottom_top=True))]]
# TODO let domain be drawn too
def hy_rect_tria_kwargs(draw):
identify_left_right = draw(hyst.booleans())
identify_bottom_top = draw(hyst.booleans())
interval_i = hyst.integers(min_value=1, max_value=42)
num_intervals = draw(hyst.tuples(interval_i.filter(lambda x: (not identify_left_right) or x > 1),
interval_i.filter(lambda y: (not identify_bottom_top) or y > 1)))
# domain_value = hyst.floats(allow_infinity=False, allow_nan=False)
# domain_point = hyst.tuples(domain_value, domain_value)
# domain = draw(hyst.tuples(domain_point, domain_point).filter(lambda d: d[0][0] < d[1][0] and d[0][1] < d[1][1]))
domain = ((0,0), (1,1))
return {"num_intervals": num_intervals, "domain": domain, "identify_left_right": identify_left_right,
"identify_bottom_top": identify_bottom_top}
@hyst.composite
def hy_rect_grid(draw):
return RectGrid(**hy_rect_tria_kwargs(draw))
tria_grid_generators = [lambda arg=arg, kwargs=kwargs: TriaGrid(arg, **kwargs) for arg, kwargs in
[((2, 4), {}),
((1, 1), {}),
((42, 42), {}),
((2, 4), dict(identify_left_right=True)),
((2, 4), dict(identify_bottom_top=True)),
((2, 4), dict(identify_left_right=True, identify_bottom_top=True)),
((2, 1), dict(identify_left_right=True)),
((1, 2), dict(identify_bottom_top=True)),
((2, 2), dict(identify_left_right=True, identify_bottom_top=True)),
((42, 30), dict(identify_left_right=True)),
((42, 30), dict(identify_bottom_top=True)),
((42, 30), dict(identify_left_right=True, identify_bottom_top=True))]]
@hyst.composite
def hy_tria_grid(draw):
return RectGrid(**hy_rect_tria_kwargs(draw))
oned_grid_generators = [lambda kwargs=kwargs: OnedGrid(**kwargs) for kwargs in
[dict(domain=np.array((-2, 2)), num_intervals=10),
dict(domain=np.array((-4, -2)), num_intervals=100),
dict(domain=np.array((-4, -2)), num_intervals=100, identify_left_right=True),
dict(domain=np.array((2, 3)), num_intervals=10),
dict(domain=np.array((2, 3)), num_intervals=10, identify_left_right=True),
dict(domain=np.array((1, 2)), num_intervals=10000)]]
unstructured_grid_generators = \
[lambda: UnstructuredTriangleGrid.from_vertices(np.array([[0, 0], [-1, -1], [1, -1], [1, 1], [-1, 1]]),
np.array([[0, 1, 2], [0, 3, 4], [0, 4, 1]]))]
@hyst.composite
def hy_oned_grid(draw):
identify_left_right = draw(hyst.booleans())
interval_i = hyst.integers(min_value=1, max_value=10000)
num_intervals = draw(interval_i.filter(lambda x: (not identify_left_right) or x > 1))
domain_point = hyst.floats(allow_infinity=False, allow_nan=False)
domain = draw(hyst.tuples(domain_point, domain_point).filter(lambda d: d[0] < d[1]))
return OnedGrid(num_intervals=num_intervals, domain=domain, identify_left_right=identify_left_right)
def subgrid_factory(grid_generator, neq, seed):
np.random.seed(seed)
g = grid_generator()
# TODO re-use other grid strategies
@hyst.composite
def hy_subgrid(draw):
grid = draw(hyst.sampled_from([RectGrid((1, 1)), TriaGrid((1, 1)), RectGrid((8, 8)), TriaGrid((24, 24))]))
neq = draw(hyst.sampled_from([0, 2, 4]))
if neq == 0:
return SubGrid(g, np.arange(g.size(0), dtype=np.int32))
return SubGrid(grid, np.arange(grid.size(0), dtype=np.int32))
else:
return SubGrid(g, np.array(random.sample(range(g.size(0)), max(int(m.floor(g.size(0) / neq)), 1))))
subgrid_generators = [lambda args=args: subgrid_factory(*args) for args in
[(lambda: RectGrid((1, 1)), 0, 123),
(lambda: RectGrid((1, 1)), 2, 123),
(lambda: RectGrid((1, 1)), 4, 123),
(lambda: TriaGrid((1, 1)), 0, 123),
(lambda: TriaGrid((1, 1)), 2, 123),
(lambda: TriaGrid((1, 1)), 4, 123),
(lambda: RectGrid((8, 8)), 0, 123),
(lambda: RectGrid((8, 8)), 2, 123),
(lambda: RectGrid((8, 8)), 4, 123),
(lambda: TriaGrid((24, 24)), 0, 123),
(lambda: TriaGrid((24, 24)), 2, 123),
(lambda: TriaGrid((24, 24)), 4, 123)]]
@pytest.fixture(params=(
rect_grid_generators
+ tria_grid_generators
+ oned_grid_generators
+ subgrid_generators
+ unstructured_grid_generators
))
def grid(request):
return request.param()
@pytest.fixture(params=(rect_grid_generators + tria_grid_generators))
def rect_or_tria_grid(request):
return request.param()
@pytest.fixture(params=(rect_grid_generators + oned_grid_generators))
def grid_with_orthogonal_centers(request):
return request.param()
random = draw(hyst.randoms())
sample = random.sample(range(grid.size(0)), max(int(m.floor(grid.size(0) / neq)), 1))
return SubGrid(grid, np.array(sample))
@pytest.fixture(params=(
rect_grid_generators
+ tria_grid_generators
+ oned_grid_generators
+ unstructured_grid_generators
))
def grids_with_visualize(request):
return request.param()
hy_grid = hy_rect_grid() | hy_tria_grid() | hy_oned_grid() | hy_subgrid()
hy_rect_or_tria_grid = hy_rect_grid() | hy_tria_grid()
hy_unstructured_grid = hyst.just(UnstructuredTriangleGrid.from_vertices(
np.array([[0, 0], [-1, -1], [1, -1], [1, 1], [-1, 1]]), np.array([[0, 1, 2], [0, 3, 4], [0, 4, 1]])))
hy_grid_with_orthogonal_centers = hy_rect_grid() | hy_oned_grid()
hy_grids_with_visualize = hy_rect_grid() | hy_tria_grid() | hy_oned_grid() | hy_unstructured_grid
......@@ -7,10 +7,11 @@ from itertools import product
import numpy as np
import pytest
from hypothesis import given, settings
from pymor.core.exceptions import QtMissing
from pymor.discretizers.builtin.gui.qt import stop_gui_processes
from pymortests.fixtures.grid import grid, grids_with_visualize
from pymortests.fixtures.grid import hy_grids_with_visualize, hy_grid
from pymortests.pickling import assert_picklable_without_dumps_function
......@@ -26,12 +27,14 @@ def monkey_allclose(a, b, rtol=1.e-5, atol=1.e-8):
np.testing.assert_allclose = monkey_allclose
@given(hy_grid)
def test_dim(grid):
g = grid
assert isinstance(g.dim, int)
assert g.dim >= 0
@given(hy_grid)
def test_size(grid):
g = grid
for d in range(g.dim + 1):
......@@ -42,6 +45,7 @@ def test_size(grid):
g.size(g.dim + 1)
@given(hy_grid)
def test_subentities_wrong_arguments(grid):
g = grid
for e in range(g.dim + 1):
......@@ -55,6 +59,7 @@ def test_subentities_wrong_arguments(grid):
g.subentities(-1, 0)
@given(hy_grid)
def test_subentities_shape(grid):
g = grid
for e in range(g.dim + 1):
......@@ -63,6 +68,7 @@ def test_subentities_shape(grid):
assert g.subentities(e, s).shape[0] == g.size(e)
@given(hy_grid)
def test_subentities_dtype(grid):
g = grid
for e in range(g.dim + 1):
......@@ -70,6 +76,7 @@ def test_subentities_dtype(grid):
assert g.subentities(e, s).dtype == np.dtype('int32')
@given(hy_grid)
def test_subentities_entry_value_range(grid):
g = grid
for e in range(g.dim + 1):
......@@ -78,6 +85,8 @@ def test_subentities_entry_value_range(grid):
np.testing.assert_array_less(-2, g.subentities(e, s))
@settings(deadline=None)
@given(hy_grid)
def test_subentities_entry_values_unique(grid):
g = grid
for e in range(g.dim + 1):
......@@ -87,6 +96,7 @@ def test_subentities_entry_values_unique(grid):
assert S.size == np.unique(S).size
@given(hy_grid)
def test_subentities_codim_d_codim_d(grid):
g = grid
for d in range(g.dim + 1):
......@@ -94,6 +104,7 @@ def test_subentities_codim_d_codim_d(grid):
np.testing.assert_array_equal(g.subentities(d, d).ravel(), np.arange(g.size(d)))
@given(hy_grid)
def test_subentities_transitivity(grid):
g = grid
for e in range(g.dim + 1):
......@@ -108,6 +119,7 @@ def test_subentities_transitivity(grid):
assert set(SESE[SE[i, j]]) <= set(SSE[i]).union((-1,))
@given(hy_grid)
def test_superentities_wrong_arguments(grid):
g = grid
for e in range(g.dim + 1):
......@@ -123,6 +135,7 @@ def test_superentities_wrong_arguments(grid):
g.superentities(-1, -2)
@given(hy_grid)
def test_superentities_shape(grid):
g = grid
for e in range(g.dim + 1):
......@@ -133,6 +146,7 @@ def test_superentities_shape(grid):
assert g.superentities(1, 0).shape[1] <= 2
@given(hy_grid)
def test_superentities_dtype(grid):
g = grid
for e in range(g.dim + 1):
......@@ -140,6 +154,7 @@ def test_superentities_dtype(grid):
assert g.superentities(e, s).dtype == np.dtype('int32')
@given(hy_grid)
def test_superentities_entry_value_range(grid):
g = grid
for e in range(g.dim + 1):
......@@ -148,6 +163,7 @@ def test_superentities_entry_value_range(grid):
np.testing.assert_array_less(-2, g.superentities(e, s))
@given(hy_grid)
def test_superentities_entry_values_unique(grid):
g = grid
for e in range(g.dim + 1):
......@@ -157,6 +173,7 @@ def test_superentities_entry_values_unique(grid):
assert S.size == np.unique(S).size
@given(hy_grid)
def test_superentities_entries_sorted(grid):
g = grid
for e in range(g.dim + 1):
......@@ -170,6 +187,7 @@ def test_superentities_entries_sorted(grid):
np.testing.assert_array_equal(S[i + 1:], -1)
@given(hy_grid)
def test_superentities_codim_d_codim_d(grid):
g = grid
for d in range(g.dim + 1):
......@@ -177,6 +195,7 @@ def test_superentities_codim_d_codim_d(grid):
np.testing.assert_array_equal(g.superentities(d, d).ravel(), np.arange(g.size(d)))
@given(hy_grid)
def test_superentities_each_entry_superentity(grid):
g = grid
for e in range(g.dim + 1):
......@@ -189,6 +208,7 @@ def test_superentities_each_entry_superentity(grid):
assert i in SUBE[se]
@given(hy_grid)
def test_superentities_each_superentity_has_entry(grid):
g = grid
for e in range(g.dim + 1):
......@@ -201,6 +221,7 @@ def test_superentities_each_superentity_has_entry(grid):
assert i in SE[se]
@given(hy_grid)
def test_superentity_indices_wrong_arguments(grid):
g = grid
for e in range(g.dim + 1):
......@@ -216,6 +237,7 @@ def test_superentity_indices_wrong_arguments(grid):
g.superentity_indices(-1, -2)
@given(hy_grid)
def test_superentity_indices_shape(grid):
g = grid
for e in range(g.dim + 1):
......@@ -223,6 +245,7 @@ def test_superentity_indices_shape(grid):
assert g.superentity_indices(e, s).shape == g.superentities(e, s).shape
@given(hy_grid)
def test_superentity_indices_dtype(grid):
g = grid
for e in range(g.dim + 1):
......@@ -230,6 +253,7 @@ def test_superentity_indices_dtype(grid):
assert g.superentity_indices(e, s).dtype == np.dtype('int32')
@given(hy_grid)
def test_superentity_indices_valid_entries(grid):
g = grid
for e in range(g.dim + 1):
......@@ -242,6 +266,7 @@ def test_superentity_indices_valid_entries(grid):
assert SUBE[superentity, SEI[index]] == index[0]
@given(hy_grid)
def test_neighbours_wrong_arguments(grid):
g = grid
for e in range(g.dim + 1):
......@@ -264,6 +289,9 @@ def test_neighbours_wrong_arguments(grid):
g.neighbours(-1, 0, g.dim)
# TODO product -> strategy
@settings(deadline=None)
@given(hy_grid)
def test_neighbours_shape(grid):
g = grid
for e, n in product(range(g.dim + 1), range(g.dim + 1)):
......@@ -272,6 +300,9 @@ def test_neighbours_shape(grid):
assert g.neighbours(e, n, s).shape[0] == g.size(e)
# TODO product -> strategy
@settings(deadline=None)
@given(hy_grid)
def test_neighbours_dtype(grid):
g = grid
for e, n in product(range(g.dim + 1), range(g.dim + 1)):
......@@ -279,6 +310,9 @@ def test_neighbours_dtype(grid):
assert g.neighbours(e, n, s).dtype == np.dtype('int32')
# TODO product -> strategy
@settings(deadline=None)
@given(hy_grid)
def test_neighbours_entry_value_range(grid):
g