From cf05e0fc13c148c7a7076ca06316099515159008 Mon Sep 17 00:00:00 2001 From: tandede <1090179959@qq.com> Date: Tue, 25 Aug 2026 10:44:55 +0800 Subject: [PATCH] [SymForce-External] Fix Rust matrix return types Rust codegen flattened every directly returned matrix into an SVector, even when both dimensions were greater than one. Reuse the existing shape-aware type formatter for both the return signature and constructor so single-output code follows the same rules as output arguments. Add a non-square Matrix23 regression to both symbolic backends and compile the generated Rust crate. This preserves vector returns while proving that true matrices retain their row and column dimensions. Signed-off-by: tandede <1090179959@qq.com> --- .../backends/rust/templates/util/util.jinja | 5 ++-- .../symforce_rust_codegen_test/src/lib.rs | 1 + .../src/matrix_return_fun.rs | 28 +++++++++++++++++++ .../symforce_rust_codegen_test/src/lib.rs | 1 + .../src/matrix_return_fun.rs | 28 +++++++++++++++++++ test/symforce_rust_codegen_test.py | 11 ++++++++ 6 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 test/symforce_function_codegen_test_data/symengine/symforce_rust_codegen_test/src/matrix_return_fun.rs create mode 100644 test/symforce_function_codegen_test_data/sympy/symforce_rust_codegen_test/src/matrix_return_fun.rs diff --git a/symforce/codegen/backends/rust/templates/util/util.jinja b/symforce/codegen/backends/rust/templates/util/util.jinja index a6ae4cbe..3bf34ba2 100644 --- a/symforce/codegen/backends/rust/templates/util/util.jinja +++ b/symforce/codegen/backends/rust/templates/util/util.jinja @@ -59,7 +59,7 @@ {% if is_symbolic(type) or T.__name__ == "float" %} {{ format_scalar(spec) }} {% elif issubclass(T, Matrix) %} - {{ format_vector(T, spec.return_key, spec) }} + {{ format_typename(spec.return_key, type, spec) }} {% else %} {{ raise("Unsupported return type: {}".format(T)) }} {% endif %} @@ -231,8 +231,7 @@ {% if is_symbolic(type) or T_return.__name__ == "float" %} {{ terms[0][1] }}; {% elif issubclass(T_return, Matrix) %} - {% set size = T_return.SHAPE[0] * T_return.SHAPE[1] %} - {{ format_vector(T_return, name, spec) }}::new( + {{ format_typename(name, type, spec) }}::new( {% for lhs, rhs in terms %} {{ rhs }}{% if not loop.last %},{% endif %} {% endfor %} diff --git a/test/symforce_function_codegen_test_data/symengine/symforce_rust_codegen_test/src/lib.rs b/test/symforce_function_codegen_test_data/symengine/symforce_rust_codegen_test/src/lib.rs index 149889d8..dc2d6522 100644 --- a/test/symforce_function_codegen_test_data/symengine/symforce_rust_codegen_test/src/lib.rs +++ b/test/symforce_function_codegen_test_data/symengine/symforce_rust_codegen_test/src/lib.rs @@ -1,4 +1,5 @@ mod backend_test_function_float32; mod backend_test_function_float64; +mod matrix_return_fun; mod vector_matrix_fun; diff --git a/test/symforce_function_codegen_test_data/symengine/symforce_rust_codegen_test/src/matrix_return_fun.rs b/test/symforce_function_codegen_test_data/symengine/symforce_rust_codegen_test/src/matrix_return_fun.rs new file mode 100644 index 00000000..3d34221a --- /dev/null +++ b/test/symforce_function_codegen_test_data/symengine/symforce_rust_codegen_test/src/matrix_return_fun.rs @@ -0,0 +1,28 @@ +// ----------------------------------------------------------------------------- +// This file was autogenerated by symforce from template: +// function/FUNCTION.rs.jinja +// Do NOT modify by hand. +// ----------------------------------------------------------------------------- + +pub mod sym { + + #[allow(unused_parens)] + + /// + /// This function was autogenerated from a symbolic function. Do not modify by hand. + /// + /// Symbolic function: matrix_return + /// + /// Outputs: + /// res: Matrix23 + + pub fn matrix_return_fun() -> nalgebra::SMatrix { + // Total ops: 0 + + // Intermediate terms (0) + + // Output terms (1) + + nalgebra::SMatrix::::new(1_f64, 4_f64, 2_f64, 5_f64, 3_f64, 6_f64) + } +} // mod sym diff --git a/test/symforce_function_codegen_test_data/sympy/symforce_rust_codegen_test/src/lib.rs b/test/symforce_function_codegen_test_data/sympy/symforce_rust_codegen_test/src/lib.rs index 149889d8..dc2d6522 100644 --- a/test/symforce_function_codegen_test_data/sympy/symforce_rust_codegen_test/src/lib.rs +++ b/test/symforce_function_codegen_test_data/sympy/symforce_rust_codegen_test/src/lib.rs @@ -1,4 +1,5 @@ mod backend_test_function_float32; mod backend_test_function_float64; +mod matrix_return_fun; mod vector_matrix_fun; diff --git a/test/symforce_function_codegen_test_data/sympy/symforce_rust_codegen_test/src/matrix_return_fun.rs b/test/symforce_function_codegen_test_data/sympy/symforce_rust_codegen_test/src/matrix_return_fun.rs new file mode 100644 index 00000000..3d34221a --- /dev/null +++ b/test/symforce_function_codegen_test_data/sympy/symforce_rust_codegen_test/src/matrix_return_fun.rs @@ -0,0 +1,28 @@ +// ----------------------------------------------------------------------------- +// This file was autogenerated by symforce from template: +// function/FUNCTION.rs.jinja +// Do NOT modify by hand. +// ----------------------------------------------------------------------------- + +pub mod sym { + + #[allow(unused_parens)] + + /// + /// This function was autogenerated from a symbolic function. Do not modify by hand. + /// + /// Symbolic function: matrix_return + /// + /// Outputs: + /// res: Matrix23 + + pub fn matrix_return_fun() -> nalgebra::SMatrix { + // Total ops: 0 + + // Intermediate terms (0) + + // Output terms (1) + + nalgebra::SMatrix::::new(1_f64, 4_f64, 2_f64, 5_f64, 3_f64, 6_f64) + } +} // mod sym diff --git a/test/symforce_rust_codegen_test.py b/test/symforce_rust_codegen_test.py index 543a05ea..2d49e6d3 100644 --- a/test/symforce_rust_codegen_test.py +++ b/test/symforce_rust_codegen_test.py @@ -55,6 +55,7 @@ def write_lib_rs(output_dir: Path) -> None: """ mod backend_test_function_float32; mod backend_test_function_float64; + mod matrix_return_fun; mod vector_matrix_fun; """ ) @@ -91,6 +92,9 @@ def test_codegen(self) -> None: def rust_func(vec3: sf.V3, mat33: sf.M33) -> sf.Matrix31: return sf.Matrix31(mat33 * vec3) + def matrix_return() -> sf.M23: + return sf.M23([[1, 2, 3], [4, 5, 6]]) + output_dir_base = self.make_output_dir("symforce_rust_codegen_test_") output_dir_src = output_dir_base / "src" @@ -103,6 +107,13 @@ def rust_func(vec3: sf.V3, mat33: sf.M33) -> sf.Matrix31: name="vector_matrix_fun", ).generate_function(output_dir_src, skip_directory_nesting=True) + # A non-square matrix distinguishes its row and column dimensions from a flattened vector. + Codegen.function( + matrix_return, + config=RustConfig(scalar_type=ScalarType.DOUBLE), + name="matrix_return_fun", + ).generate_function(output_dir_src, skip_directory_nesting=True) + # Generate the symbolic backend test function for scalar in scalars: Codegen.function(