|
12 | 12 | # See the License for the specific language governing permissions and
|
13 | 13 | # limitations under the License.
|
14 | 14 | import unittest
|
| 15 | +import warnings |
15 | 16 |
|
16 | 17 | from functools import reduce
|
17 | 18 |
|
@@ -704,25 +705,45 @@ def test_nested_model_coords():
|
704 | 705 | assert set(m2.RV_dims) < set(m1.RV_dims)
|
705 | 706 |
|
706 | 707 |
|
707 |
| -def test_shapeerror_from_resize_immutable_dims(): |
| 708 | +def test_shapeerror_from_set_data_dimensionality(): |
| 709 | + with pm.Model() as pmodel: |
| 710 | + pm.MutableData("m", np.ones((3,)), dims="one") |
| 711 | + with pytest.raises(ValueError, match="must have 1 dimensions"): |
| 712 | + pmodel.set_data("m", np.ones((3, 4))) |
| 713 | + |
| 714 | + |
| 715 | +def test_shapeerror_from_resize_immutable_dim_from_RV(): |
708 | 716 | """
|
709 | 717 | Trying to resize an immutable dimension should raise a ShapeError.
|
710 | 718 | Even if the variable being updated is a SharedVariable and has other
|
711 | 719 | dimensions that are mutable.
|
712 | 720 | """
|
713 | 721 | with pm.Model() as pmodel:
|
714 |
| - a = pm.Normal("a", mu=[1, 2, 3], dims="fixed") |
| 722 | + pm.Normal("a", mu=[1, 2, 3], dims="fixed") |
| 723 | + assert isinstance(pmodel.dim_lengths["fixed"], TensorVariable) |
715 | 724 |
|
716 |
| - m = pm.MutableData("m", [[1, 2, 3]], dims=("one", "fixed")) |
| 725 | + pm.MutableData("m", [[1, 2, 3]], dims=("one", "fixed")) |
717 | 726 |
|
718 | 727 | # This is fine because the "fixed" dim is not resized
|
719 |
| - pm.set_data({"m": [[1, 2, 3], [3, 4, 5]]}) |
| 728 | + pmodel.set_data("m", [[1, 2, 3], [3, 4, 5]]) |
720 | 729 |
|
721 | 730 | with pytest.raises(ShapeError, match="was initialized from 'a'"):
|
722 |
| - # Can't work because the "fixed" dimension is linked to a constant shape: |
| 731 | + # Can't work because the "fixed" dimension is linked to a |
| 732 | + # TensorVariable with constant shape. |
723 | 733 | # Note that the new data tries to change both dimensions
|
724 |
| - with pmodel: |
725 |
| - pm.set_data({"m": [[1, 2], [3, 4]]}) |
| 734 | + pmodel.set_data("m", [[1, 2], [3, 4]]) |
| 735 | + |
| 736 | + |
| 737 | +def test_shapeerror_from_resize_immutable_dim_from_coords(): |
| 738 | + with pm.Model(coords={"immutable": [1, 2]}) as pmodel: |
| 739 | + assert isinstance(pmodel.dim_lengths["immutable"], TensorConstant) |
| 740 | + pm.MutableData("m", [1, 2], dims="immutable") |
| 741 | + # Data can be changed |
| 742 | + pmodel.set_data("m", [3, 4]) |
| 743 | + |
| 744 | + with pytest.raises(ShapeError, match="`TensorConstant` stores its length"): |
| 745 | + # But the length is linked to a TensorConstant |
| 746 | + pmodel.set_data("m", [1, 2, 3], coords=dict(immutable=[1, 2, 3])) |
726 | 747 |
|
727 | 748 |
|
728 | 749 | def test_valueerror_from_resize_without_coords_update():
|
@@ -798,22 +819,65 @@ def test_set_dim_with_coords():
|
798 | 819 | assert pmodel.coords["mdim"] == ("A", "B", "C")
|
799 | 820 |
|
800 | 821 |
|
801 |
| -def test_set_data_warns_resize_mutable_dim(): |
| 822 | +def test_set_data_indirect_resize(): |
802 | 823 | with pm.Model() as pmodel:
|
803 | 824 | pmodel.add_coord("mdim", mutable=True, length=2)
|
804 | 825 | pm.MutableData("mdata", [1, 2], dims="mdim")
|
805 | 826 |
|
806 | 827 | # First resize the dimension.
|
807 | 828 | pmodel.dim_lengths["mdim"].set_value(3)
|
808 | 829 | # Then change the data.
|
809 |
| - pmodel.set_data("mdata", [1, 2, 3]) |
| 830 | + with warnings.catch_warnings(): |
| 831 | + warnings.simplefilter("error") |
| 832 | + pmodel.set_data("mdata", [1, 2, 3]) |
810 | 833 |
|
811 | 834 | # Now the other way around.
|
812 |
| - # Because the dimension doesn't depend on the data variable, |
813 |
| - # a warning shoudl be emitted. |
814 |
| - with pytest.warns(ShapeWarning, match="update the dimension length"): |
| 835 | + with warnings.catch_warnings(): |
| 836 | + warnings.simplefilter("error") |
815 | 837 | pmodel.set_data("mdata", [1, 2, 3, 4])
|
816 |
| - pass |
| 838 | + |
| 839 | + |
| 840 | +def test_set_data_warns_on_resize_of_dims_defined_by_other_mutabledata(): |
| 841 | + with pm.Model() as pmodel: |
| 842 | + pm.MutableData("m1", [1, 2], dims="mutable") |
| 843 | + pm.MutableData("m2", [3, 4], dims="mutable") |
| 844 | + |
| 845 | + # Resizing the non-defining variable first gives a warning |
| 846 | + with pytest.warns(ShapeWarning, match="by another variable"): |
| 847 | + pmodel.set_data("m2", [4, 5, 6]) |
| 848 | + pmodel.set_data("m1", [1, 2, 3]) |
| 849 | + |
| 850 | + # Resizing the definint variable first is silent |
| 851 | + with warnings.catch_warnings(): |
| 852 | + warnings.simplefilter("error") |
| 853 | + pmodel.set_data("m1", [1, 2]) |
| 854 | + pmodel.set_data("m2", [3, 4]) |
| 855 | + |
| 856 | + |
| 857 | +def test_set_data_indirect_resize_with_coords(): |
| 858 | + with pm.Model() as pmodel: |
| 859 | + pmodel.add_coord("mdim", ["A", "B"], mutable=True, length=2) |
| 860 | + pm.MutableData("mdata", [1, 2], dims="mdim") |
| 861 | + |
| 862 | + assert pmodel.coords["mdim"] == ("A", "B") |
| 863 | + |
| 864 | + # First resize the dimension. |
| 865 | + pmodel.set_dim("mdim", 3, ["A", "B", "C"]) |
| 866 | + assert pmodel.coords["mdim"] == ("A", "B", "C") |
| 867 | + # Then change the data. |
| 868 | + with warnings.catch_warnings(): |
| 869 | + warnings.simplefilter("error") |
| 870 | + pmodel.set_data("mdata", [1, 2, 3]) |
| 871 | + |
| 872 | + # Now the other way around. |
| 873 | + with warnings.catch_warnings(): |
| 874 | + warnings.simplefilter("error") |
| 875 | + pmodel.set_data("mdata", [1, 2, 3, 4], coords=dict(mdim=["A", "B", "C", "D"])) |
| 876 | + assert pmodel.coords["mdim"] == ("A", "B", "C", "D") |
| 877 | + |
| 878 | + # This time with incorrectly sized coord values |
| 879 | + with pytest.raises(ShapeError, match="new coordinate values"): |
| 880 | + pmodel.set_data("mdata", [1, 2], coords=dict(mdim=[1, 2, 3])) |
817 | 881 |
|
818 | 882 |
|
819 | 883 | @pytest.mark.parametrize("jacobian", [True, False])
|
|
0 commit comments