From db1316c8b527f36fb68b3ea9845ea54e4227ebc5 Mon Sep 17 00:00:00 2001 From: Stanislav Date: Fri, 16 Oct 2026 12:04:56 +0400 Subject: [PATCH 1/9] Keep single-row and single-column matrices as matrices in Transpose Transpose[{{1, 2, 3}}] gave {1, 2, 3} instead of {{1}, {2}, {3}}: the 2D case went through a SymPy matrix, and from_sympy_matrix turns any one-column result into a vector. Transpose a 2D list by moving its elements directly instead, which also leaves them untouched. Co-Authored-By: Claude Opus 5.5 --- mathics/eval/tensors.py | 9 ++++++--- test/builtin/test_tensor.py | 13 +++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/mathics/eval/tensors.py b/mathics/eval/tensors.py index 406f7fe12c..50e75a7db8 100644 --- a/mathics/eval/tensors.py +++ b/mathics/eval/tensors.py @@ -5,7 +5,7 @@ from sympy.utilities.iterables import permutations from mathics.core.atoms import Integer, Integer0, Integer1, String -from mathics.core.convert.matrix import to_sympy_array, to_sympy_matrix +from mathics.core.convert.matrix import to_sympy_array from mathics.core.convert.python import from_python from mathics.core.convert.sympy import from_sympy_matrix from mathics.core.evaluation import Evaluation @@ -340,5 +340,8 @@ def eval_Transpose(m, dimensions: int) -> Optional[Expression]: return from_sympy_matrix(p.as_explicit()) assert dimensions == 2 - sympy_m = to_sympy_matrix(m) - return None if sympy_m is None else from_sympy_matrix(sympy_m.T) + # Rearrange the elements directly. Going through a SymPy matrix + # would turn a result with a single column, such as the transpose + # of {{1, 2, 3}}, into a vector. + rows = [row.elements for row in m.elements] + return ListExpression(*(ListExpression(*column) for column in zip(*rows))) diff --git a/test/builtin/test_tensor.py b/test/builtin/test_tensor.py index 853d7806fb..bfad22327a 100644 --- a/test/builtin/test_tensor.py +++ b/test/builtin/test_tensor.py @@ -24,6 +24,19 @@ ("A", None, "{{1 / Sqrt[b], 0}, {a / Sqrt[b], Sqrt[b]}}", None), # Transpose ("Transpose[x]", None, "Transpose[x]", None), + # A matrix with a single row or column stays a matrix. + ("Transpose[{{1, 2, 3}}]", None, "{{1}, {2}, {3}}", None), + ("Transpose[{{1}, {2}, {3}}]", None, "{{1, 2, 3}}", None), + ("Transpose[{{a}}]", None, "{{a}}", None), + ("Transpose[Transpose[{{a, b}}]]", None, "{{a, b}}", None), + ("Dimensions[Transpose[{{1, 2, 3}}]]", None, "{3, 1}", None), + # Elements are moved as they are, without a round trip through SymPy. + ( + "Transpose[{{x + y, f[x]}, {1/2, Sin[x]}}]", + None, + "{{x + y, 1 / 2}, {f[x], Sin[x]}}", + None, + ), ], ) def test_tensor(str_expr, msgs, str_expected, fail_msg): From 257b7c7681a38dba7d9ead9a04cba2706aef3e95 Mon Sep 17 00:00:00 2001 From: "R. Bernstein" Date: Fri, 16 Oct 2026 10:44:45 -0400 Subject: [PATCH 2/9] Apply batched suggestions from code review Co-authored-by: R. Bernstein --- test/builtin/test_tensor.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/builtin/test_tensor.py b/test/builtin/test_tensor.py index bfad22327a..43ce4d1164 100644 --- a/test/builtin/test_tensor.py +++ b/test/builtin/test_tensor.py @@ -25,11 +25,14 @@ # Transpose ("Transpose[x]", None, "Transpose[x]", None), # A matrix with a single row or column stays a matrix. - ("Transpose[{{1, 2, 3}}]", None, "{{1}, {2}, {3}}", None), - ("Transpose[{{1}, {2}, {3}}]", None, "{{1, 2, 3}}", None), + ("Transpose[{{1, 2, 3}}]", None, "{{1}, {2}, {3}}", + "Transpose of a single row turns into a single columns"), + ("Transpose[{{1}, {2}, {3}}]", None, "{{1, 2, 3}}", + "Transpose of a single columns turns into a single row"), ("Transpose[{{a}}]", None, "{{a}}", None), ("Transpose[Transpose[{{a, b}}]]", None, "{{a, b}}", None), - ("Dimensions[Transpose[{{1, 2, 3}}]]", None, "{3, 1}", None), + ("Dimensions[Transpose[{{1, 2, 3}}]]", None, "{3, 1}", + "Check the shape of a Transpose of a single row"), # Elements are moved as they are, without a round trip through SymPy. ( "Transpose[{{x + y, f[x]}, {1/2, Sin[x]}}]", From d20bca8bfce9f1c548d928d5b8e8d6d4be4dc598 Mon Sep 17 00:00:00 2001 From: "R. Bernstein" Date: Fri, 16 Oct 2026 10:45:23 -0400 Subject: [PATCH 3/9] Apply batched suggestions from code review Add assert failure messages to new tests. Co-authored-by: R. Bernstein --- test/builtin/test_tensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/builtin/test_tensor.py b/test/builtin/test_tensor.py index 43ce4d1164..a13a4e1c74 100644 --- a/test/builtin/test_tensor.py +++ b/test/builtin/test_tensor.py @@ -29,7 +29,7 @@ "Transpose of a single row turns into a single columns"), ("Transpose[{{1}, {2}, {3}}]", None, "{{1, 2, 3}}", "Transpose of a single columns turns into a single row"), - ("Transpose[{{a}}]", None, "{{a}}", None), + ("Transpose[{{a}}]", None, "{{a}}", "Transpose of a single element"), ("Transpose[Transpose[{{a, b}}]]", None, "{{a, b}}", None), ("Dimensions[Transpose[{{1, 2, 3}}]]", None, "{3, 1}", "Check the shape of a Transpose of a single row"), From 92ae440c77a847e0a144da651457837294529751 Mon Sep 17 00:00:00 2001 From: "R. Bernstein" Date: Fri, 16 Oct 2026 10:46:29 -0400 Subject: [PATCH 4/9] Apply batched suggestions from code review Co-authored-by: R. Bernstein --- test/builtin/test_tensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/builtin/test_tensor.py b/test/builtin/test_tensor.py index a13a4e1c74..d0068e3145 100644 --- a/test/builtin/test_tensor.py +++ b/test/builtin/test_tensor.py @@ -32,7 +32,7 @@ ("Transpose[{{a}}]", None, "{{a}}", "Transpose of a single element"), ("Transpose[Transpose[{{a, b}}]]", None, "{{a, b}}", None), ("Dimensions[Transpose[{{1, 2, 3}}]]", None, "{3, 1}", - "Check the shape of a Transpose of a single row"), + "Check the shape of a Transpose of a single row"), # Elements are moved as they are, without a round trip through SymPy. ( "Transpose[{{x + y, f[x]}, {1/2, Sin[x]}}]", From 25957da7ae26e04fd0e81afa118f15defce8ceb9 Mon Sep 17 00:00:00 2001 From: "R. Bernstein" Date: Fri, 16 Oct 2026 10:54:35 -0400 Subject: [PATCH 5/9] Apply suggestion from @rocky black --- test/builtin/test_tensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/builtin/test_tensor.py b/test/builtin/test_tensor.py index d0068e3145..b6446929d9 100644 --- a/test/builtin/test_tensor.py +++ b/test/builtin/test_tensor.py @@ -32,7 +32,7 @@ ("Transpose[{{a}}]", None, "{{a}}", "Transpose of a single element"), ("Transpose[Transpose[{{a, b}}]]", None, "{{a, b}}", None), ("Dimensions[Transpose[{{1, 2, 3}}]]", None, "{3, 1}", - "Check the shape of a Transpose of a single row"), + "Check the shape of a Transpose of a single row"), # Elements are moved as they are, without a round trip through SymPy. ( "Transpose[{{x + y, f[x]}, {1/2, Sin[x]}}]", From affd486696911ed03ef91f38040910d4a83e8239 Mon Sep 17 00:00:00 2001 From: Juan Mauricio Matera Date: Fri, 16 Oct 2026 20:27:23 -0300 Subject: [PATCH 6/9] Update test_tensor.py --- test/builtin/test_tensor.py | 45 +++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/test/builtin/test_tensor.py b/test/builtin/test_tensor.py index b6446929d9..8da229c024 100644 --- a/test/builtin/test_tensor.py +++ b/test/builtin/test_tensor.py @@ -23,16 +23,43 @@ ("A . Inverse[A]", None, "{{1, 0}, {0, 1}}", None), ("A", None, "{{1 / Sqrt[b], 0}, {a / Sqrt[b], Sqrt[b]}}", None), # Transpose - ("Transpose[x]", None, "Transpose[x]", None), + ( + "Transpose[x]", + None, + "Transpose[x]", + None + ), # A matrix with a single row or column stays a matrix. - ("Transpose[{{1, 2, 3}}]", None, "{{1}, {2}, {3}}", - "Transpose of a single row turns into a single columns"), - ("Transpose[{{1}, {2}, {3}}]", None, "{{1, 2, 3}}", - "Transpose of a single columns turns into a single row"), - ("Transpose[{{a}}]", None, "{{a}}", "Transpose of a single element"), - ("Transpose[Transpose[{{a, b}}]]", None, "{{a, b}}", None), - ("Dimensions[Transpose[{{1, 2, 3}}]]", None, "{3, 1}", - "Check the shape of a Transpose of a single row"), + ( + "Transpose[{{1, 2, 3}}]", + None, + "{{1}, {2}, {3}}", + "Transpose of a single row turns into a single columns" + ), + ( + "Transpose[{{1}, {2}, {3}}]", + None, + "{{1, 2, 3}}", + "Transpose of a single columns turns into a single row" + ), + ( + "Transpose[{{a}}]", + None, + "{{a}}", + "Transpose of a single element" + ), + ( + "Transpose[Transpose[{{a, b}}]]", + None, + "{{a, b}}", + None + ), + ( + "Dimensions[Transpose[{{1, 2, 3}}]]", + None, + "{3, 1}", + "Check the shape of a Transpose of a single row" + ), # Elements are moved as they are, without a round trip through SymPy. ( "Transpose[{{x + y, f[x]}, {1/2, Sin[x]}}]", From a2a78f7dba74f9c763bec3c54709f7b27acd2a63 Mon Sep 17 00:00:00 2001 From: Juan Mauricio Matera Date: Fri, 16 Oct 2026 20:48:40 -0300 Subject: [PATCH 7/9] Update test_tensor.py --- test/builtin/test_tensor.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/test/builtin/test_tensor.py b/test/builtin/test_tensor.py index 8da229c024..57d00dd1f3 100644 --- a/test/builtin/test_tensor.py +++ b/test/builtin/test_tensor.py @@ -11,8 +11,18 @@ @pytest.mark.parametrize( ("str_expr", "msgs", "str_expected", "fail_msg"), [ - ("Dimensions[{}]", None, "{0}", None), - ("Dimensions[{{}}]", None, "{1, 0}", None), + ( + "Dimensions[{}]", + None, + "{0}", + None, + ), + ( + "Dimensions[{{}}]", + None, + "{1, 0}", + None, + ), ## Issue #670 ( "A = {{ b ^ ( -1 / 2), 0}, {a * b ^ ( -1 / 2 ), b ^ ( 1 / 2 )}}", @@ -27,32 +37,32 @@ "Transpose[x]", None, "Transpose[x]", - None + None, ), # A matrix with a single row or column stays a matrix. ( "Transpose[{{1, 2, 3}}]", None, "{{1}, {2}, {3}}", - "Transpose of a single row turns into a single columns" + "Transpose of a single row turns into a single column", ), ( "Transpose[{{1}, {2}, {3}}]", None, "{{1, 2, 3}}", - "Transpose of a single columns turns into a single row" + "Transpose of a single column turns into a single row", ), ( "Transpose[{{a}}]", None, "{{a}}", - "Transpose of a single element" + "Transpose of a single element", ), ( "Transpose[Transpose[{{a, b}}]]", None, "{{a, b}}", - None + None, ), ( "Dimensions[Transpose[{{1, 2, 3}}]]", From 01ed4b23b76cf6df3feca4328b0a5459055ab668 Mon Sep 17 00:00:00 2001 From: Juan Mauricio Matera Date: Fri, 16 Oct 2026 20:51:47 -0300 Subject: [PATCH 8/9] Update test_tensor.py --- test/builtin/test_tensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/builtin/test_tensor.py b/test/builtin/test_tensor.py index 57d00dd1f3..43d0c2e789 100644 --- a/test/builtin/test_tensor.py +++ b/test/builtin/test_tensor.py @@ -68,7 +68,7 @@ "Dimensions[Transpose[{{1, 2, 3}}]]", None, "{3, 1}", - "Check the shape of a Transpose of a single row" + "Check the shape of a Transpose of a single row", ), # Elements are moved as they are, without a round trip through SymPy. ( From d318f1c8fcb2e6a905358ed0e72700f20c666e3f Mon Sep 17 00:00:00 2001 From: Juan Mauricio Matera Date: Fri, 16 Oct 2026 20:57:08 -0300 Subject: [PATCH 9/9] Update tensors.py --- mathics/eval/tensors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mathics/eval/tensors.py b/mathics/eval/tensors.py index 50e75a7db8..5bcceec643 100644 --- a/mathics/eval/tensors.py +++ b/mathics/eval/tensors.py @@ -339,7 +339,7 @@ def eval_Transpose(m, dimensions: int) -> Optional[Expression]: p = PermuteDims(sympy_m, (1, 0, 2)) return from_sympy_matrix(p.as_explicit()) - assert dimensions == 2 + assert dimensions == 2, "eval_Transpose only applies to 2- and 3-dimensional array." # Rearrange the elements directly. Going through a SymPy matrix # would turn a result with a single column, such as the transpose # of {{1, 2, 3}}, into a vector.