# ----------------------------------------------------------------------------# SymForce - Copyright 2022, Skydio, Inc.# This source code is under the Apache 2.0 license found in the LICENSE file.# ----------------------------------------------------------------------------"""API for mathematical groups in python with minimal dependencies. Assumes elementshave appropriate methods, or for the case of scalar types (ints, floats, sympy.Symbols)assumes that the group is reals under addition.This is the recommended API for using these concepts, rather than calling directly on a type."""importabcimportnumpyasnpfrom.group_opsimportGroupOpsfrom.lie_group_opsimportLieGroupOpsfrom.storage_opsimportStorageOps# isort: splitimportsymforce.internal.symbolicassffromsymforceimporttypingasTfromsymforceimporttyping_utilfrom.impl.array_lie_group_opsimportArrayLieGroupOpsfrom.impl.databuffer_storage_opsimportDataBufferStorageOpsfrom.impl.dataclass_lie_group_opsimportDataclassLieGroupOpsfrom.impl.nonetype_lie_group_opsimportNoneTypeLieGroupOps# Register ops for scalars and sequencesfrom.impl.scalar_lie_group_opsimportScalarLieGroupOpsfrom.impl.sequence_lie_group_opsimportSequenceLieGroupOps
[docs]classScalarExpr(abc.ABC):""" Metaclass for scalar expressions :class:`symforce.symbolic.DataBuffer` is a subclass of :class:`sf.Expr <symforce.symbolic.Expr>` but we do not want it to be registered under :class:`ScalarLieGroupOps <symforce.ops.impl.scalar_lie_group_ops.ScalarLieGroupOps>`. """@abc.abstractmethoddef__init__(self,*args:T.Any,**kwargs:T.Any)->None:pass@classmethoddef__subclasshook__(cls,subclass:T.Type)->bool:ifissubclass(subclass,sf.DataBuffer):returnFalsereturnissubclass(subclass,sf.Expr)andisinstance(subclass,type)
forscalar_typeintyping_util.SCALAR_TYPES:LieGroupOps.register(scalar_type,ScalarLieGroupOps)LieGroupOps.register(ScalarExpr,ScalarLieGroupOps)LieGroupOps.register(list,SequenceLieGroupOps)LieGroupOps.register(tuple,SequenceLieGroupOps)LieGroupOps.register(np.ndarray,ArrayLieGroupOps)LieGroupOps.register(T.Dataclass,DataclassLieGroupOps)# We register NoneType to allow dataclasses to have optional fields which default to "None".LieGroupOps.register(type(None),NoneTypeLieGroupOps)
[docs]classLieGroupSymClass(abc.ABC):# noqa: B024""" Metaclass for generated numeric geo classes We use a metaclass here to avoid having `symforce.ops` depend on `sym`, which would make it impossible to generate `sym` from scratch. TODO(aaron): SymClassLieGroupOps does the wrong thing for some methods, e.g. storage_D_tangent returns the wrong type. We should also implement this for the cam classes, which aren't lie groups. """@staticmethoddef__subclasshook__(subclass:T.Type)->bool:forparentinsubclass.__mro__:ifparent.__module__.startswith("sym."):fromsymforceimportgeofromsymforce.ops.interfaces.lie_groupimportLieGroupmaybe_geo_class=getattr(geo,parent.__name__,None)ifmaybe_geo_classisnotNoneandissubclass(maybe_geo_class,LieGroup):returnTruereturnFalse