This is a common failure (per our search traffic :) ), hopefully these
error messages are clearer. Examples:
Python 3.8.0 (default, Nov 6 2019, 21:49:08)
Type 'copyright', 'credits' or 'license' for more information
IPython 8.4.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: import symforce.symbolic as sf
In [2]: from symforce import codegen
In [3]: def foo(x: sf.Scalar) -> sf.Scalar:
...: return x
...:
In [4]: codegen.Codegen.function(foo, config=codegen.CppConfig()).with_linearization()
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Input In [4], in <cell line: 1>()
----> 1 codegen.Codegen.function(foo, config=codegen.CppConfig()).with_linearization()
File ~/symforce/symforce/codegen/codegen.py:618, in Codegen.with_linearization(self, which_args, include_result, name, linearization_mode, sparse_linearization, custom_jacobian)
613 common_msg = (
614 "The output of a factor must be a column vector representing the "
615 f"residual (of shape Nx1). For factor \"{self.name}\", "
616 )
617 if python_util.scalar_like(result):
--> 618 raise ValueError(
619 common_msg + "got a scalar expression instead. Did you mean to wrap it in "
620 "`geo.V1(expr)`?"
621 )
622 if isinstance(result, sf.Matrix):
623 raise ValueError(common_msg + f"got a matrix of shape {result.shape} instead")
ValueError: The output of a factor must be a column vector representing the residual (of shape Nx1). For factor "foo", got a scalar expression instead. Did you mean to wrap it in `geo.V1(expr)`?
In [5]: def foo(x: sf.Scalar) -> sf.M22:
...: return sf.M22(x, x**2, x**3, x**4)
...:
In [6]: codegen.Codegen.function(foo, config=codegen.CppConfig()).with_linearization()
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Input In [6], in <cell line: 1>()
----> 1 codegen.Codegen.function(foo, config=codegen.CppConfig()).with_linearization()
File ~/symforce/symforce/codegen/codegen.py:623, in Codegen.with_linearization(self, which_args, include_result, name, linearization_mode, sparse_linearization, custom_jacobian)
618 raise ValueError(
619 common_msg + "got a scalar expression instead. Did you mean to wrap it in "
620 "`geo.V1(expr)`?"
621 )
622 if isinstance(result, sf.Matrix):
--> 623 raise ValueError(common_msg + f"got a matrix of shape {result.shape} instead")
625 raise ValueError(common_msg + f"got an object of type {type(result)} instead")
627 hessian = jacobian.compute_AtA(lower_only=True)
ValueError: The output of a factor must be a column vector representing the residual (of shape Nx1). For factor "foo", got a matrix of shape (2, 2) instead
In [7]: def foo(x: sf.Scalar) -> sf.Rot3:
...: return sf.Rot3.from_angle_axis(angle=x, axis=sf.V3(0, 0, 1))
...:
In [8]: codegen.Codegen.function(foo, config=codegen.CppConfig()).with_linearization()
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Input In [8], in <cell line: 1>()
----> 1 codegen.Codegen.function(foo, config=codegen.CppConfig()).with_linearization()
File ~/symforce/symforce/codegen/codegen.py:625, in Codegen.with_linearization(self, which_args, include_result, name, linearization_mode, sparse_linearization, custom_jacobian)
622 if isinstance(result, sf.Matrix):
623 raise ValueError(common_msg + f"got a matrix of shape {result.shape} instead")
--> 625 raise ValueError(common_msg + f"got an object of type {type(result)} instead")
627 hessian = jacobian.compute_AtA(lower_only=True)
628 outputs["hessian"] = hessian
ValueError: The output of a factor must be a column vector representing the residual (of shape Nx1). For factor "foo", got an object of type <class 'symforce.geo.rot3.Rot3'> instead
For general objects, we're printing the type as opposed to the object so
we don't attempt to print huge expressions (which isn't something I've
been careful about previously, but should start being careful about).
This is a common failure (per our search traffic :) ), hopefully these error messages are clearer. Examples:
For general objects, we're printing the type as opposed to the object so we don't attempt to print huge expressions (which isn't something I've been careful about previously, but should start being careful about).