From 5e0abe57fcba976f9bf51f428ec3c2c38962ece1 Mon Sep 17 00:00:00 2001 From: HarshvirSandhu Date: Sun, 4 Feb 2024 12:29:46 +0530 Subject: [PATCH 01/13] Refactor stacking functions, add dstack and column_stack --- pytensor/tensor/basic.py | 49 ++++++++++++++++------- tests/tensor/test_basic.py | 79 +++++++++++++++++++++++++++++++++----- 2 files changed, 105 insertions(+), 23 deletions(-) diff --git a/pytensor/tensor/basic.py b/pytensor/tensor/basic.py index c0a49c10e7..61113752c3 100644 --- a/pytensor/tensor/basic.py +++ b/pytensor/tensor/basic.py @@ -2758,14 +2758,8 @@ def concatenate(tensor_list, axis=0): return join(axis, *tensor_list) -def horizontal_stack(*args): +def hstack(*args): r"""Stack arrays in sequence horizontally (column wise).""" - # Note: 'horizontal_stack' and 'vertical_stack' do not behave exactly like - # Numpy's hstack and vstack functions. This is intended, because Numpy's - # functions have potentially confusing/incoherent behavior (try them on 1D - # arrays). If this is fixed in a future version of Numpy, it may be worth - # trying to get closer to Numpy's way of doing things. In the meantime, - # better keep different names to emphasize the implementation divergences. if len(args) < 2: raise ValueError("Too few arguments") @@ -2773,14 +2767,12 @@ def horizontal_stack(*args): _args = [] for arg in args: _arg = as_tensor_variable(arg) - if _arg.type.ndim != 2: - raise ValueError("All arguments must have two dimensions") _args.append(_arg) return concatenate(_args, axis=1) -def vertical_stack(*args): +def vstack(*args): r"""Stack arrays in sequence vertically (row wise).""" if len(args) < 2: @@ -2789,12 +2781,39 @@ def vertical_stack(*args): _args = [] for arg in args: _arg = as_tensor_variable(arg) - if _arg.type.ndim != 2: - raise ValueError("All arguments must have two dimensions") _args.append(_arg) return concatenate(_args, axis=0) +def dstack(*args): + r"""Stack arrays in sequence along third axis (depth wise).""" + + if len(args) < 2: + raise ValueError("Too few arguments") + + _args = [] + for arg in args: + _arg = as_tensor_variable(arg) + if _arg.type.ndim != 3: + raise ValueError("All arguments must have three dimensions") + _args.append(_arg) + + return concatenate(_args, axis=2) + +def column_stack(*args): + r"""Stack 1-D arrays as columns into a 2-D array.""" + + if len(args) < 2: + raise ValueError("Too few arguments") + + _args = [] + for arg in args: + _arg = as_tensor_variable(arg) + if _arg.type.ndim < 2: + _arg = atleast_2d(_arg).transpose() + _args.append(_arg) + + return concatenate(_args, axis=1) def is_flat(var, ndim=1): """ @@ -4298,8 +4317,10 @@ def ix_(*args): "tile", "flatten", "is_flat", - "vertical_stack", - "horizontal_stack", + "vstack", + "hstack", + "dstack", + "column_stack", "get_vector_length", "concatenate", "stack", diff --git a/tests/tensor/test_basic.py b/tests/tensor/test_basic.py index d5452112a4..360840246c 100644 --- a/tests/tensor/test_basic.py +++ b/tests/tensor/test_basic.py @@ -54,7 +54,7 @@ get_scalar_constant_value, get_underlying_scalar_constant_value, get_vector_length, - horizontal_stack, + hstack, identity_like, infer_static_shape, inverse_permutation, @@ -85,7 +85,9 @@ triu, triu_indices, triu_indices_from, - vertical_stack, + dstack, + vstack, + column_stack, zeros_like, ) from pytensor.tensor.blockwise import Blockwise @@ -1667,24 +1669,64 @@ def test_join_matrix_ints(self): assert (np.asarray(grad(s.sum(), b).eval()) == 0).all() assert (np.asarray(grad(s.sum(), a).eval()) == 0).all() - def test_join_matrix1_using_vertical_stack(self): + def test_join_matrix1_using_vstack(self): a = self.shared(np.array([[1, 2, 3], [4, 5, 6]], dtype=self.floatX)) b = as_tensor_variable(np.array([[7, 8, 9]], dtype=self.floatX)) c = as_tensor_variable(np.array([[9, 8, 7]], dtype=self.floatX)) - s = vertical_stack(a, b, c) + s = vstack(a, b, c) want = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [9, 8, 7]]) out = self.eval_outputs_and_check_join([s]) assert (out == want).all() + + def test_join_matrix1_using_dstack(self): + a = self.shared(np.array( + [ + [[0.1], [0.2], [0.3]], + [[0.4], [0.5], [0.6]] + ], + dtype="float32")) + + b = as_tensor_variable(np.array( + [[[0.2, 0.3], + [0.3, 0.4], + [0.4, 0.5], ], + [[0.5, 0.6], + [0.6, 0.7], + [0.7, 0.8]]], + dtype="float32")) + + c = as_tensor_variable(np.array( + [ + [[0.4], [0.5], [0.6]], + [[0.7], [0.8], [0.9]] + ], + dtype="float32")) + + s = dstack(a, b, c) - def test_join_matrix1_using_horizontal_stack(self): + want = np.array( + [[[0.1, 0.2, 0.3, 0.4], + [0.2, 0.3, 0.4, 0.5], + [0.3, 0.4, 0.5, 0.6]], + + [[0.4, 0.5, 0.6, 0.7], + [0.5, 0.6, 0.7, 0.8], + [0.6, 0.7, 0.8, 0.9]]], + dtype="float32") + + out = self.eval_outputs_and_check_join([s]) + assert (out == want).all() + + + def test_join_matrix1_using_hstack(self): av = np.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]], dtype="float32") bv = np.array([[0.7], [0.8]], dtype="float32") cv = np.array([[0.3, 0.2, 0.1], [0.6, 0.5, 0.4]], dtype="float32") a = self.shared(av) b = as_tensor_variable(bv) c = as_tensor_variable(cv) - s = horizontal_stack(a, b, c) + s = hstack(a, b, c) want = np.array( [[0.1, 0.2, 0.3, 0.7, 0.3, 0.2, 0.1], [0.4, 0.5, 0.6, 0.8, 0.6, 0.5, 0.4]], dtype="float32", @@ -1694,6 +1736,20 @@ def test_join_matrix1_using_horizontal_stack(self): utt.verify_grad(lambda a, b: join(1, a, b), [av, bv], mode=self.mode) + def test_join_matrix1_using_column_stack(self): + av = np.array([0.1, 0.2, 0.3], dtype="float32") + bv = np.array([0.7, 0.8, 0.9], dtype="float32") + a = self.shared(av) + b = as_tensor_variable(bv) + s = column_stack(a, b) + want = np.array( + [[0.1, 0.7],[0.2, 0.8],[0.3, 0.9]], + dtype="float32", + ) + out = self.eval_outputs_and_check_join([s]) + assert (out == want).all() + + def test_join_matrixV(self): # variable join axis v = np.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]], dtype=self.floatX) @@ -4489,16 +4545,21 @@ def test_full_like(inp, shape): ) -@pytest.mark.parametrize("func", [horizontal_stack, vertical_stack]) +@pytest.mark.parametrize("func", [hstack, vstack, column_stack]) def test_oriented_stack_functions(func): with pytest.raises(ValueError): func() - a = ptb.tensor(dtype=np.float64, shape=(None, None, None)) +@pytest.mark.parametrize("func", [dstack]) +def test_dstack_function(func): with pytest.raises(ValueError): - func(a, a) + func() + + a = ptb.tensor(dtype=np.float64, shape=(None, None)) + with pytest.raises(ValueError): + func(a, a) def test_trace(): x_val = np.ones((5, 4, 2)) From 2d7617e1cd455945260ab4fdf974cbb817046d54 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 4 Feb 2024 07:18:29 +0000 Subject: [PATCH 02/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pytensor/tensor/basic.py | 3 ++ tests/tensor/test_basic.py | 72 ++++++++++++++++++-------------------- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/pytensor/tensor/basic.py b/pytensor/tensor/basic.py index 61113752c3..eb75177d3f 100644 --- a/pytensor/tensor/basic.py +++ b/pytensor/tensor/basic.py @@ -2785,6 +2785,7 @@ def vstack(*args): return concatenate(_args, axis=0) + def dstack(*args): r"""Stack arrays in sequence along third axis (depth wise).""" @@ -2800,6 +2801,7 @@ def dstack(*args): return concatenate(_args, axis=2) + def column_stack(*args): r"""Stack 1-D arrays as columns into a 2-D array.""" @@ -2815,6 +2817,7 @@ def column_stack(*args): return concatenate(_args, axis=1) + def is_flat(var, ndim=1): """ Verifies the dimensionality of the var is equal to diff --git a/tests/tensor/test_basic.py b/tests/tensor/test_basic.py index 360840246c..baf1b712df 100644 --- a/tests/tensor/test_basic.py +++ b/tests/tensor/test_basic.py @@ -41,9 +41,11 @@ atleast_Nd, cast, choose, + column_stack, constant, default, diag, + dstack, expand_dims, extract_constant, eye, @@ -85,9 +87,7 @@ triu, triu_indices, triu_indices_from, - dstack, vstack, - column_stack, zeros_like, ) from pytensor.tensor.blockwise import Blockwise @@ -1678,46 +1678,42 @@ def test_join_matrix1_using_vstack(self): want = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [9, 8, 7]]) out = self.eval_outputs_and_check_join([s]) assert (out == want).all() - + def test_join_matrix1_using_dstack(self): - a = self.shared(np.array( - [ - [[0.1], [0.2], [0.3]], - [[0.4], [0.5], [0.6]] - ], - dtype="float32")) - - b = as_tensor_variable(np.array( - [[[0.2, 0.3], - [0.3, 0.4], - [0.4, 0.5], ], - [[0.5, 0.6], - [0.6, 0.7], - [0.7, 0.8]]], - dtype="float32")) - - c = as_tensor_variable(np.array( - [ - [[0.4], [0.5], [0.6]], - [[0.7], [0.8], [0.9]] - ], - dtype="float32")) - + a = self.shared( + np.array([[[0.1], [0.2], [0.3]], [[0.4], [0.5], [0.6]]], dtype="float32") + ) + + b = as_tensor_variable( + np.array( + [ + [ + [0.2, 0.3], + [0.3, 0.4], + [0.4, 0.5], + ], + [[0.5, 0.6], [0.6, 0.7], [0.7, 0.8]], + ], + dtype="float32", + ) + ) + + c = as_tensor_variable( + np.array([[[0.4], [0.5], [0.6]], [[0.7], [0.8], [0.9]]], dtype="float32") + ) + s = dstack(a, b, c) want = np.array( - [[[0.1, 0.2, 0.3, 0.4], - [0.2, 0.3, 0.4, 0.5], - [0.3, 0.4, 0.5, 0.6]], - - [[0.4, 0.5, 0.6, 0.7], - [0.5, 0.6, 0.7, 0.8], - [0.6, 0.7, 0.8, 0.9]]], - dtype="float32") - + [ + [[0.1, 0.2, 0.3, 0.4], [0.2, 0.3, 0.4, 0.5], [0.3, 0.4, 0.5, 0.6]], + [[0.4, 0.5, 0.6, 0.7], [0.5, 0.6, 0.7, 0.8], [0.6, 0.7, 0.8, 0.9]], + ], + dtype="float32", + ) + out = self.eval_outputs_and_check_join([s]) assert (out == want).all() - def test_join_matrix1_using_hstack(self): av = np.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]], dtype="float32") @@ -1743,13 +1739,12 @@ def test_join_matrix1_using_column_stack(self): b = as_tensor_variable(bv) s = column_stack(a, b) want = np.array( - [[0.1, 0.7],[0.2, 0.8],[0.3, 0.9]], + [[0.1, 0.7], [0.2, 0.8], [0.3, 0.9]], dtype="float32", ) out = self.eval_outputs_and_check_join([s]) assert (out == want).all() - def test_join_matrixV(self): # variable join axis v = np.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]], dtype=self.floatX) @@ -4561,6 +4556,7 @@ def test_dstack_function(func): with pytest.raises(ValueError): func(a, a) + def test_trace(): x_val = np.ones((5, 4, 2)) x = ptb.as_tensor(x_val) From 1fc5e23a209c00079aaa6d9968092df8c804a7d5 Mon Sep 17 00:00:00 2001 From: HarshvirSandhu Date: Sun, 4 Feb 2024 21:30:12 +0530 Subject: [PATCH 03/13] Add FutureWarning --- pytensor/tensor/basic.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pytensor/tensor/basic.py b/pytensor/tensor/basic.py index 61113752c3..cd2687577c 100644 --- a/pytensor/tensor/basic.py +++ b/pytensor/tensor/basic.py @@ -2785,6 +2785,17 @@ def vstack(*args): return concatenate(_args, axis=0) + +def horizontal_stack(*args): + warnings.warn("horizontal_stack was renamed to hstack and will be removed in a future release", FutureWarning) + return hstack(*args) + + +def vertical_stack(*args): + warnings.warn("vertical_stack was renamed to vstack and will be removed in a future release", FutureWarning) + return vstack(*args) + + def dstack(*args): r"""Stack arrays in sequence along third axis (depth wise).""" From 7c5b094d74e0eaf7688e9b012a0878fa8b3a2cb5 Mon Sep 17 00:00:00 2001 From: HarshvirSandhu Date: Sun, 4 Feb 2024 21:39:23 +0530 Subject: [PATCH 04/13] Add FutureWarning --- pytensor/tensor/basic.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pytensor/tensor/basic.py b/pytensor/tensor/basic.py index cd2687577c..cfae5a2a22 100644 --- a/pytensor/tensor/basic.py +++ b/pytensor/tensor/basic.py @@ -2796,6 +2796,7 @@ def vertical_stack(*args): return vstack(*args) + def dstack(*args): r"""Stack arrays in sequence along third axis (depth wise).""" @@ -2811,6 +2812,7 @@ def dstack(*args): return concatenate(_args, axis=2) + def column_stack(*args): r"""Stack 1-D arrays as columns into a 2-D array.""" @@ -2826,6 +2828,7 @@ def column_stack(*args): return concatenate(_args, axis=1) + def is_flat(var, ndim=1): """ Verifies the dimensionality of the var is equal to From fe9e2dadd5a3c45c3c4d73c85bd97bee0bab74a6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 4 Feb 2024 16:17:08 +0000 Subject: [PATCH 05/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pytensor/tensor/basic.py | 16 +++++---- tests/tensor/test_basic.py | 72 ++++++++++++++++++-------------------- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/pytensor/tensor/basic.py b/pytensor/tensor/basic.py index dfea40e968..3f21d57b5b 100644 --- a/pytensor/tensor/basic.py +++ b/pytensor/tensor/basic.py @@ -2787,15 +2787,19 @@ def vstack(*args): def horizontal_stack(*args): - warnings.warn("horizontal_stack was renamed to hstack and will be removed in a future release", FutureWarning) - return hstack(*args) + warnings.warn( + "horizontal_stack was renamed to hstack and will be removed in a future release", + FutureWarning, + ) + return hstack(*args) def vertical_stack(*args): - warnings.warn("vertical_stack was renamed to vstack and will be removed in a future release", FutureWarning) - return vstack(*args) - - + warnings.warn( + "vertical_stack was renamed to vstack and will be removed in a future release", + FutureWarning, + ) + return vstack(*args) def dstack(*args): diff --git a/tests/tensor/test_basic.py b/tests/tensor/test_basic.py index 360840246c..baf1b712df 100644 --- a/tests/tensor/test_basic.py +++ b/tests/tensor/test_basic.py @@ -41,9 +41,11 @@ atleast_Nd, cast, choose, + column_stack, constant, default, diag, + dstack, expand_dims, extract_constant, eye, @@ -85,9 +87,7 @@ triu, triu_indices, triu_indices_from, - dstack, vstack, - column_stack, zeros_like, ) from pytensor.tensor.blockwise import Blockwise @@ -1678,46 +1678,42 @@ def test_join_matrix1_using_vstack(self): want = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [9, 8, 7]]) out = self.eval_outputs_and_check_join([s]) assert (out == want).all() - + def test_join_matrix1_using_dstack(self): - a = self.shared(np.array( - [ - [[0.1], [0.2], [0.3]], - [[0.4], [0.5], [0.6]] - ], - dtype="float32")) - - b = as_tensor_variable(np.array( - [[[0.2, 0.3], - [0.3, 0.4], - [0.4, 0.5], ], - [[0.5, 0.6], - [0.6, 0.7], - [0.7, 0.8]]], - dtype="float32")) - - c = as_tensor_variable(np.array( - [ - [[0.4], [0.5], [0.6]], - [[0.7], [0.8], [0.9]] - ], - dtype="float32")) - + a = self.shared( + np.array([[[0.1], [0.2], [0.3]], [[0.4], [0.5], [0.6]]], dtype="float32") + ) + + b = as_tensor_variable( + np.array( + [ + [ + [0.2, 0.3], + [0.3, 0.4], + [0.4, 0.5], + ], + [[0.5, 0.6], [0.6, 0.7], [0.7, 0.8]], + ], + dtype="float32", + ) + ) + + c = as_tensor_variable( + np.array([[[0.4], [0.5], [0.6]], [[0.7], [0.8], [0.9]]], dtype="float32") + ) + s = dstack(a, b, c) want = np.array( - [[[0.1, 0.2, 0.3, 0.4], - [0.2, 0.3, 0.4, 0.5], - [0.3, 0.4, 0.5, 0.6]], - - [[0.4, 0.5, 0.6, 0.7], - [0.5, 0.6, 0.7, 0.8], - [0.6, 0.7, 0.8, 0.9]]], - dtype="float32") - + [ + [[0.1, 0.2, 0.3, 0.4], [0.2, 0.3, 0.4, 0.5], [0.3, 0.4, 0.5, 0.6]], + [[0.4, 0.5, 0.6, 0.7], [0.5, 0.6, 0.7, 0.8], [0.6, 0.7, 0.8, 0.9]], + ], + dtype="float32", + ) + out = self.eval_outputs_and_check_join([s]) assert (out == want).all() - def test_join_matrix1_using_hstack(self): av = np.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]], dtype="float32") @@ -1743,13 +1739,12 @@ def test_join_matrix1_using_column_stack(self): b = as_tensor_variable(bv) s = column_stack(a, b) want = np.array( - [[0.1, 0.7],[0.2, 0.8],[0.3, 0.9]], + [[0.1, 0.7], [0.2, 0.8], [0.3, 0.9]], dtype="float32", ) out = self.eval_outputs_and_check_join([s]) assert (out == want).all() - def test_join_matrixV(self): # variable join axis v = np.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]], dtype=self.floatX) @@ -4561,6 +4556,7 @@ def test_dstack_function(func): with pytest.raises(ValueError): func(a, a) + def test_trace(): x_val = np.ones((5, 4, 2)) x = ptb.as_tensor(x_val) From d160f9f2cadcd3fb7a0290b1810bf0a9607e0065 Mon Sep 17 00:00:00 2001 From: HarshvirSandhu Date: Sun, 4 Feb 2024 22:33:05 +0530 Subject: [PATCH 06/13] Add horizontal_stack and vertical_stack in __all__ --- pytensor/tensor/basic.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pytensor/tensor/basic.py b/pytensor/tensor/basic.py index 3f21d57b5b..82f893fdd4 100644 --- a/pytensor/tensor/basic.py +++ b/pytensor/tensor/basic.py @@ -4338,6 +4338,8 @@ def ix_(*args): "is_flat", "vstack", "hstack", + "vertical_stack", + "horizontal_stack", "dstack", "column_stack", "get_vector_length", From 2c4355a43ec37871c7e0ad020c2a36030e938df7 Mon Sep 17 00:00:00 2001 From: HarshvirSandhu Date: Sun, 11 Feb 2024 10:59:42 +0530 Subject: [PATCH 07/13] Implement stack helper functions to align with NumPy behavior --- pytensor/tensor/basic.py | 93 ++++++++++++++++++++++++-------------- tests/tensor/test_basic.py | 53 ++++++++++++++++++---- 2 files changed, 105 insertions(+), 41 deletions(-) diff --git a/pytensor/tensor/basic.py b/pytensor/tensor/basic.py index 1be3e62c12..ef6c9bbe64 100644 --- a/pytensor/tensor/basic.py +++ b/pytensor/tensor/basic.py @@ -2758,40 +2758,45 @@ def concatenate(tensor_list, axis=0): return join(axis, *tensor_list) -def hstack(*args): +def hstack(tup): r"""Stack arrays in sequence horizontally (column wise).""" - if len(args) < 2: - raise ValueError("Too few arguments") + arrs = atleast_1d(*tup) + if not isinstance(arrs, list): + arrs = [arrs] + # As a special case, dimension 0 of 1-dimensional arrays is "horizontal" + if arrs and arrs[0].ndim == 1: + return concatenate(arrs, axis=0) + else: + return concatenate(arrs, axis=1) - _args = [] - for arg in args: - _arg = as_tensor_variable(arg) - _args.append(_arg) - return concatenate(_args, axis=1) +def vstack(tup): + r"""Stack arrays in sequence vertically (row wise).""" + arrs = atleast_2d(*tup) + if not isinstance(arrs, list): + arrs = [arrs] + + return concatenate(arrs, axis=0) -def vstack(*args): - r"""Stack arrays in sequence vertically (row wise).""" +def horizontal_stack(*args): + warnings.warn( + "horizontal_stack was renamed to hstack and will be removed in a future release", + FutureWarning, + ) if len(args) < 2: raise ValueError("Too few arguments") _args = [] for arg in args: _arg = as_tensor_variable(arg) + if _arg.type.ndim != 2: + raise ValueError("All arguments must have two dimensions") _args.append(_arg) - return concatenate(_args, axis=0) - - -def horizontal_stack(*args): - warnings.warn( - "horizontal_stack was renamed to hstack and will be removed in a future release", - FutureWarning, - ) - return hstack(*args) + return concatenate(_args, axis=1) def vertical_stack(*args): @@ -2799,40 +2804,62 @@ def vertical_stack(*args): "vertical_stack was renamed to vstack and will be removed in a future release", FutureWarning, ) - return vstack(*args) - - -def dstack(*args): - r"""Stack arrays in sequence along third axis (depth wise).""" - if len(args) < 2: raise ValueError("Too few arguments") _args = [] for arg in args: _arg = as_tensor_variable(arg) - if _arg.type.ndim != 3: - raise ValueError("All arguments must have three dimensions") + if _arg.type.ndim != 2: + raise ValueError("All arguments must have two dimensions") _args.append(_arg) - return concatenate(_args, axis=2) + return concatenate(_args, axis=0) + + +def dstack(tup): + r"""Stack arrays in sequence along third axis (depth wise).""" + + # arrs = atleast_3d(*tup, left=False) + # if not isinstance(arrs, list): + # arrs = [arrs] + arrs = [] + for arr in tup: + if arr.ndim == 1: + arr = atleast_3d([arr], left=False) + else: + arr = atleast_3d(arr, left=False) + arrs.append(arr) + return concatenate(arrs, 2) -def column_stack(*args): +def column_stack(tup): r"""Stack 1-D arrays as columns into a 2-D array.""" + arrays = [] + for arr in tup: + if arr.ndim < 2: + arr = atleast_2d(arr).transpose() + arrays.append(arr) + return concatenate(arrays, 1) + + + + +def vertical_stack(*args): + r"""Stack arrays in sequence vertically (row wise).""" + if len(args) < 2: raise ValueError("Too few arguments") _args = [] for arg in args: _arg = as_tensor_variable(arg) - if _arg.type.ndim < 2: - _arg = atleast_2d(_arg).transpose() + if _arg.type.ndim != 2: + raise ValueError("All arguments must have two dimensions") _args.append(_arg) - return concatenate(_args, axis=1) - + return concatenate(_args, axis=0) def is_flat(var, ndim=1): """ diff --git a/tests/tensor/test_basic.py b/tests/tensor/test_basic.py index 7cabed135c..d715ffa73a 100644 --- a/tests/tensor/test_basic.py +++ b/tests/tensor/test_basic.py @@ -55,6 +55,7 @@ full_like, get_scalar_constant_value, get_underlying_scalar_constant_value, + horizontal_stack, get_vector_length, hstack, identity_like, @@ -89,6 +90,7 @@ triu_indices_from, vstack, zeros_like, + vertical_stack, ) from pytensor.tensor.blockwise import Blockwise from pytensor.tensor.elemwise import DimShuffle @@ -1745,6 +1747,33 @@ def test_join_matrix1_using_column_stack(self): out = self.eval_outputs_and_check_join([s]) assert (out == want).all() + def test_join_matrix1_using_vertical_stack(self): + a = self.shared(np.array([[1, 2, 3], [4, 5, 6]], dtype=self.floatX)) + b = as_tensor_variable(np.array([[7, 8, 9]], dtype=self.floatX)) + c = as_tensor_variable(np.array([[9, 8, 7]], dtype=self.floatX)) + s = vertical_stack(a, b, c) + + want = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [9, 8, 7]]) + out = self.eval_outputs_and_check_join([s]) + assert (out == want).all() + + def test_join_matrix1_using_horizontal_stack(self): + av = np.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]], dtype="float32") + bv = np.array([[0.7], [0.8]], dtype="float32") + cv = np.array([[0.3, 0.2, 0.1], [0.6, 0.5, 0.4]], dtype="float32") + a = self.shared(av) + b = as_tensor_variable(bv) + c = as_tensor_variable(cv) + s = horizontal_stack(a, b, c) + want = np.array( + [[0.1, 0.2, 0.3, 0.7, 0.3, 0.2, 0.1], [0.4, 0.5, 0.6, 0.8, 0.6, 0.5, 0.4]], + dtype="float32", + ) + out = self.eval_outputs_and_check_join([s]) + assert (out == want).all() + + utt.verify_grad(lambda a, b: join(1, a, b), [av, bv], mode=self.mode) + def test_join_matrixV(self): # variable join axis v = np.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]], dtype=self.floatX) @@ -4540,23 +4569,31 @@ def test_full_like(inp, shape): ) -@pytest.mark.parametrize("func", [hstack, vstack, column_stack]) -def test_oriented_stack_functions(func): - with pytest.raises(ValueError): - func() +@pytest.mark.parametrize("func", [hstack, vstack, dstack]) +@pytest.mark.parametrize("dimension", [1, 2, 3]) +def test_stack_helpers(func, dimension): + + if dimension == 1: + arrays = [np.arange(i * dimension, (i + 1) * dimension) for i in range(3)] + else: + arrays = [np.arange(i * dimension * dimension, (i + 1) * dimension * dimension).reshape(dimension, dimension) for i in range(3)] + + result = func(arrays) + np_result = getattr(np, func.__name__)(arrays) + assert np.array_equal(result.eval(), np_result) -@pytest.mark.parametrize("func", [dstack]) -def test_dstack_function(func): + +@pytest.mark.parametrize("func", [horizontal_stack, vertical_stack]) +def test_oriented_stack_functions(func): with pytest.raises(ValueError): func() - a = ptb.tensor(dtype=np.float64, shape=(None, None)) + a = ptb.tensor(dtype=np.float64, shape=(None, None, None)) with pytest.raises(ValueError): func(a, a) - def test_trace(): x_val = np.ones((5, 4, 2)) x = ptb.as_tensor(x_val) From b86036991f3cfcf44182ba4fd4a74cd240149e10 Mon Sep 17 00:00:00 2001 From: HarshvirSandhu Date: Sun, 11 Feb 2024 22:49:20 +0530 Subject: [PATCH 08/13] Solved linting issues --- pytensor/tensor/basic.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/pytensor/tensor/basic.py b/pytensor/tensor/basic.py index ef6c9bbe64..2eb8a1e16a 100644 --- a/pytensor/tensor/basic.py +++ b/pytensor/tensor/basic.py @@ -2844,23 +2844,6 @@ def column_stack(tup): return concatenate(arrays, 1) - - -def vertical_stack(*args): - r"""Stack arrays in sequence vertically (row wise).""" - - if len(args) < 2: - raise ValueError("Too few arguments") - - _args = [] - for arg in args: - _arg = as_tensor_variable(arg) - if _arg.type.ndim != 2: - raise ValueError("All arguments must have two dimensions") - _args.append(_arg) - - return concatenate(_args, axis=0) - def is_flat(var, ndim=1): """ Verifies the dimensionality of the var is equal to From 3ba05ae8c4bba4c11bbe06f501c497f6bee33b3a Mon Sep 17 00:00:00 2001 From: HarshvirSandhu Date: Sun, 11 Feb 2024 23:08:34 +0530 Subject: [PATCH 09/13] Solved linting issues --- tests/tensor/test_basic.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/tensor/test_basic.py b/tests/tensor/test_basic.py index d715ffa73a..2f0d5d5af0 100644 --- a/tests/tensor/test_basic.py +++ b/tests/tensor/test_basic.py @@ -55,8 +55,8 @@ full_like, get_scalar_constant_value, get_underlying_scalar_constant_value, - horizontal_stack, get_vector_length, + horizontal_stack, hstack, identity_like, infer_static_shape, @@ -88,9 +88,9 @@ triu, triu_indices, triu_indices_from, + vertical_stack, vstack, zeros_like, - vertical_stack, ) from pytensor.tensor.blockwise import Blockwise from pytensor.tensor.elemwise import DimShuffle @@ -1773,7 +1773,7 @@ def test_join_matrix1_using_horizontal_stack(self): assert (out == want).all() utt.verify_grad(lambda a, b: join(1, a, b), [av, bv], mode=self.mode) - + def test_join_matrixV(self): # variable join axis v = np.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]], dtype=self.floatX) @@ -4577,7 +4577,7 @@ def test_stack_helpers(func, dimension): arrays = [np.arange(i * dimension, (i + 1) * dimension) for i in range(3)] else: arrays = [np.arange(i * dimension * dimension, (i + 1) * dimension * dimension).reshape(dimension, dimension) for i in range(3)] - + result = func(arrays) np_result = getattr(np, func.__name__)(arrays) From 21671789f30fe41eb06f7fa1ab3a61a18528e31e Mon Sep 17 00:00:00 2001 From: HarshvirSandhu Date: Sun, 11 Feb 2024 23:14:58 +0530 Subject: [PATCH 10/13] Fix ruff format --- pytensor/tensor/basic.py | 2 +- tests/tensor/test_basic.py | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/pytensor/tensor/basic.py b/pytensor/tensor/basic.py index 2eb8a1e16a..748dc2d227 100644 --- a/pytensor/tensor/basic.py +++ b/pytensor/tensor/basic.py @@ -2761,7 +2761,7 @@ def concatenate(tensor_list, axis=0): def hstack(tup): r"""Stack arrays in sequence horizontally (column wise).""" - arrs = atleast_1d(*tup) + arrs = atleast_1d(*tup) if not isinstance(arrs, list): arrs = [arrs] # As a special case, dimension 0 of 1-dimensional arrays is "horizontal" diff --git a/tests/tensor/test_basic.py b/tests/tensor/test_basic.py index 2f0d5d5af0..acaa29fe27 100644 --- a/tests/tensor/test_basic.py +++ b/tests/tensor/test_basic.py @@ -4572,11 +4572,15 @@ def test_full_like(inp, shape): @pytest.mark.parametrize("func", [hstack, vstack, dstack]) @pytest.mark.parametrize("dimension", [1, 2, 3]) def test_stack_helpers(func, dimension): - if dimension == 1: arrays = [np.arange(i * dimension, (i + 1) * dimension) for i in range(3)] else: - arrays = [np.arange(i * dimension * dimension, (i + 1) * dimension * dimension).reshape(dimension, dimension) for i in range(3)] + arrays = [ + np.arange( + i * dimension * dimension, (i + 1) * dimension * dimension + ).reshape(dimension, dimension) + for i in range(3) + ] result = func(arrays) np_result = getattr(np, func.__name__)(arrays) @@ -4594,6 +4598,7 @@ def test_oriented_stack_functions(func): with pytest.raises(ValueError): func(a, a) + def test_trace(): x_val = np.ones((5, 4, 2)) x = ptb.as_tensor(x_val) From 4b5210a9587b7b9edfe0082872dbd8673e9c50f8 Mon Sep 17 00:00:00 2001 From: HarshvirSandhu Date: Mon, 19 Feb 2024 12:07:01 +0530 Subject: [PATCH 11/13] Remove old tests --- tests/tensor/test_basic.py | 76 ++++---------------------------------- 1 file changed, 7 insertions(+), 69 deletions(-) diff --git a/tests/tensor/test_basic.py b/tests/tensor/test_basic.py index acaa29fe27..1ffc9a3353 100644 --- a/tests/tensor/test_basic.py +++ b/tests/tensor/test_basic.py @@ -1671,75 +1671,12 @@ def test_join_matrix_ints(self): assert (np.asarray(grad(s.sum(), b).eval()) == 0).all() assert (np.asarray(grad(s.sum(), a).eval()) == 0).all() - def test_join_matrix1_using_vstack(self): - a = self.shared(np.array([[1, 2, 3], [4, 5, 6]], dtype=self.floatX)) - b = as_tensor_variable(np.array([[7, 8, 9]], dtype=self.floatX)) - c = as_tensor_variable(np.array([[9, 8, 7]], dtype=self.floatX)) - s = vstack(a, b, c) - - want = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [9, 8, 7]]) - out = self.eval_outputs_and_check_join([s]) - assert (out == want).all() - - def test_join_matrix1_using_dstack(self): - a = self.shared( - np.array([[[0.1], [0.2], [0.3]], [[0.4], [0.5], [0.6]]], dtype="float32") - ) - - b = as_tensor_variable( - np.array( - [ - [ - [0.2, 0.3], - [0.3, 0.4], - [0.4, 0.5], - ], - [[0.5, 0.6], [0.6, 0.7], [0.7, 0.8]], - ], - dtype="float32", - ) - ) - - c = as_tensor_variable( - np.array([[[0.4], [0.5], [0.6]], [[0.7], [0.8], [0.9]]], dtype="float32") - ) - - s = dstack(a, b, c) - - want = np.array( - [ - [[0.1, 0.2, 0.3, 0.4], [0.2, 0.3, 0.4, 0.5], [0.3, 0.4, 0.5, 0.6]], - [[0.4, 0.5, 0.6, 0.7], [0.5, 0.6, 0.7, 0.8], [0.6, 0.7, 0.8, 0.9]], - ], - dtype="float32", - ) - - out = self.eval_outputs_and_check_join([s]) - assert (out == want).all() - - def test_join_matrix1_using_hstack(self): - av = np.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]], dtype="float32") - bv = np.array([[0.7], [0.8]], dtype="float32") - cv = np.array([[0.3, 0.2, 0.1], [0.6, 0.5, 0.4]], dtype="float32") - a = self.shared(av) - b = as_tensor_variable(bv) - c = as_tensor_variable(cv) - s = hstack(a, b, c) - want = np.array( - [[0.1, 0.2, 0.3, 0.7, 0.3, 0.2, 0.1], [0.4, 0.5, 0.6, 0.8, 0.6, 0.5, 0.4]], - dtype="float32", - ) - out = self.eval_outputs_and_check_join([s]) - assert (out == want).all() - - utt.verify_grad(lambda a, b: join(1, a, b), [av, bv], mode=self.mode) - def test_join_matrix1_using_column_stack(self): av = np.array([0.1, 0.2, 0.3], dtype="float32") bv = np.array([0.7, 0.8, 0.9], dtype="float32") a = self.shared(av) b = as_tensor_variable(bv) - s = column_stack(a, b) + s = column_stack((a, b)) want = np.array( [[0.1, 0.7], [0.2, 0.8], [0.3, 0.9]], dtype="float32", @@ -4590,13 +4527,14 @@ def test_stack_helpers(func, dimension): @pytest.mark.parametrize("func", [horizontal_stack, vertical_stack]) def test_oriented_stack_functions(func): - with pytest.raises(ValueError): - func() + with pytest.warns(FutureWarning): + with pytest.raises(ValueError): + func() - a = ptb.tensor(dtype=np.float64, shape=(None, None, None)) + a = ptb.tensor(dtype=np.float64, shape=(None, None, None)) - with pytest.raises(ValueError): - func(a, a) + with pytest.raises(ValueError): + func(a, a) def test_trace(): From 6a962ab104f5871e0830b58877070d44f822d298 Mon Sep 17 00:00:00 2001 From: HarshvirSandhu Date: Mon, 4 Mar 2024 18:11:36 +0530 Subject: [PATCH 12/13] Modify tests --- tests/tensor/test_basic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tensor/test_basic.py b/tests/tensor/test_basic.py index 1ffc9a3353..44eef8b3b7 100644 --- a/tests/tensor/test_basic.py +++ b/tests/tensor/test_basic.py @@ -1682,7 +1682,7 @@ def test_join_matrix1_using_column_stack(self): dtype="float32", ) out = self.eval_outputs_and_check_join([s]) - assert (out == want).all() + np.testing.assert_array_equal(out, want, strict=True) def test_join_matrix1_using_vertical_stack(self): a = self.shared(np.array([[1, 2, 3], [4, 5, 6]], dtype=self.floatX)) From e4d9087fb347fafd85c3aba8a10909396ea07404 Mon Sep 17 00:00:00 2001 From: HarshvirSandhu Date: Mon, 4 Mar 2024 18:36:50 +0530 Subject: [PATCH 13/13] Include warnings in tests --- tests/tensor/test_basic.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/tensor/test_basic.py b/tests/tensor/test_basic.py index 44eef8b3b7..3c570ff1a5 100644 --- a/tests/tensor/test_basic.py +++ b/tests/tensor/test_basic.py @@ -1688,7 +1688,8 @@ def test_join_matrix1_using_vertical_stack(self): a = self.shared(np.array([[1, 2, 3], [4, 5, 6]], dtype=self.floatX)) b = as_tensor_variable(np.array([[7, 8, 9]], dtype=self.floatX)) c = as_tensor_variable(np.array([[9, 8, 7]], dtype=self.floatX)) - s = vertical_stack(a, b, c) + with pytest.warns(FutureWarning): + s = vertical_stack(a, b, c) want = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [9, 8, 7]]) out = self.eval_outputs_and_check_join([s]) @@ -1701,7 +1702,8 @@ def test_join_matrix1_using_horizontal_stack(self): a = self.shared(av) b = as_tensor_variable(bv) c = as_tensor_variable(cv) - s = horizontal_stack(a, b, c) + with pytest.warns(FutureWarning): + s = horizontal_stack(a, b, c) want = np.array( [[0.1, 0.2, 0.3, 0.7, 0.3, 0.2, 0.1], [0.4, 0.5, 0.6, 0.8, 0.6, 0.5, 0.4]], dtype="float32",