Source code for symforce.ops.storage_ops

# ----------------------------------------------------------------------------
# SymForce - Copyright 2022, Skydio, Inc.
# This source code is under the Apache 2.0 license found in the LICENSE file.
# ----------------------------------------------------------------------------

import symforce.internal.symbolic as sf
from symforce import typing as T
from symforce.typing_util import get_type
from symforce.typing_util import scalar_like

from .ops import Ops


[docs]class StorageOps(Ops): """ API for symbolic data types that can be serialized to and from a vector of scalar quantities. """
[docs] @staticmethod def storage_dim(a: T.ElementOrType) -> int: """ Size of the element's storage, aka the number of scalar values it contains. """ return StorageOps.implementation(get_type(a)).storage_dim(a)
[docs] @staticmethod def to_storage(a: T.Element) -> T.List: """ Serialization of the underlying storage into a list. This is NOT a tangent space. Args: a: Returns: list: Length equal to `storage_dim(a)` """ return StorageOps.implementation(get_type(a)).to_storage(a)
[docs] @staticmethod def from_storage(a: T.ElementOrType, elements: T.Sequence[T.Scalar]) -> T.Element: """ Construct from a flat list representation. Opposite of :meth:`to_storage`. """ return StorageOps.implementation(get_type(a)).from_storage(a, elements)
[docs] @staticmethod def symbolic(a: T.ElementOrType, name: str, **kwargs: T.Dict) -> T.Element: """ Construct a symbolic element with the given name prefix. Args: a: name: String prefix kwargs: Additional arguments to pass to :class:`sf.Symbol <symforce.symbolic.Symbol>` (like assumptions) Returns: Storage: """ return StorageOps.implementation(get_type(a)).symbolic(a, name, **kwargs)
[docs] @staticmethod def evalf(a: T.Element) -> T.Element: """ Evaluate to a numerical quantity (rationals, trig functions, etc). """ def evalf_scalar(s: T.Scalar) -> T.Scalar: if hasattr(s, "evalf"): return s.evalf() if scalar_like(s): return s raise TypeError return StorageOps.from_storage(a, [evalf_scalar(s) for s in StorageOps.to_storage(a)])
[docs] @staticmethod def subs(a: T.Element, *args: T.Any, **kwargs: T.Any) -> T.Element: # We convert to a Matrix here so that we can call `.subs` once, which is faster return StorageOps.from_storage( a, list(iter(sf.sympy.Matrix(StorageOps.to_storage(a)).subs(*args, **kwargs))) )
[docs] @staticmethod def simplify(a: T.Element) -> T.Element: return StorageOps.from_storage( a, list(sf.simplify(sf.sympy.Matrix(StorageOps.to_storage(a)))) )
_use_latex_friendly_symbols = False
[docs] @classmethod def use_latex_friendly_symbols(cls) -> bool: """ Should `StorageOps.symbolic` produce symbols names that are LaTeX-friendly, as opposed to plaintext friendly? """ return cls._use_latex_friendly_symbols
[docs] @classmethod def set_use_latex_friendly_symbols(cls, value: bool) -> None: """ Should `StorageOps.symbolic` produce symbols names that are LaTeX-friendly, as opposed to plaintext friendly? """ cls._use_latex_friendly_symbols = value