From b34742deb747205cdb4d5520194642a4b3ba6f05 Mon Sep 17 00:00:00 2001 From: Jonathan Dekermanjian Date: Wed, 4 Sep 2024 18:10:40 -0600 Subject: [PATCH 1/9] added __copy__ and __deepcopy__ methods to Model and added unit tests --- pymc/model/core.py | 16 +++++++++++++ tests/model/test_core.py | 50 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/pymc/model/core.py b/pymc/model/core.py index 3dbd0c306c..b312b40948 100644 --- a/pymc/model/core.py +++ b/pymc/model/core.py @@ -1570,6 +1570,22 @@ def __getitem__(self, key): def __contains__(self, key): return key in self.named_vars or self.name_for(key) in self.named_vars + + def __copy__(self): + from pymc.model.fgraph import clone_model + check_for_gp_vars = [k for x in ['_rotated_', '_hsgp_coeffs_'] for k in self.named_vars.keys() if x in k] + if len(check_for_gp_vars) > 0: + raise Exception("Unable to clone Gaussian Process Variables") + + return clone_model(self) + + def __deepcopy__(self, _): + from pymc.model.fgraph import clone_model + check_for_gp_vars = [k for x in ['_rotated_', '_hsgp_coeffs_'] for k in self.named_vars.keys() if x in k] + if len(check_for_gp_vars) > 0: + raise Exception("Unable to clone Gaussian Process Variables") + + return clone_model(self) def replace_rvs_by_values( self, diff --git a/tests/model/test_core.py b/tests/model/test_core.py index 95a46873fb..747040ecdc 100644 --- a/tests/model/test_core.py +++ b/tests/model/test_core.py @@ -11,6 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import copy import pickle import threading import traceback @@ -1761,3 +1762,52 @@ def test_graphviz_call_function(self, var_names, filenames) -> None: figsize=None, dpi=300, ) + + +class TestModelCopy(unittest.TestCase): + @staticmethod + def simple_model() -> pm.Model: + with pm.Model() as simple_model: + error = pm.HalfNormal("error", 0.5) + alpha = pm.Normal("alpha", 0, 1) + pm.Normal("y", alpha, error) + return simple_model + + @staticmethod + def gp_model() -> pm.Model: + with pm.Model() as gp_model: + ell = pm.Gamma("ell", alpha=2, beta=1) + cov = 2 * pm.gp.cov.ExpQuad(1, ell) + gp = pm.gp.Latent(cov_func=cov) + f = gp.prior("f", X=np.arange(10)[:, None]) + pm.Normal("y", f * 2) + return gp_model + + def test_copy_model(self) -> None: + simple_model = self.simple_model() + copy_simple_model = copy.copy(simple_model) + deepcopy_simple_model = copy.deepcopy(simple_model) + + with simple_model: + simple_model_prior_predictive = pm.sample_prior_predictive(random_seed=42) + + with copy_simple_model: + copy_simple_model_prior_predictive = pm.sample_prior_predictive(random_seed=42) + + with deepcopy_simple_model: + deepcopy_simple_model_prior_predictive = pm.sample_prior_predictive(random_seed=42) + + simple_model_prior_predictive_mean = simple_model_prior_predictive['prior']['y'].mean(('chain', 'draw')) + copy_simple_model_prior_predictive_mean = copy_simple_model_prior_predictive['prior']['y'].mean(('chain', 'draw')) + deepcopy_simple_model_prior_predictive_mean = deepcopy_simple_model_prior_predictive['prior']['y'].mean(('chain', 'draw')) + + assert np.isclose(simple_model_prior_predictive_mean, copy_simple_model_prior_predictive_mean) + assert np.isclose(simple_model_prior_predictive_mean, deepcopy_simple_model_prior_predictive_mean) + + def test_guassian_process_copy_failure(self) -> None: + gaussian_process_model = self.gp_model() + with pytest.raises(Exception) as e: + copy.copy(gaussian_process_model) + + with pytest.raises(Exception) as e: + copy.deepcopy(gaussian_process_model) \ No newline at end of file From fe4e0c54d19e50e6ab976eb01b343cd77441a99e Mon Sep 17 00:00:00 2001 From: Jonathan Dekermanjian Date: Wed, 4 Sep 2024 18:19:27 -0600 Subject: [PATCH 2/9] added docs to methods --- pymc/model/core.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/pymc/model/core.py b/pymc/model/core.py index b312b40948..99f8b2c96c 100644 --- a/pymc/model/core.py +++ b/pymc/model/core.py @@ -1570,21 +1570,35 @@ def __getitem__(self, key): def __contains__(self, key): return key in self.named_vars or self.name_for(key) in self.named_vars - + def __copy__(self): + """ + Clone a pymc model by overiding the python copy method using the clone_model method from fgraph. + if guassian process variables are detected then an exception will be raised. + """ from pymc.model.fgraph import clone_model - check_for_gp_vars = [k for x in ['_rotated_', '_hsgp_coeffs_'] for k in self.named_vars.keys() if x in k] + + check_for_gp_vars = [ + k for x in ["_rotated_", "_hsgp_coeffs_"] for k in self.named_vars.keys() if x in k + ] if len(check_for_gp_vars) > 0: raise Exception("Unable to clone Gaussian Process Variables") - + return clone_model(self) - + def __deepcopy__(self, _): + """ + Clone a pymc model by overiding the python copy method using the clone_model method from fgraph. + if guassian process variables are detected then an exception will be raised. + """ from pymc.model.fgraph import clone_model - check_for_gp_vars = [k for x in ['_rotated_', '_hsgp_coeffs_'] for k in self.named_vars.keys() if x in k] + + check_for_gp_vars = [ + k for x in ["_rotated_", "_hsgp_coeffs_"] for k in self.named_vars.keys() if x in k + ] if len(check_for_gp_vars) > 0: raise Exception("Unable to clone Gaussian Process Variables") - + return clone_model(self) def replace_rvs_by_values( From bcb4309e0e750c47502d3fa61b57110f78ab3f16 Mon Sep 17 00:00:00 2001 From: Jonathan Dekermanjian Date: Sun, 8 Sep 2024 11:05:04 -0600 Subject: [PATCH 3/9] changed raise to warning, moved warning to low level clone_graph, added doc example, updated pytest --- pymc/model/core.py | 54 +++++++++++++++++++++++++++++----------- pymc/model/fgraph.py | 9 ++++++- tests/model/test_core.py | 34 ++++++++++++++++--------- 3 files changed, 70 insertions(+), 27 deletions(-) diff --git a/pymc/model/core.py b/pymc/model/core.py index 99f8b2c96c..bd62fa4369 100644 --- a/pymc/model/core.py +++ b/pymc/model/core.py @@ -1574,31 +1574,57 @@ def __contains__(self, key): def __copy__(self): """ Clone a pymc model by overiding the python copy method using the clone_model method from fgraph. - if guassian process variables are detected then an exception will be raised. + Constants are not cloned and if guassian process variables are detected then a warning will be triggered. + + Examples + -------- + .. code-block:: python + + import pymc as pm + import copy + + with pm.Model() as m: + p = pm.Beta("p", 1, 1) + x = pm.Bernoulli("x", p=p, shape=(3,)) + + clone_m = copy.copy(m) + + # Access cloned variables by name + clone_x = clone_m["x"] + + # z will be part of clone_m but not m + z = pm.Deterministic("z", clone_x + 1) """ from pymc.model.fgraph import clone_model - check_for_gp_vars = [ - k for x in ["_rotated_", "_hsgp_coeffs_"] for k in self.named_vars.keys() if x in k - ] - if len(check_for_gp_vars) > 0: - raise Exception("Unable to clone Gaussian Process Variables") - return clone_model(self) def __deepcopy__(self, _): """ Clone a pymc model by overiding the python copy method using the clone_model method from fgraph. - if guassian process variables are detected then an exception will be raised. + Constants are not cloned and if guassian process variables are detected then a warning will be triggered. + + Examples + -------- + .. code-block:: python + + import pymc as pm + import copy + + with pm.Model() as m: + p = pm.Beta("p", 1, 1) + x = pm.Bernoulli("x", p=p, shape=(3,)) + + clone_m = copy.deepcopy(m) + + # Access cloned variables by name + clone_x = clone_m["x"] + + # z will be part of clone_m but not m + z = pm.Deterministic("z", clone_x + 1) """ from pymc.model.fgraph import clone_model - check_for_gp_vars = [ - k for x in ["_rotated_", "_hsgp_coeffs_"] for k in self.named_vars.keys() if x in k - ] - if len(check_for_gp_vars) > 0: - raise Exception("Unable to clone Gaussian Process Variables") - return clone_model(self) def replace_rvs_by_values( diff --git a/pymc/model/fgraph.py b/pymc/model/fgraph.py index b1d67fd07b..b61ff06da3 100644 --- a/pymc/model/fgraph.py +++ b/pymc/model/fgraph.py @@ -11,6 +11,8 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import warnings + from copy import copy, deepcopy import pytensor @@ -369,7 +371,7 @@ def clone_model(model: Model) -> Model: Recreates a PyMC model with clones of the original variables. Shared variables will point to the same container but be otherwise different objects. - Constants are not cloned. + Constants are not cloned and if guassian process variables are detected then a warning will be triggered. Examples @@ -391,6 +393,11 @@ def clone_model(model: Model) -> Model: z = pm.Deterministic("z", clone_x + 1) """ + check_for_gp_vars = [ + k for x in ["_rotated_", "_hsgp_coeffs_"] for k in model.named_vars.keys() if x in k + ] + if len(check_for_gp_vars) > 0: + warnings.warn("Unable to clone Gaussian Process Variables", UserWarning) return model_from_fgraph(fgraph_from_model(model)[0], mutate_fgraph=True) diff --git a/tests/model/test_core.py b/tests/model/test_core.py index 747040ecdc..eaf711ab39 100644 --- a/tests/model/test_core.py +++ b/tests/model/test_core.py @@ -1764,7 +1764,7 @@ def test_graphviz_call_function(self, var_names, filenames) -> None: ) -class TestModelCopy(unittest.TestCase): +class TestModelCopy: @staticmethod def simple_model() -> pm.Model: with pm.Model() as simple_model: @@ -1772,7 +1772,7 @@ def simple_model() -> pm.Model: alpha = pm.Normal("alpha", 0, 1) pm.Normal("y", alpha, error) return simple_model - + @staticmethod def gp_model() -> pm.Model: with pm.Model() as gp_model: @@ -1782,7 +1782,7 @@ def gp_model() -> pm.Model: f = gp.prior("f", X=np.arange(10)[:, None]) pm.Normal("y", f * 2) return gp_model - + def test_copy_model(self) -> None: simple_model = self.simple_model() copy_simple_model = copy.copy(simple_model) @@ -1797,17 +1797,27 @@ def test_copy_model(self) -> None: with deepcopy_simple_model: deepcopy_simple_model_prior_predictive = pm.sample_prior_predictive(random_seed=42) - simple_model_prior_predictive_mean = simple_model_prior_predictive['prior']['y'].mean(('chain', 'draw')) - copy_simple_model_prior_predictive_mean = copy_simple_model_prior_predictive['prior']['y'].mean(('chain', 'draw')) - deepcopy_simple_model_prior_predictive_mean = deepcopy_simple_model_prior_predictive['prior']['y'].mean(('chain', 'draw')) + simple_model_prior_predictive_mean = simple_model_prior_predictive["prior"]["y"].mean( + ("chain", "draw") + ) + copy_simple_model_prior_predictive_mean = copy_simple_model_prior_predictive["prior"][ + "y" + ].mean(("chain", "draw")) + deepcopy_simple_model_prior_predictive_mean = deepcopy_simple_model_prior_predictive[ + "prior" + ]["y"].mean(("chain", "draw")) - assert np.isclose(simple_model_prior_predictive_mean, copy_simple_model_prior_predictive_mean) - assert np.isclose(simple_model_prior_predictive_mean, deepcopy_simple_model_prior_predictive_mean) + assert np.isclose( + simple_model_prior_predictive_mean, copy_simple_model_prior_predictive_mean + ) + assert np.isclose( + simple_model_prior_predictive_mean, deepcopy_simple_model_prior_predictive_mean + ) def test_guassian_process_copy_failure(self) -> None: gaussian_process_model = self.gp_model() - with pytest.raises(Exception) as e: + with pytest.warns(UserWarning): copy.copy(gaussian_process_model) - - with pytest.raises(Exception) as e: - copy.deepcopy(gaussian_process_model) \ No newline at end of file + + with pytest.warns(UserWarning): + copy.deepcopy(gaussian_process_model) From 33c57665c73d69d4f506a5010441f8f23922a1e4 Mon Sep 17 00:00:00 2001 From: Jonathan Dekermanjian Date: Sun, 8 Sep 2024 11:42:59 -0600 Subject: [PATCH 4/9] moved gaussian process checking from clone_model to lower level fgraph_from_model --- pymc/model/fgraph.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pymc/model/fgraph.py b/pymc/model/fgraph.py index b61ff06da3..400ee728f5 100644 --- a/pymc/model/fgraph.py +++ b/pymc/model/fgraph.py @@ -160,6 +160,12 @@ def fgraph_from_model( "Nested sub-models cannot be converted to fgraph. Convert the parent model instead" ) + check_for_gp_vars = [ + k for x in ["_rotated_", "_hsgp_coeffs_"] for k in model.named_vars.keys() if x in k + ] + if len(check_for_gp_vars) > 0: + warnings.warn("Unable to clone Gaussian Process Variables", UserWarning) + # Collect PyTensor variables rvs_to_values = model.rvs_to_values rvs = list(rvs_to_values.keys()) @@ -393,11 +399,6 @@ def clone_model(model: Model) -> Model: z = pm.Deterministic("z", clone_x + 1) """ - check_for_gp_vars = [ - k for x in ["_rotated_", "_hsgp_coeffs_"] for k in model.named_vars.keys() if x in k - ] - if len(check_for_gp_vars) > 0: - warnings.warn("Unable to clone Gaussian Process Variables", UserWarning) return model_from_fgraph(fgraph_from_model(model)[0], mutate_fgraph=True) From 88fde25269c9b27495135f35a4b10f6335a49c9f Mon Sep 17 00:00:00 2001 From: Jonathan Dekermanjian Date: Sat, 28 Sep 2024 17:00:47 -0600 Subject: [PATCH 5/9] simplified conditional for GP variables in fgraph and reverted documentation for clone_model function --- pymc/model/fgraph.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pymc/model/fgraph.py b/pymc/model/fgraph.py index 400ee728f5..8c37861c8f 100644 --- a/pymc/model/fgraph.py +++ b/pymc/model/fgraph.py @@ -160,11 +160,13 @@ def fgraph_from_model( "Nested sub-models cannot be converted to fgraph. Convert the parent model instead" ) - check_for_gp_vars = [ - k for x in ["_rotated_", "_hsgp_coeffs_"] for k in model.named_vars.keys() if x in k - ] - if len(check_for_gp_vars) > 0: - warnings.warn("Unable to clone Gaussian Process Variables", UserWarning) + if any( + ("_rotated_" in var_name or "_hsgp_coeffs_" in var_name) for var_name in model.named_vars + ): + warnings.warn( + "Detected variables likely created by GP objects. Further use of these old GP objects should be avoided as it may reintroduce variables from the old model. See issue: https://github.com/pymc-devs/pymc/issues/6883", + UserWarning, + ) # Collect PyTensor variables rvs_to_values = model.rvs_to_values @@ -377,7 +379,7 @@ def clone_model(model: Model) -> Model: Recreates a PyMC model with clones of the original variables. Shared variables will point to the same container but be otherwise different objects. - Constants are not cloned and if guassian process variables are detected then a warning will be triggered. + Constants are not cloned. Examples From 90419cb338b7a6ed4b35b2d0063af1aa6d8ee1e2 Mon Sep 17 00:00:00 2001 From: Jonathan Dekermanjian Date: Sun, 29 Sep 2024 04:54:09 -0600 Subject: [PATCH 6/9] parametrized tests to be more efficient, added test for adding deterministics to clone model, added copy method to Model class --- pymc/model/core.py | 32 ++++----------------- tests/model/test_core.py | 61 ++++++++++++++++++++-------------------- 2 files changed, 36 insertions(+), 57 deletions(-) diff --git a/pymc/model/core.py b/pymc/model/core.py index bd62fa4369..9235524157 100644 --- a/pymc/model/core.py +++ b/pymc/model/core.py @@ -1572,34 +1572,12 @@ def __contains__(self, key): return key in self.named_vars or self.name_for(key) in self.named_vars def __copy__(self): - """ - Clone a pymc model by overiding the python copy method using the clone_model method from fgraph. - Constants are not cloned and if guassian process variables are detected then a warning will be triggered. - - Examples - -------- - .. code-block:: python - - import pymc as pm - import copy - - with pm.Model() as m: - p = pm.Beta("p", 1, 1) - x = pm.Bernoulli("x", p=p, shape=(3,)) - - clone_m = copy.copy(m) - - # Access cloned variables by name - clone_x = clone_m["x"] - - # z will be part of clone_m but not m - z = pm.Deterministic("z", clone_x + 1) - """ - from pymc.model.fgraph import clone_model - - return clone_model(self) + return self.copy() def __deepcopy__(self, _): + return self.copy() + + def copy(self): """ Clone a pymc model by overiding the python copy method using the clone_model method from fgraph. Constants are not cloned and if guassian process variables are detected then a warning will be triggered. @@ -1615,7 +1593,7 @@ def __deepcopy__(self, _): p = pm.Beta("p", 1, 1) x = pm.Bernoulli("x", p=p, shape=(3,)) - clone_m = copy.deepcopy(m) + clone_m = copy.copy(m) # Access cloned variables by name clone_x = clone_m["x"] diff --git a/tests/model/test_core.py b/tests/model/test_core.py index eaf711ab39..61e502d6cd 100644 --- a/tests/model/test_core.py +++ b/tests/model/test_core.py @@ -1773,29 +1773,18 @@ def simple_model() -> pm.Model: pm.Normal("y", alpha, error) return simple_model - @staticmethod - def gp_model() -> pm.Model: - with pm.Model() as gp_model: - ell = pm.Gamma("ell", alpha=2, beta=1) - cov = 2 * pm.gp.cov.ExpQuad(1, ell) - gp = pm.gp.Latent(cov_func=cov) - f = gp.prior("f", X=np.arange(10)[:, None]) - pm.Normal("y", f * 2) - return gp_model - - def test_copy_model(self) -> None: + @pytest.mark.parametrize("copy_method", (copy.copy, copy.deepcopy)) + def test_copy_model(self, copy_method) -> None: simple_model = self.simple_model() - copy_simple_model = copy.copy(simple_model) - deepcopy_simple_model = copy.deepcopy(simple_model) + copy_simple_model = copy_method(simple_model) with simple_model: - simple_model_prior_predictive = pm.sample_prior_predictive(random_seed=42) + simple_model_prior_predictive = pm.sample_prior_predictive(samples=1, random_seed=42) with copy_simple_model: - copy_simple_model_prior_predictive = pm.sample_prior_predictive(random_seed=42) - - with deepcopy_simple_model: - deepcopy_simple_model_prior_predictive = pm.sample_prior_predictive(random_seed=42) + copy_simple_model_prior_predictive = pm.sample_prior_predictive( + samples=1, random_seed=42 + ) simple_model_prior_predictive_mean = simple_model_prior_predictive["prior"]["y"].mean( ("chain", "draw") @@ -1803,21 +1792,33 @@ def test_copy_model(self) -> None: copy_simple_model_prior_predictive_mean = copy_simple_model_prior_predictive["prior"][ "y" ].mean(("chain", "draw")) - deepcopy_simple_model_prior_predictive_mean = deepcopy_simple_model_prior_predictive[ - "prior" - ]["y"].mean(("chain", "draw")) assert np.isclose( simple_model_prior_predictive_mean, copy_simple_model_prior_predictive_mean ) - assert np.isclose( - simple_model_prior_predictive_mean, deepcopy_simple_model_prior_predictive_mean - ) - def test_guassian_process_copy_failure(self) -> None: - gaussian_process_model = self.gp_model() - with pytest.warns(UserWarning): - copy.copy(gaussian_process_model) + @pytest.mark.parametrize("copy_method", (copy.copy, copy.deepcopy)) + def test_guassian_process_copy_failure(self, copy_method) -> None: + with pm.Model() as gaussian_process_model: + ell = pm.Gamma("ell", alpha=2, beta=1) + cov = 2 * pm.gp.cov.ExpQuad(1, ell) + gp = pm.gp.Latent(cov_func=cov) + f = gp.prior("f", X=np.arange(10)[:, None]) + pm.Normal("y", f * 2) + + with pytest.warns( + UserWarning, + match="Detected variables likely created by GP objects. Further use of these old GP objects should be avoided as it may reintroduce variables from the old model. See issue: https://github.com/pymc-devs/pymc/issues/6883", + ): + copy_method(gaussian_process_model) + + @pytest.mark.parametrize("copy_method", (copy.copy, copy.deepcopy)) + def test_adding_deterministics_to_clone(self, copy_method) -> None: + simple_model = self.simple_model() + clone_model = copy_method(simple_model) + + with clone_model: + z = pm.Deterministic("z", clone_model["alpha"] + 1) - with pytest.warns(UserWarning): - copy.deepcopy(gaussian_process_model) + assert "z" in clone_model.named_vars + assert "z" not in simple_model.named_vars From 07106ec26860a156525db0350291401fb61a6fb4 Mon Sep 17 00:00:00 2001 From: Jonathan Dekermanjian Date: Mon, 30 Sep 2024 06:31:41 -0600 Subject: [PATCH 7/9] updated copy method docs and simplified TestModelCopy tests --- pymc/model/core.py | 5 +++-- tests/model/test_core.py | 42 +++++++++++++++++----------------------- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/pymc/model/core.py b/pymc/model/core.py index 9235524157..0d3ad555ed 100644 --- a/pymc/model/core.py +++ b/pymc/model/core.py @@ -1579,8 +1579,9 @@ def __deepcopy__(self, _): def copy(self): """ - Clone a pymc model by overiding the python copy method using the clone_model method from fgraph. - Constants are not cloned and if guassian process variables are detected then a warning will be triggered. + Clone the model + + To access variables in the cloned model use `cloned_model["var_name"]`. Examples -------- diff --git a/tests/model/test_core.py b/tests/model/test_core.py index 61e502d6cd..6678af3b17 100644 --- a/tests/model/test_core.py +++ b/tests/model/test_core.py @@ -1765,17 +1765,13 @@ def test_graphviz_call_function(self, var_names, filenames) -> None: class TestModelCopy: - @staticmethod - def simple_model() -> pm.Model: + @pytest.mark.parametrize("copy_method", (copy.copy, copy.deepcopy)) + def test_copy_model(self, copy_method) -> None: with pm.Model() as simple_model: error = pm.HalfNormal("error", 0.5) alpha = pm.Normal("alpha", 0, 1) pm.Normal("y", alpha, error) - return simple_model - @pytest.mark.parametrize("copy_method", (copy.copy, copy.deepcopy)) - def test_copy_model(self, copy_method) -> None: - simple_model = self.simple_model() copy_simple_model = copy_method(simple_model) with simple_model: @@ -1786,15 +1782,24 @@ def test_copy_model(self, copy_method) -> None: samples=1, random_seed=42 ) - simple_model_prior_predictive_mean = simple_model_prior_predictive["prior"]["y"].mean( - ("chain", "draw") - ) - copy_simple_model_prior_predictive_mean = copy_simple_model_prior_predictive["prior"][ + simple_model_prior_predictive_val = simple_model_prior_predictive["prior"]["y"].values + copy_simple_model_prior_predictive_val = copy_simple_model_prior_predictive["prior"][ "y" - ].mean(("chain", "draw")) + ].values - assert np.isclose( - simple_model_prior_predictive_mean, copy_simple_model_prior_predictive_mean + assert simple_model_prior_predictive_val == copy_simple_model_prior_predictive_val + + with copy_simple_model: + z = pm.Deterministic("z", copy_simple_model["alpha"] + 1) + copy_simple_model_prior_predictive = pm.sample_prior_predictive( + samples=1, random_seed=42 + ) + + assert "z" in copy_simple_model.named_vars + assert "z" not in simple_model.named_vars + assert ( + copy_simple_model_prior_predictive["prior"]["z"].values + == 1 + copy_simple_model_prior_predictive["prior"]["alpha"].values ) @pytest.mark.parametrize("copy_method", (copy.copy, copy.deepcopy)) @@ -1811,14 +1816,3 @@ def test_guassian_process_copy_failure(self, copy_method) -> None: match="Detected variables likely created by GP objects. Further use of these old GP objects should be avoided as it may reintroduce variables from the old model. See issue: https://github.com/pymc-devs/pymc/issues/6883", ): copy_method(gaussian_process_model) - - @pytest.mark.parametrize("copy_method", (copy.copy, copy.deepcopy)) - def test_adding_deterministics_to_clone(self, copy_method) -> None: - simple_model = self.simple_model() - clone_model = copy_method(simple_model) - - with clone_model: - z = pm.Deterministic("z", clone_model["alpha"] + 1) - - assert "z" in clone_model.named_vars - assert "z" not in simple_model.named_vars From fb00f85dc0c9be5189b826e1fae9c59d8c158f84 Mon Sep 17 00:00:00 2001 From: Jonathan Dekermanjian Date: Mon, 30 Sep 2024 15:21:24 -0600 Subject: [PATCH 8/9] shortened TestModelCopy by removing assigned variables before comparison --- tests/model/test_core.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/model/test_core.py b/tests/model/test_core.py index 6678af3b17..03dd35ca9a 100644 --- a/tests/model/test_core.py +++ b/tests/model/test_core.py @@ -1782,12 +1782,10 @@ def test_copy_model(self, copy_method) -> None: samples=1, random_seed=42 ) - simple_model_prior_predictive_val = simple_model_prior_predictive["prior"]["y"].values - copy_simple_model_prior_predictive_val = copy_simple_model_prior_predictive["prior"][ - "y" - ].values - - assert simple_model_prior_predictive_val == copy_simple_model_prior_predictive_val + assert ( + simple_model_prior_predictive["prior"]["y"].values + == copy_simple_model_prior_predictive["prior"]["y"].values + ) with copy_simple_model: z = pm.Deterministic("z", copy_simple_model["alpha"] + 1) From d057a9d35467f28b53164fdc628dce1b9a39fa2a Mon Sep 17 00:00:00 2001 From: Jonathan Dekermanjian Date: Wed, 2 Oct 2024 06:04:10 -0600 Subject: [PATCH 9/9] simplified model in TestModelCopy --- tests/model/test_core.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/tests/model/test_core.py b/tests/model/test_core.py index 03dd35ca9a..cea9edf647 100644 --- a/tests/model/test_core.py +++ b/tests/model/test_core.py @@ -1768,9 +1768,7 @@ class TestModelCopy: @pytest.mark.parametrize("copy_method", (copy.copy, copy.deepcopy)) def test_copy_model(self, copy_method) -> None: with pm.Model() as simple_model: - error = pm.HalfNormal("error", 0.5) - alpha = pm.Normal("alpha", 0, 1) - pm.Normal("y", alpha, error) + pm.Normal("y") copy_simple_model = copy_method(simple_model) @@ -1778,6 +1776,7 @@ def test_copy_model(self, copy_method) -> None: simple_model_prior_predictive = pm.sample_prior_predictive(samples=1, random_seed=42) with copy_simple_model: + z = pm.Deterministic("z", copy_simple_model["y"] + 1) copy_simple_model_prior_predictive = pm.sample_prior_predictive( samples=1, random_seed=42 ) @@ -1787,17 +1786,11 @@ def test_copy_model(self, copy_method) -> None: == copy_simple_model_prior_predictive["prior"]["y"].values ) - with copy_simple_model: - z = pm.Deterministic("z", copy_simple_model["alpha"] + 1) - copy_simple_model_prior_predictive = pm.sample_prior_predictive( - samples=1, random_seed=42 - ) - assert "z" in copy_simple_model.named_vars assert "z" not in simple_model.named_vars assert ( copy_simple_model_prior_predictive["prior"]["z"].values - == 1 + copy_simple_model_prior_predictive["prior"]["alpha"].values + == 1 + simple_model_prior_predictive["prior"]["y"].values ) @pytest.mark.parametrize("copy_method", (copy.copy, copy.deepcopy))