diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8dc81c7580..409612d28b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -33,7 +33,7 @@ jobs: strategy: matrix: os: [ubuntu-20.04] - floatx: [float32, float64] + floatx: [float64] test-subset: - | pymc/tests/test_util.py @@ -125,7 +125,7 @@ jobs: - name: Run tests run: | conda activate pymc-test-py37 - python -m pytest -vv --cov=pymc --cov-append --cov-report=xml --cov-report term --durations=50 $TEST_SUBSET + python -m pytest -vv --cov=pymc --cov-report=xml --cov-report term --durations=50 $TEST_SUBSET - name: Upload coverage to Codecov uses: codecov/codecov-action@v2 with: @@ -136,7 +136,7 @@ jobs: strategy: matrix: os: [windows-latest] - floatx: [float32, float64] + floatx: [float64] test-subset: - pymc/tests/test_variational_inference.py pymc/tests/test_initial_point.py - pymc/tests/test_pickling.py pymc/tests/test_profile.py pymc/tests/test_step.py @@ -195,7 +195,7 @@ jobs: # The ">-" in the next line replaces newlines with spaces (see https://stackoverflow.com/a/66809682). run: >- conda activate pymc-test-py38 && - python -m pytest -vv --cov=pymc --cov-append --cov-report=xml --cov-report term --durations=50 %TEST_SUBSET% + python -m pytest -vv --cov=pymc --cov-report=xml --cov-report term --durations=50 %TEST_SUBSET% - name: Upload coverage to Codecov uses: codecov/codecov-action@v2 with: @@ -341,3 +341,69 @@ jobs: env_vars: TEST_SUBSET name: JAX tests - ${{ matrix.os }} ${{ matrix.floatx }} fail_ci_if_error: false + float32: + strategy: + matrix: + os: [windows-latest] + floatx: [float32] + test-subset: + - pymc/tests/test_sampling.py pymc/tests/test_ode.py + fail-fast: false + runs-on: ${{ matrix.os }} + env: + TEST_SUBSET: ${{ matrix.test-subset }} + AESARA_FLAGS: floatX=${{ matrix.floatx }},gcc__cxxflags='-march=core2' + defaults: + run: + shell: cmd + steps: + - uses: actions/checkout@v2 + - name: Cache conda + uses: actions/cache@v1 + env: + # Increase this value to reset cache if conda-envs/environment-test-py38.yml has not changed + CACHE_NUMBER: 0 + with: + path: ~/conda_pkgs_dir + key: ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-${{ + hashFiles('conda-envs/windows-environment-test-py38.yml') }} + - name: Cache multiple paths + uses: actions/cache@v2 + env: + # Increase this value to reset cache if requirements.txt has not changed + CACHE_NUMBER: 0 + with: + path: | + ~/.cache/pip + $RUNNER_TOOL_CACHE/Python/* + ~\AppData\Local\pip\Cache + key: ${{ runner.os }}-build-${{ matrix.python-version }}-${{ + hashFiles('requirements.txt') }} + - uses: conda-incubator/setup-miniconda@v2 + with: + miniforge-variant: Mambaforge + miniforge-version: latest + mamba-version: "*" + activate-environment: pymc-test-py38 + channel-priority: strict + environment-file: conda-envs/windows-environment-test-py38.yml + use-mamba: true + use-only-tar-bz2: true # IMPORTANT: This needs to be set for caching to work properly! + - name: Install-pymc + run: | + conda activate pymc-test-py38 + pip install -e . + pip install --pre -U polyagamma + python --version + - name: Run tests + # This job uses a cmd shell, therefore the environment variable syntax is different! + # The ">-" in the next line replaces newlines with spaces (see https://stackoverflow.com/a/66809682). + run: >- + conda activate pymc-test-py38 && + python -m pytest -vv --cov=pymc --cov-report=xml --cov-report term --durations=50 %TEST_SUBSET% + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v2 + with: + env_vars: TEST_SUBSET + name: ${{ matrix.os }} ${{ matrix.floatx }} + fail_ci_if_error: false diff --git a/pymc/distributions/simulator.py b/pymc/distributions/simulator.py index 0affa2b6a2..54bb256273 100644 --- a/pymc/distributions/simulator.py +++ b/pymc/distributions/simulator.py @@ -295,11 +295,9 @@ def __call__(self, epsilon, obs_data, sim_data): return self.d_n * np.sum(-np.log(nu_d / self.rho_d) / epsilon) + self.log_r -scalarX = at.dscalar if aesara.config.floatX == "float64" else at.fscalar -vectorX = at.dvector if aesara.config.floatX == "float64" else at.fvector - - def create_sum_stat_op_from_fn(fn): + vectorX = at.dvector if aesara.config.floatX == "float64" else at.fvector + # Check if callable returns TensorVariable with dummy inputs try: res = fn(vectorX()) @@ -322,6 +320,9 @@ def perform(self, node, inputs, outputs): def create_distance_op_from_fn(fn): + scalarX = at.dscalar if aesara.config.floatX == "float64" else at.fscalar + vectorX = at.dvector if aesara.config.floatX == "float64" else at.fvector + # Check if callable returns TensorVariable with dummy inputs try: res = fn(scalarX(), vectorX(), vectorX()) diff --git a/pymc/tests/test_aesaraf.py b/pymc/tests/test_aesaraf.py index 2b9de48707..74622a16a3 100644 --- a/pymc/tests/test_aesaraf.py +++ b/pymc/tests/test_aesaraf.py @@ -47,9 +47,6 @@ from pymc.exceptions import ShapeError from pymc.vartypes import int_types -FLOATX = str(aesara.config.floatX) -INTX = str(_conversion_map[FLOATX]) - def test_change_rv_size(): loc = at.as_tensor_variable([1, 2]) @@ -176,57 +173,59 @@ def setup_class(self): self.output_buffer = dict() self.func_buffer = dict() - def _input_tensors(self, shape): + def _input_tensors(self, shape, floatX): + intX = str(_conversion_map[floatX]) ndim = len(shape) - arr = TensorType(FLOATX, [False] * ndim)("arr") - indices = TensorType(INTX, [False] * ndim)("indices") - arr.tag.test_value = np.zeros(shape, dtype=FLOATX) - indices.tag.test_value = np.zeros(shape, dtype=INTX) + arr = TensorType(floatX, [False] * ndim)("arr") + indices = TensorType(intX, [False] * ndim)("indices") + arr.tag.test_value = np.zeros(shape, dtype=floatX) + indices.tag.test_value = np.zeros(shape, dtype=intX) return arr, indices - def get_input_tensors(self, shape): + def get_input_tensors(self, shape, floatX): ndim = len(shape) try: - return self.inputs_buffer[ndim] + return self.inputs_buffer[(ndim, floatX)] except KeyError: - arr, indices = self._input_tensors(shape) - self.inputs_buffer[ndim] = arr, indices + arr, indices = self._input_tensors(shape, floatX) + self.inputs_buffer[(ndim, floatX)] = arr, indices return arr, indices def _output_tensor(self, arr, indices, axis): return take_along_axis(arr, indices, axis) - def get_output_tensors(self, shape, axis): + def get_output_tensors(self, shape, axis, floatX): ndim = len(shape) try: - return self.output_buffer[(ndim, axis)] + return self.output_buffer[(ndim, axis, floatX)] except KeyError: - arr, indices = self.get_input_tensors(shape) + arr, indices = self.get_input_tensors(shape, floatX) out = self._output_tensor(arr, indices, axis) - self.output_buffer[(ndim, axis)] = out + self.output_buffer[(ndim, axis, floatX)] = out return out def _function(self, arr, indices, out): return aesara.function([arr, indices], [out]) - def get_function(self, shape, axis): + def get_function(self, shape, axis, floatX): ndim = len(shape) try: - return self.func_buffer[(ndim, axis)] + return self.func_buffer[(ndim, axis, floatX)] except KeyError: - arr, indices = self.get_input_tensors(shape) - out = self.get_output_tensors(shape, axis) + arr, indices = self.get_input_tensors(shape, floatX) + out = self.get_output_tensors(shape, axis, floatX) func = self._function(arr, indices, out) - self.func_buffer[(ndim, axis)] = func + self.func_buffer[(ndim, axis, floatX)] = func return func @staticmethod - def get_input_values(shape, axis, samples): - arr = np.random.randn(*shape).astype(FLOATX) + def get_input_values(shape, axis, samples, floatX): + intX = str(_conversion_map[floatX]) + arr = np.random.randn(*shape).astype(floatX) size = list(shape) size[axis] = samples size = tuple(size) - indices = np.random.randint(low=0, high=shape[axis], size=size, dtype=INTX) + indices = np.random.randint(low=0, high=shape[axis], size=size, dtype=intX) return arr, indices @pytest.mark.parametrize( @@ -250,10 +249,12 @@ def get_input_values(shape, axis, samples): ), ids=str, ) - def test_take_along_axis(self, shape, axis, samples): - arr, indices = self.get_input_values(shape, axis, samples) - func = self.get_function(shape, axis) - assert np.allclose(np_take_along_axis(arr, indices, axis=axis), func(arr, indices)[0]) + @pytest.mark.parametrize("floatX", ["float32", "float64"]) + def test_take_along_axis(self, shape, axis, samples, floatX): + with aesara.config.change_flags(floatX=floatX): + arr, indices = self.get_input_values(shape, axis, samples, floatX) + func = self.get_function(shape, axis, floatX) + assert np.allclose(np_take_along_axis(arr, indices, axis=axis), func(arr, indices)[0]) @pytest.mark.parametrize( ["shape", "axis", "samples"], @@ -276,53 +277,62 @@ def test_take_along_axis(self, shape, axis, samples): ), ids=str, ) - def test_take_along_axis_grad(self, shape, axis, samples): - if axis < 0: - _axis = len(shape) + axis - else: - _axis = axis - # Setup the aesara function - t_arr, t_indices = self.get_input_tensors(shape) - t_out2 = aesara.grad( - at.sum(self._output_tensor(t_arr**2, t_indices, axis)), - t_arr, - ) - func = aesara.function([t_arr, t_indices], [t_out2]) - - # Test that the gradient gives the same output as what is expected - arr, indices = self.get_input_values(shape, axis, samples) - expected_grad = np.zeros_like(arr) - slicer = [slice(None)] * len(shape) - for i in range(indices.shape[axis]): - slicer[axis] = i - inds = indices[tuple(slicer)].reshape(shape[:_axis] + (1,) + shape[_axis + 1 :]) - inds = _make_along_axis_idx(shape, inds, _axis) - expected_grad[inds] += 1 - expected_grad *= 2 * arr - out = func(arr, indices)[0] - assert np.allclose(out, expected_grad) + @pytest.mark.parametrize("floatX", ["float32", "float64"]) + def test_take_along_axis_grad(self, shape, axis, samples, floatX): + with aesara.config.change_flags(floatX=floatX): + if axis < 0: + _axis = len(shape) + axis + else: + _axis = axis + # Setup the aesara function + t_arr, t_indices = self.get_input_tensors(shape, floatX) + t_out2 = aesara.grad( + at.sum(self._output_tensor(t_arr**2, t_indices, axis)), + t_arr, + ) + func = aesara.function([t_arr, t_indices], [t_out2]) + + # Test that the gradient gives the same output as what is expected + arr, indices = self.get_input_values(shape, axis, samples, floatX) + expected_grad = np.zeros_like(arr) + slicer = [slice(None)] * len(shape) + for i in range(indices.shape[axis]): + slicer[axis] = i + inds = indices[tuple(slicer)].reshape(shape[:_axis] + (1,) + shape[_axis + 1 :]) + inds = _make_along_axis_idx(shape, inds, _axis) + expected_grad[inds] += 1 + expected_grad *= 2 * arr + out = func(arr, indices)[0] + assert np.allclose(out, expected_grad) @pytest.mark.parametrize("axis", [-4, 4], ids=str) - def test_axis_failure(self, axis): - arr, indices = self.get_input_tensors((3, 1)) - with pytest.raises(ValueError): - take_along_axis(arr, indices, axis=axis) - - def test_ndim_failure(self): - arr = TensorType(FLOATX, [False] * 3)("arr") - indices = TensorType(INTX, [False] * 2)("indices") - arr.tag.test_value = np.zeros((1,) * arr.ndim, dtype=FLOATX) - indices.tag.test_value = np.zeros((1,) * indices.ndim, dtype=INTX) - with pytest.raises(ValueError): - take_along_axis(arr, indices) - - def test_dtype_failure(self): - arr = TensorType(FLOATX, [False] * 3)("arr") - indices = TensorType(FLOATX, [False] * 3)("indices") - arr.tag.test_value = np.zeros((1,) * arr.ndim, dtype=FLOATX) - indices.tag.test_value = np.zeros((1,) * indices.ndim, dtype=FLOATX) - with pytest.raises(IndexError): - take_along_axis(arr, indices) + @pytest.mark.parametrize("floatX", ["float32", "float64"]) + def test_axis_failure(self, axis, floatX): + with aesara.config.change_flags(floatX=floatX): + arr, indices = self.get_input_tensors((3, 1), floatX) + with pytest.raises(ValueError): + take_along_axis(arr, indices, axis=axis) + + @pytest.mark.parametrize("floatX", ["float32", "float64"]) + def test_ndim_failure(self, floatX): + with aesara.config.change_flags(floatX=floatX): + intX = str(_conversion_map[floatX]) + arr = TensorType(floatX, [False] * 3)("arr") + indices = TensorType(intX, [False] * 2)("indices") + arr.tag.test_value = np.zeros((1,) * arr.ndim, dtype=floatX) + indices.tag.test_value = np.zeros((1,) * indices.ndim, dtype=intX) + with pytest.raises(ValueError): + take_along_axis(arr, indices) + + @pytest.mark.parametrize("floatX", ["float32", "float64"]) + def test_dtype_failure(self, floatX): + with aesara.config.change_flags(floatX=floatX): + arr = TensorType(floatX, [False] * 3)("arr") + indices = TensorType(floatX, [False] * 3)("indices") + arr.tag.test_value = np.zeros((1,) * arr.ndim, dtype=floatX) + indices.tag.test_value = np.zeros((1,) * indices.ndim, dtype=floatX) + with pytest.raises(IndexError): + take_along_axis(arr, indices) def test_extract_obs_data(): diff --git a/pymc/tests/test_distributions_random.py b/pymc/tests/test_distributions_random.py index c0c09d736a..2be81395cd 100644 --- a/pymc/tests/test_distributions_random.py +++ b/pymc/tests/test_distributions_random.py @@ -14,6 +14,7 @@ import functools import itertools import re +import sys from typing import Callable, List, Optional @@ -1571,14 +1572,18 @@ def constant_rng_fn(self, size, c): "check_pymc_params_match_rv_op", "check_pymc_draws_match_reference", "check_rv_size", - "check_dtype", ] - def check_dtype(self): - assert pm.Constant.dist(2**4).dtype == "int8" - assert pm.Constant.dist(2**16).dtype == "int32" - assert pm.Constant.dist(2**32).dtype == "int64" - assert pm.Constant.dist(2.0).dtype == aesara.config.floatX + @pytest.mark.parametrize("floatX", ["float32", "float64"]) + @pytest.mark.xfail( + sys.platform == "win32", reason="https://github.com/aesara-devs/aesara/issues/871" + ) + def test_dtype(self, floatX): + with aesara.config.change_flags(floatX=floatX): + assert pm.Constant.dist(2**4).dtype == "int8" + assert pm.Constant.dist(2**16).dtype == "int32" + assert pm.Constant.dist(2**32).dtype == "int64" + assert pm.Constant.dist(2.0).dtype == floatX class TestOrderedLogistic(BaseTestDistributionRandom): diff --git a/pymc/tests/test_mixture.py b/pymc/tests/test_mixture.py index 825207d0bb..bd9c8400ed 100644 --- a/pymc/tests/test_mixture.py +++ b/pymc/tests/test_mixture.py @@ -659,24 +659,26 @@ def test_iterable_single_component_warning(self): with pytest.warns(UserWarning, match="Single component will be treated as a mixture"): Mixture.dist(w=[0.5, 0.5], comp_dists=[Normal.dist(size=2)]) - def test_mixture_dtype(self): - mix_dtype = Mixture.dist( - w=[0.5, 0.5], - comp_dists=[ - Multinomial.dist(n=5, p=[0.5, 0.5]), - Multinomial.dist(n=5, p=[0.5, 0.5]), - ], - ).dtype - assert mix_dtype == "int64" - - mix_dtype = Mixture.dist( - w=[0.5, 0.5], - comp_dists=[ - Dirichlet.dist(a=[0.5, 0.5]), - Dirichlet.dist(a=[0.5, 0.5]), - ], - ).dtype - assert mix_dtype == aesara.config.floatX + @pytest.mark.parametrize("floatX", ["float32", "float64"]) + def test_mixture_dtype(self, floatX): + with aesara.config.change_flags(floatX=floatX): + mix_dtype = Mixture.dist( + w=[0.5, 0.5], + comp_dists=[ + Multinomial.dist(n=5, p=[0.5, 0.5]), + Multinomial.dist(n=5, p=[0.5, 0.5]), + ], + ).dtype + assert mix_dtype == "int64" + + mix_dtype = Mixture.dist( + w=[0.5, 0.5], + comp_dists=[ + Dirichlet.dist(a=[0.5, 0.5]), + Dirichlet.dist(a=[0.5, 0.5]), + ], + ).dtype + assert mix_dtype == floatX @pytest.mark.parametrize( "comp_dists, expected_shape", diff --git a/pymc/tests/test_smc.py b/pymc/tests/test_smc.py index c33eaed240..6711dfd873 100644 --- a/pymc/tests/test_smc.py +++ b/pymc/tests/test_smc.py @@ -314,54 +314,58 @@ def test_one_gaussian(self): assert abs(self.data.mean() - po_p["s"].mean()) < 0.10 assert abs(self.data.std() - po_p["s"].std()) < 0.10 - def test_custom_dist_sum_stat(self): - with pm.Model() as m: - a = pm.Normal("a", mu=0, sigma=1) - b = pm.HalfNormal("b", sigma=1) - s = pm.Simulator( - "s", - self.normal_sim, - a, - b, - distance=self.abs_diff, - sum_stat=self.quantiles, - observed=self.data, - ) - - assert self.count_rvs(m.logpt()) == 1 - - with m: - pm.sample_smc(draws=100) - - def test_custom_dist_sum_stat_scalar(self): + @pytest.mark.parametrize("floatX", ["float32", "float64"]) + def test_custom_dist_sum_stat(self, floatX): + with aesara.config.change_flags(floatX=floatX): + with pm.Model() as m: + a = pm.Normal("a", mu=0, sigma=1) + b = pm.HalfNormal("b", sigma=1) + s = pm.Simulator( + "s", + self.normal_sim, + a, + b, + distance=self.abs_diff, + sum_stat=self.quantiles, + observed=self.data, + ) + + assert self.count_rvs(m.logpt()) == 1 + + with m: + pm.sample_smc(draws=100) + + @pytest.mark.parametrize("floatX", ["float32", "float64"]) + def test_custom_dist_sum_stat_scalar(self, floatX): """ Test that automatically wrapped functions cope well with scalar inputs """ scalar_data = 5 - with pm.Model() as m: - s = pm.Simulator( - "s", - self.normal_sim, - 0, - 1, - distance=self.abs_diff, - sum_stat=self.quantiles, - observed=scalar_data, - ) - assert self.count_rvs(m.logpt()) == 1 + with aesara.config.change_flags(floatX=floatX): + with pm.Model() as m: + s = pm.Simulator( + "s", + self.normal_sim, + 0, + 1, + distance=self.abs_diff, + sum_stat=self.quantiles, + observed=scalar_data, + ) + assert self.count_rvs(m.logpt()) == 1 - with pm.Model() as m: - s = pm.Simulator( - "s", - self.normal_sim, - 0, - 1, - distance=self.abs_diff, - sum_stat="mean", - observed=scalar_data, - ) - assert self.count_rvs(m.logpt()) == 1 + with pm.Model() as m: + s = pm.Simulator( + "s", + self.normal_sim, + 0, + 1, + distance=self.abs_diff, + sum_stat="mean", + observed=scalar_data, + ) + assert self.count_rvs(m.logpt()) == 1 def test_model_with_potential(self): assert self.count_rvs(self.SMABC_potential.logpt()) == 1 diff --git a/pymc/tests/test_step.py b/pymc/tests/test_step.py index 0d3cfb84a4..e8eb856642 100644 --- a/pymc/tests/test_step.py +++ b/pymc/tests/test_step.py @@ -25,7 +25,6 @@ from aesara.compile.ops import as_op from aesara.graph.op import Op -from numpy.testing import assert_array_almost_equal import pymc as pm @@ -62,7 +61,6 @@ ) from pymc.step_methods.mlda import extract_Q_estimate from pymc.tests.checks import close_to -from pymc.tests.helpers import select_by_precision from pymc.tests.models import ( mv_prior_simple, mv_simple, @@ -74,482 +72,13 @@ ) -class TestStepMethods: # yield test doesn't work subclassing object - master_samples = { - Slice: np.array( - [ - 0.10233528, - 0.40458486, - 0.17329217, - 0.46281232, - 0.22556278, - 1.52632836, - -0.27823807, - 0.02539625, - 1.02711735, - 0.03686346, - -0.62841281, - -0.27125083, - 0.31989505, - 0.84031155, - -0.18949138, - 1.60550262, - 1.01375291, - -0.29742941, - 0.35312738, - 0.43363622, - 1.18898078, - 0.80063888, - 0.38445644, - 0.90184395, - 1.69150017, - 2.05452171, - -0.13334755, - 1.61265408, - 1.36579345, - 1.3216292, - -0.59487037, - -0.34648927, - 1.05107285, - 0.42870305, - 0.61552257, - 0.55239884, - 0.13929271, - 0.26213809, - -0.2316028, - 0.19711046, - 1.42832629, - 1.93641434, - -0.81142379, - -0.31059485, - -0.3189694, - 1.43542534, - 0.40311093, - 1.63103768, - 0.24034874, - 0.33924866, - 0.94951616, - 0.71700185, - 0.79273056, - -0.44569146, - 1.91974783, - 0.84673795, - 1.12411833, - -0.83123811, - -0.54310095, - -0.00721347, - 0.9925055, - 1.04015058, - -0.34958074, - -0.14926302, - -0.47990225, - -0.75629446, - -0.95942067, - 1.68179204, - 1.20598073, - 1.39675733, - 1.22755935, - 0.06728757, - 1.05184231, - 1.01126791, - -0.67327093, - 0.21429651, - 1.33730461, - -1.56174184, - -0.64348764, - 0.98050636, - 0.25923049, - 0.58622631, - 0.46589069, - 1.44367347, - -0.43141573, - 1.08293374, - -0.5563204, - 1.46287904, - 1.26019815, - 0.52972104, - 1.08792687, - 1.10064358, - 1.84881549, - 0.91179647, - 0.69316592, - -0.47657064, - 2.22747063, - 0.83388935, - 0.84680716, - -0.10556406, - ] - ), - HamiltonianMC: np.array( - [ - 1.43583525, - 1.43583525, - 1.43583525, - -0.57415005, - 0.91472062, - 0.91472062, - 0.36282799, - 0.80991631, - 0.84457253, - 0.84457253, - -0.12651784, - -0.12651784, - 0.39027088, - -0.22998424, - 0.64337475, - 0.64337475, - 0.03504003, - 1.2667789, - 1.2667789, - 0.34770874, - 0.224319, - 0.224319, - 1.00416894, - 0.46161403, - 0.28217305, - 0.28217305, - 0.50327811, - 0.50327811, - 0.50327811, - 0.50327811, - 0.42335724, - 0.42335724, - 0.20336198, - 0.20336198, - 0.20336198, - 0.16330229, - 0.16330229, - -0.7332075, - 1.04924226, - 1.04924226, - 0.39630439, - 0.16481719, - 0.16481719, - 0.84146061, - 0.83146709, - 0.83146709, - 0.32748059, - 1.00918804, - 1.00918804, - 0.91034823, - 1.31278027, - 1.38222654, - 1.38222654, - -0.32268814, - -0.32268814, - 2.1866116, - 1.21679252, - -0.15916878, - -0.15916878, - 0.38958249, - 0.38958249, - 0.54971928, - 0.05591406, - 0.87712017, - 0.87712017, - 0.19409043, - 0.19409043, - 0.19409043, - 0.40718849, - 0.63399349, - 0.35510353, - 0.35510353, - 0.47860847, - 0.47860847, - 0.69805772, - 0.16686305, - 0.16686305, - 0.16686305, - 0.04971251, - 0.04971251, - -0.90052793, - -0.73203754, - 1.02258958, - 1.02258958, - -0.14144856, - -0.14144856, - 1.43017486, - 1.23202605, - 1.23202605, - 0.24442885, - 0.78300516, - 0.30494261, - 0.30494261, - 0.30494261, - -0.00596443, - 1.31695235, - 0.81375848, - 0.81375848, - 0.81375848, - 1.91238675, - ] - ), - Metropolis: np.array( - [ - 1.62434536, - 1.01258895, - 0.4844172, - 0.4844172, - 0.4844172, - 0.4844172, - 0.4844172, - 0.4844172, - 0.4844172, - 0.4844172, - 0.31198899, - 0.31198899, - 0.31198899, - 0.31198899, - 1.21284494, - 0.52911708, - 0.261229, - 0.79158447, - 0.10441177, - -0.74079387, - -0.74079387, - -0.50637818, - -0.50637818, - -0.50637818, - -0.45557042, - -0.45557042, - -0.33541147, - 0.28179164, - 0.58196196, - 0.22971211, - 0.02081788, - 0.60744107, - 0.8930284, - 0.8930284, - 1.40595822, - 1.10786538, - 1.10786538, - 1.10786538, - 1.10786538, - -0.28863095, - -0.12859388, - 0.74757504, - 0.74757504, - 0.74757504, - 0.97766977, - 0.97766977, - 0.75534163, - 0.55458356, - 0.75288328, - 0.87189193, - 0.9937132, - 0.9937132, - 0.61842825, - 0.61842825, - 0.27457457, - 0.31817143, - 0.31817143, - 0.31817143, - -0.77674042, - -0.60735798, - 0.13319847, - -0.82050213, - -0.82050213, - -0.50534274, - -0.15479676, - -0.15479676, - -0.19349227, - -0.19349227, - -0.21810923, - -0.21810923, - -0.21810923, - 1.0180548, - -0.18121323, - 0.68213209, - 0.68213209, - 1.23266958, - 1.23266958, - 0.60913885, - 1.41099989, - 1.45756718, - 1.45756718, - 1.45756718, - 1.45756718, - 1.59526839, - 1.82776295, - 1.82776295, - 1.82776295, - 1.82776295, - 2.2691274, - 2.16897216, - 2.18638157, - 1.06436284, - 0.54726838, - 0.54726838, - 1.04247971, - 0.86777655, - 0.86777655, - 0.86777655, - 0.86777655, - 0.61914177, - ] - ), - NUTS: np.array( - [ - 0.550575, - 0.550575, - 0.80031201, - 0.91580544, - 1.34622953, - 1.34622953, - -0.63861533, - -0.62101385, - -0.62101385, - -0.60250375, - -1.04753424, - -0.34850626, - 0.35882649, - -0.20339408, - -0.18077466, - -0.18077466, - 0.1242007, - -0.48708213, - 0.01216292, - 0.01216292, - -0.15991487, - 0.0118306, - 0.0118306, - 0.02512962, - -0.06002705, - 0.61278464, - -0.45991609, - -0.45991609, - -0.45991609, - -0.3067988, - -0.3067988, - -0.30830273, - -0.62877494, - -0.5896293, - 0.32740518, - 0.32740518, - 0.55321326, - 0.34885231, - 0.34885231, - 0.35304997, - 1.20016133, - 1.20016133, - 1.26432486, - 1.22481613, - 1.46040499, - 1.2251786, - 0.29954482, - 0.29954482, - 0.5713582, - 0.5755183, - 0.26968846, - 0.68253483, - 0.68253483, - 0.69418724, - 1.4172782, - 1.4172782, - 0.85063608, - 0.23409974, - -0.65012501, - 1.16211157, - -0.04844954, - 1.34390994, - -0.44058335, - -0.44058335, - 0.85096033, - 0.98734074, - 1.31200906, - 1.2751574, - 1.2751574, - 0.04377635, - 0.08244824, - 0.6342471, - -0.31243596, - 1.0165907, - -0.19025897, - -0.19025897, - 0.02133041, - -0.02335463, - 0.43923434, - -0.45033488, - 0.05985518, - -0.10019701, - 1.34229104, - 1.28571862, - 0.59557205, - 0.63730268, - 0.63730268, - 0.54269992, - 0.54269992, - -0.48334519, - 1.02199273, - -0.17367903, - -0.17367903, - 0.8470911, - -0.12868214, - 1.8986946, - 1.55412619, - 1.55412619, - 0.90228003, - 1.3328478, - ] - ), - } - +class TestStepMethods: def setup_class(self): self.temp_dir = tempfile.mkdtemp() def teardown_class(self): shutil.rmtree(self.temp_dir) - @pytest.mark.xfail( - reason="This test is too ambiguous/broad and completely RNG-state specific. " - "It needs to be refactored or removed." - ) - @pytest.mark.xfail(condition=(aesara.config.floatX == "float32"), reason="Fails on float32") - def test_sample_exact(self): - for step_method in self.master_samples: - self.check_trace(step_method) - - def check_trace(self, step_method): - """Tests whether the trace for step methods is exactly the same as on master. - - Code changes that effect how random numbers are drawn may change this, and require - `master_samples` to be updated, but such changes should be noted and justified in the - commit. - - This method may also be used to benchmark step methods across commits, by running, for - example - - ``` - BENCHMARK=100000 ./scripts/test.sh -s pymc/tests/test_step.py:TestStepMethods - ``` - - on multiple commits. - """ - n_steps = 100 - with Model() as model: - x = Normal("x", mu=0, sigma=1) - y = Normal("y", mu=x, sigma=1, observed=1) - if step_method.__name__ == "NUTS": - step = step_method(scaling=model.compute_initial_point()) - idata = sample( - 0, tune=n_steps, discard_tuned_samples=False, step=step, random_seed=1, chains=1 - ) - else: - idata = sample( - 0, - tune=n_steps, - discard_tuned_samples=False, - step=step_method(), - random_seed=1, - chains=1, - ) - - assert_array_almost_equal( - idata.warmup_posterior["x"], - self.master_samples[step_method], - decimal=select_by_precision(float64=6, float32=4), - ) - def check_stat(self, check, idata, name): if hasattr(idata, "warmup_posterior"): group = idata.warmup_posterior