# ----------------------------------------------------------------------------# SymForce - Copyright 2022, Skydio, Inc.# This source code is under the Apache 2.0 license found in the LICENSE file.# ----------------------------------------------------------------------------importfunctoolsfromsymforceimportcodegenfromsymforceimporttypingasTfromsymforce.type_helpersimportsymbolic_inputs_T=T.TypeVar("_T")
[docs]defsymbolic_eval(func:T.Callable[...,_T])->_T:""" Build symbolic arguments for a function, and return the function evaluated on those arguments. Useful for easily visualizing what expressions a symbolic function produces Args: func: A callable; args should have type annotations, and those types should be constructible automatically with :func:`symforce.ops.storage_ops.StorageOps.symbolic` Returns: The outputs of ``func`` evaluated on the constructed symbolic args See also: :func:`symforce.type_helpers.symbolic_inputs` """returnfunc(**symbolic_inputs(func))
[docs]deflambdify(f:T.Callable,use_numba:bool=False)->T.Callable:""" Convert a symbolic function to a numerical one. This is a thin wrapper around :meth:`Codegen.function <symforce.codegen.codegen.Codegen.function>` provided for convenience. Args: f: A callable with symbolic inputs and outputs - see :meth:`Codegen.function <symforce.codegen.codegen.Codegen.function>` for details use_numba: If True, use Numba to compile the generated function. This can be much faster, but has some limitations - see :class:`codegen.PythonConfig <symforce.codegen.backends.python.python_config.PythonConfig>` for details Returns: A numerical function equivalent to ``f`` See also: :meth:`Codegen.lambdify <symforce.codegen.codegen.Codegen.lambdify>` :meth:`Codegen.function <symforce.codegen.codegen.Codegen.function>` :class:`codegen.PythonConfig <symforce.codegen.backends.python.python_config.PythonConfig>` """codegen_obj=codegen.Codegen.function(f,config=codegen.PythonConfig(use_numba=use_numba))returncodegen_obj.lambdify()
[docs]defnumbify(f:T.Callable)->T.Callable:""" Shorthand for ``lambdify(f, use_numba=True)`` See also: :func:`lambdify` """returnlambdify(f,use_numba=True)
[docs]defspecialize_types(f:SymbolicFunction,type_replacements:T.Mapping[T.Type,T.Type])->SymbolicFunction:""" Specialize the type annotations on the given function, replacing any types in ``type_replacements`` For example, this can be used to take a symbolic function that accepts a generic type and generate it for several concrete types:: def f(x: sf.CameraCal) -> sf.Scalar: ... Codegen.function(specialize_types(f, {sf.CameraCal: sf.LinearCameraCal}), ...) Codegen.function(specialize_types(f, {sf.CameraCal: sf.PolynomialCameraCal}), ...) See also: :func:`specialize_args` """@functools.wraps(f)defspecialized_function(*args:T.Any,**kwargs:T.Any)->T.Any:returnf(*args,**kwargs)specialized_function.__annotations__=f.__annotations__.copy()forannotation,clsinspecialized_function.__annotations__.items():ifclsintype_replacements:specialized_function.__annotations__[annotation]=type_replacements[cls]returnT.cast(SymbolicFunction,specialized_function)
[docs]defspecialize_args(f:SymbolicFunction,arg_replacements:T.Mapping[str,T.Type])->SymbolicFunction:""" Specialize the type annotations on the given function, replacing types for any arguments in ``arg_replacements`` For example, this can be used to take a symbolic function that accepts a generic type and generate it for several concrete types:: def f(x: sf.CameraCal, y: sf.CameraCal) -> sf.Scalar: ... Codegen.function( specialize_types(f, {"x": sf.LinearCameraCal, "y": sf.PolynomialCameraCal}), ... ) See also: :func:`specialize_types` """@functools.wraps(f)defspecialized_function(*args:T.Any,**kwargs:T.Any)->T.Any:returnf(*args,**kwargs)specialized_function.__annotations__=f.__annotations__.copy()forannotationinspecialized_function.__annotations__:ifannotationinarg_replacements:specialized_function.__annotations__[annotation]=arg_replacements[annotation]returnT.cast(SymbolicFunction,specialized_function)