mink 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mink/.mypy_cache/.gitignore +2 -0
- mink/.mypy_cache/3.12/@plugins_snapshot.json +1 -0
- mink/.mypy_cache/3.12/__future__.data.json +1 -0
- mink/.mypy_cache/3.12/__future__.meta.json +1 -0
- mink/.mypy_cache/3.12/_ast.data.json +1 -0
- mink/.mypy_cache/3.12/_ast.meta.json +1 -0
- mink/.mypy_cache/3.12/_codecs.data.json +1 -0
- mink/.mypy_cache/3.12/_codecs.meta.json +1 -0
- mink/.mypy_cache/3.12/_collections_abc.data.json +1 -0
- mink/.mypy_cache/3.12/_collections_abc.meta.json +1 -0
- mink/.mypy_cache/3.12/_ctypes.data.json +1 -0
- mink/.mypy_cache/3.12/_ctypes.meta.json +1 -0
- mink/.mypy_cache/3.12/_thread.data.json +1 -0
- mink/.mypy_cache/3.12/_thread.meta.json +1 -0
- mink/.mypy_cache/3.12/_typeshed/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/_typeshed/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/_warnings.data.json +1 -0
- mink/.mypy_cache/3.12/_warnings.meta.json +1 -0
- mink/.mypy_cache/3.12/abc.data.json +1 -0
- mink/.mypy_cache/3.12/abc.meta.json +1 -0
- mink/.mypy_cache/3.12/array.data.json +1 -0
- mink/.mypy_cache/3.12/array.meta.json +1 -0
- mink/.mypy_cache/3.12/ast.data.json +1 -0
- mink/.mypy_cache/3.12/ast.meta.json +1 -0
- mink/.mypy_cache/3.12/builtins.data.json +1 -0
- mink/.mypy_cache/3.12/builtins.meta.json +1 -0
- mink/.mypy_cache/3.12/codecs.data.json +1 -0
- mink/.mypy_cache/3.12/codecs.meta.json +1 -0
- mink/.mypy_cache/3.12/collections/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/collections/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/collections/abc.data.json +1 -0
- mink/.mypy_cache/3.12/collections/abc.meta.json +1 -0
- mink/.mypy_cache/3.12/contextlib.data.json +1 -0
- mink/.mypy_cache/3.12/contextlib.meta.json +1 -0
- mink/.mypy_cache/3.12/ctypes/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/ctypes/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/dataclasses.data.json +1 -0
- mink/.mypy_cache/3.12/dataclasses.meta.json +1 -0
- mink/.mypy_cache/3.12/datetime.data.json +1 -0
- mink/.mypy_cache/3.12/datetime.meta.json +1 -0
- mink/.mypy_cache/3.12/email/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/email/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/email/charset.data.json +1 -0
- mink/.mypy_cache/3.12/email/charset.meta.json +1 -0
- mink/.mypy_cache/3.12/email/contentmanager.data.json +1 -0
- mink/.mypy_cache/3.12/email/contentmanager.meta.json +1 -0
- mink/.mypy_cache/3.12/email/errors.data.json +1 -0
- mink/.mypy_cache/3.12/email/errors.meta.json +1 -0
- mink/.mypy_cache/3.12/email/header.data.json +1 -0
- mink/.mypy_cache/3.12/email/header.meta.json +1 -0
- mink/.mypy_cache/3.12/email/message.data.json +1 -0
- mink/.mypy_cache/3.12/email/message.meta.json +1 -0
- mink/.mypy_cache/3.12/email/policy.data.json +1 -0
- mink/.mypy_cache/3.12/email/policy.meta.json +1 -0
- mink/.mypy_cache/3.12/enum.data.json +1 -0
- mink/.mypy_cache/3.12/enum.meta.json +1 -0
- mink/.mypy_cache/3.12/genericpath.data.json +1 -0
- mink/.mypy_cache/3.12/genericpath.meta.json +1 -0
- mink/.mypy_cache/3.12/importlib/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/importlib/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/importlib/abc.data.json +1 -0
- mink/.mypy_cache/3.12/importlib/abc.meta.json +1 -0
- mink/.mypy_cache/3.12/importlib/machinery.data.json +1 -0
- mink/.mypy_cache/3.12/importlib/machinery.meta.json +1 -0
- mink/.mypy_cache/3.12/importlib/metadata/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/importlib/metadata/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/importlib/metadata/_meta.data.json +1 -0
- mink/.mypy_cache/3.12/importlib/metadata/_meta.meta.json +1 -0
- mink/.mypy_cache/3.12/importlib/readers.data.json +1 -0
- mink/.mypy_cache/3.12/importlib/readers.meta.json +1 -0
- mink/.mypy_cache/3.12/importlib/resources/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/importlib/resources/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/importlib/resources/abc.data.json +1 -0
- mink/.mypy_cache/3.12/importlib/resources/abc.meta.json +1 -0
- mink/.mypy_cache/3.12/io.data.json +1 -0
- mink/.mypy_cache/3.12/io.meta.json +1 -0
- mink/.mypy_cache/3.12/logging/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/logging/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/math.data.json +1 -0
- mink/.mypy_cache/3.12/math.meta.json +1 -0
- mink/.mypy_cache/3.12/mink/limits/limit.data.json +1 -0
- mink/.mypy_cache/3.12/mink/limits/limit.meta.json +1 -0
- mink/.mypy_cache/3.12/mmap.data.json +1 -0
- mink/.mypy_cache/3.12/mmap.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_pytesttester.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_pytesttester.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_add_docstring.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_add_docstring.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_array_like.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_array_like.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_callable.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_callable.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_char_codes.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_char_codes.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_dtype_like.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_dtype_like.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_extended_precision.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_extended_precision.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_nbit.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_nbit.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_nested_sequence.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_nested_sequence.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_scalars.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_scalars.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_shape.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_shape.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_ufunc.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_typing/_ufunc.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_utils/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_utils/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/_utils/_convertions.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/_utils/_convertions.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/_asarray.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/_asarray.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/_internal.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/_internal.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/_type_aliases.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/_type_aliases.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/_ufunc_config.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/_ufunc_config.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/arrayprint.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/arrayprint.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/defchararray.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/defchararray.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/einsumfunc.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/einsumfunc.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/fromnumeric.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/fromnumeric.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/function_base.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/function_base.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/multiarray.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/multiarray.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/numeric.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/numeric.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/numerictypes.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/numerictypes.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/records.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/records.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/shape_base.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/shape_base.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/umath.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/core/umath.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/ctypeslib.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/ctypeslib.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/dtypes.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/dtypes.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/exceptions.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/exceptions.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/fft/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/fft/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/fft/_pocketfft.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/fft/_pocketfft.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/fft/helper.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/fft/helper.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/_version.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/_version.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/arraypad.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/arraypad.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/arraysetops.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/arraysetops.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/arrayterator.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/arrayterator.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/format.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/format.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/function_base.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/function_base.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/histograms.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/histograms.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/index_tricks.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/index_tricks.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/mixins.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/mixins.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/nanfunctions.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/nanfunctions.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/npyio.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/npyio.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/polynomial.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/polynomial.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/scimath.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/scimath.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/shape_base.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/shape_base.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/stride_tricks.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/stride_tricks.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/twodim_base.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/twodim_base.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/type_check.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/type_check.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/ufunclike.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/ufunclike.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/utils.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/lib/utils.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/linalg/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/linalg/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/linalg/linalg.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/linalg/linalg.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/ma/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/ma/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/ma/core.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/ma/core.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/ma/extras.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/ma/extras.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/ma/mrecords.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/ma/mrecords.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/matrixlib/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/matrixlib/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/matrixlib/defmatrix.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/matrixlib/defmatrix.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/_polybase.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/_polybase.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/chebyshev.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/chebyshev.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/hermite.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/hermite.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/hermite_e.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/hermite_e.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/laguerre.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/laguerre.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/legendre.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/legendre.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/polynomial.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/polynomial.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/polyutils.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/polynomial/polyutils.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/_generator.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/_generator.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/_mt19937.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/_mt19937.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/_pcg64.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/_pcg64.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/_philox.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/_philox.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/_sfc64.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/_sfc64.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/bit_generator.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/bit_generator.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/mtrand.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/random/mtrand.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/testing/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/testing/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/testing/_private/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/testing/_private/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/testing/_private/utils.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/testing/_private/utils.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/typing/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/typing/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/numpy/version.data.json +1 -0
- mink/.mypy_cache/3.12/numpy/version.meta.json +1 -0
- mink/.mypy_cache/3.12/os/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/os/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/os/path.data.json +1 -0
- mink/.mypy_cache/3.12/os/path.meta.json +1 -0
- mink/.mypy_cache/3.12/pathlib.data.json +1 -0
- mink/.mypy_cache/3.12/pathlib.meta.json +1 -0
- mink/.mypy_cache/3.12/posixpath.data.json +1 -0
- mink/.mypy_cache/3.12/posixpath.meta.json +1 -0
- mink/.mypy_cache/3.12/re.data.json +1 -0
- mink/.mypy_cache/3.12/re.meta.json +1 -0
- mink/.mypy_cache/3.12/sre_compile.data.json +1 -0
- mink/.mypy_cache/3.12/sre_compile.meta.json +1 -0
- mink/.mypy_cache/3.12/sre_constants.data.json +1 -0
- mink/.mypy_cache/3.12/sre_constants.meta.json +1 -0
- mink/.mypy_cache/3.12/sre_parse.data.json +1 -0
- mink/.mypy_cache/3.12/sre_parse.meta.json +1 -0
- mink/.mypy_cache/3.12/string.data.json +1 -0
- mink/.mypy_cache/3.12/string.meta.json +1 -0
- mink/.mypy_cache/3.12/subprocess.data.json +1 -0
- mink/.mypy_cache/3.12/subprocess.meta.json +1 -0
- mink/.mypy_cache/3.12/sys/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/sys/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/sys/_monitoring.data.json +1 -0
- mink/.mypy_cache/3.12/sys/_monitoring.meta.json +1 -0
- mink/.mypy_cache/3.12/textwrap.data.json +1 -0
- mink/.mypy_cache/3.12/textwrap.meta.json +1 -0
- mink/.mypy_cache/3.12/threading.data.json +1 -0
- mink/.mypy_cache/3.12/threading.meta.json +1 -0
- mink/.mypy_cache/3.12/time.data.json +1 -0
- mink/.mypy_cache/3.12/time.meta.json +1 -0
- mink/.mypy_cache/3.12/types.data.json +1 -0
- mink/.mypy_cache/3.12/types.meta.json +1 -0
- mink/.mypy_cache/3.12/typing.data.json +1 -0
- mink/.mypy_cache/3.12/typing.meta.json +1 -0
- mink/.mypy_cache/3.12/typing_extensions.data.json +1 -0
- mink/.mypy_cache/3.12/typing_extensions.meta.json +1 -0
- mink/.mypy_cache/3.12/unittest/__init__.data.json +1 -0
- mink/.mypy_cache/3.12/unittest/__init__.meta.json +1 -0
- mink/.mypy_cache/3.12/unittest/_log.data.json +1 -0
- mink/.mypy_cache/3.12/unittest/_log.meta.json +1 -0
- mink/.mypy_cache/3.12/unittest/async_case.data.json +1 -0
- mink/.mypy_cache/3.12/unittest/async_case.meta.json +1 -0
- mink/.mypy_cache/3.12/unittest/case.data.json +1 -0
- mink/.mypy_cache/3.12/unittest/case.meta.json +1 -0
- mink/.mypy_cache/3.12/unittest/loader.data.json +1 -0
- mink/.mypy_cache/3.12/unittest/loader.meta.json +1 -0
- mink/.mypy_cache/3.12/unittest/main.data.json +1 -0
- mink/.mypy_cache/3.12/unittest/main.meta.json +1 -0
- mink/.mypy_cache/3.12/unittest/result.data.json +1 -0
- mink/.mypy_cache/3.12/unittest/result.meta.json +1 -0
- mink/.mypy_cache/3.12/unittest/runner.data.json +1 -0
- mink/.mypy_cache/3.12/unittest/runner.meta.json +1 -0
- mink/.mypy_cache/3.12/unittest/signals.data.json +1 -0
- mink/.mypy_cache/3.12/unittest/signals.meta.json +1 -0
- mink/.mypy_cache/3.12/unittest/suite.data.json +1 -0
- mink/.mypy_cache/3.12/unittest/suite.meta.json +1 -0
- mink/.mypy_cache/3.12/warnings.data.json +1 -0
- mink/.mypy_cache/3.12/warnings.meta.json +1 -0
- mink/.mypy_cache/3.12/zipfile.data.json +1 -0
- mink/.mypy_cache/3.12/zipfile.meta.json +1 -0
- mink/.mypy_cache/CACHEDIR.TAG +3 -0
- mink/__init__.py +75 -0
- mink/configuration.py +215 -0
- mink/constants.py +34 -0
- mink/exceptions.py +98 -0
- mink/lie/__init__.py +13 -0
- mink/lie/base.py +156 -0
- mink/lie/se3.py +249 -0
- mink/lie/so3.py +224 -0
- mink/lie/tests/__init__.py +0 -0
- mink/lie/tests/test_axioms.py +51 -0
- mink/lie/tests/test_operations.py +77 -0
- mink/lie/tests/utils.py +20 -0
- mink/lie/utils.py +29 -0
- mink/limits/__init__.py +16 -0
- mink/limits/collision_avoidance_limit.py +274 -0
- mink/limits/configuration_limit.py +126 -0
- mink/limits/exceptions.py +7 -0
- mink/limits/limit.py +41 -0
- mink/limits/velocity_limit.py +92 -0
- mink/py.typed +0 -0
- mink/solve_ik.py +105 -0
- mink/tasks/__init__.py +26 -0
- mink/tasks/com_task.py +82 -0
- mink/tasks/exceptions.py +27 -0
- mink/tasks/frame_task.py +114 -0
- mink/tasks/posture_task.py +103 -0
- mink/tasks/task.py +105 -0
- mink/utils.py +128 -0
- mink-0.0.1.dist-info/METADATA +71 -0
- mink-0.0.1.dist-info/RECORD +352 -0
- mink-0.0.1.dist-info/WHEEL +4 -0
mink/lie/se3.py
ADDED
@@ -0,0 +1,249 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from dataclasses import dataclass
|
4
|
+
|
5
|
+
import mujoco
|
6
|
+
import numpy as np
|
7
|
+
|
8
|
+
from ..exceptions import InvalidMocapBody
|
9
|
+
from .base import MatrixLieGroup
|
10
|
+
from .so3 import SO3
|
11
|
+
from .utils import get_epsilon, skew
|
12
|
+
|
13
|
+
_IDENTITY_WXYZ_XYZ = np.array([1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], dtype=np.float64)
|
14
|
+
|
15
|
+
|
16
|
+
@dataclass(frozen=True)
|
17
|
+
class SE3(MatrixLieGroup):
|
18
|
+
"""Special Euclidean group for proper rigid transforms in 3D.
|
19
|
+
|
20
|
+
Internal parameterization is (qw, qx, qy, qz, x, y, z). Tangent parameterization is
|
21
|
+
(vx, vy, vz, omega_x, omega_y, omega_z).
|
22
|
+
"""
|
23
|
+
|
24
|
+
wxyz_xyz: np.ndarray
|
25
|
+
matrix_dim: int = 4
|
26
|
+
parameters_dim: int = 7
|
27
|
+
tangent_dim: int = 6
|
28
|
+
space_dim: int = 3
|
29
|
+
|
30
|
+
def __repr__(self) -> str:
|
31
|
+
quat = np.round(self.wxyz_xyz[:4], 5)
|
32
|
+
xyz = np.round(self.wxyz_xyz[4:], 5)
|
33
|
+
return f"{self.__class__.__name__}(wxyz={quat}, xyz={xyz})"
|
34
|
+
|
35
|
+
def copy(self) -> SE3:
|
36
|
+
return SE3(wxyz_xyz=np.array(self.wxyz_xyz))
|
37
|
+
|
38
|
+
def parameters(self) -> np.ndarray:
|
39
|
+
return self.wxyz_xyz
|
40
|
+
|
41
|
+
@classmethod
|
42
|
+
def identity(cls) -> SE3:
|
43
|
+
return SE3(wxyz_xyz=_IDENTITY_WXYZ_XYZ)
|
44
|
+
|
45
|
+
@classmethod
|
46
|
+
def from_rotation_and_translation(
|
47
|
+
cls,
|
48
|
+
rotation: SO3,
|
49
|
+
translation: np.ndarray,
|
50
|
+
) -> SE3:
|
51
|
+
assert translation.shape == (SE3.space_dim,)
|
52
|
+
return SE3(wxyz_xyz=np.concatenate([rotation.wxyz, translation]))
|
53
|
+
|
54
|
+
@classmethod
|
55
|
+
def from_rotation(cls, rotation: SO3) -> SE3:
|
56
|
+
return SE3.from_rotation_and_translation(
|
57
|
+
rotation=rotation,
|
58
|
+
translation=np.zeros(
|
59
|
+
SE3.space_dim,
|
60
|
+
),
|
61
|
+
)
|
62
|
+
|
63
|
+
@classmethod
|
64
|
+
def from_translation(cls, translation: np.ndarray) -> SE3:
|
65
|
+
return SE3.from_rotation_and_translation(
|
66
|
+
rotation=SO3.identity(), translation=translation
|
67
|
+
)
|
68
|
+
|
69
|
+
@classmethod
|
70
|
+
def from_matrix(cls, matrix: np.ndarray) -> SE3:
|
71
|
+
assert matrix.shape == (SE3.matrix_dim, SE3.matrix_dim)
|
72
|
+
return SE3.from_rotation_and_translation(
|
73
|
+
rotation=SO3.from_matrix(matrix[:3, :3]),
|
74
|
+
translation=matrix[:3, 3],
|
75
|
+
)
|
76
|
+
|
77
|
+
@classmethod
|
78
|
+
def from_mocap_id(cls, data: mujoco.MjData, mocap_id: int) -> SE3:
|
79
|
+
return SE3.from_rotation_and_translation(
|
80
|
+
rotation=SO3(data.mocap_quat[mocap_id]),
|
81
|
+
translation=data.mocap_pos[mocap_id],
|
82
|
+
)
|
83
|
+
|
84
|
+
@classmethod
|
85
|
+
def from_mocap_name(
|
86
|
+
cls, model: mujoco.MjModel, data: mujoco.MjData, mocap_name: str
|
87
|
+
) -> SE3:
|
88
|
+
mocap_id = model.body(mocap_name).mocapid[0]
|
89
|
+
if mocap_id == -1:
|
90
|
+
raise InvalidMocapBody(mocap_name, model)
|
91
|
+
return SE3.from_mocap_id(data, mocap_id)
|
92
|
+
|
93
|
+
@classmethod
|
94
|
+
def sample_uniform(cls) -> SE3:
|
95
|
+
return SE3.from_rotation_and_translation(
|
96
|
+
rotation=SO3.sample_uniform(),
|
97
|
+
translation=np.random.uniform(-1.0, 1.0, size=(SE3.space_dim,)),
|
98
|
+
)
|
99
|
+
|
100
|
+
def rotation(self) -> SO3:
|
101
|
+
return SO3(wxyz=self.wxyz_xyz[:4])
|
102
|
+
|
103
|
+
def translation(self) -> np.ndarray:
|
104
|
+
return self.wxyz_xyz[4:]
|
105
|
+
|
106
|
+
def as_matrix(self) -> np.ndarray:
|
107
|
+
hmat = np.eye(self.matrix_dim, dtype=np.float64)
|
108
|
+
hmat[:3, :3] = self.rotation().as_matrix()
|
109
|
+
hmat[:3, 3] = self.translation()
|
110
|
+
return hmat
|
111
|
+
|
112
|
+
@classmethod
|
113
|
+
def exp(cls, tangent: np.ndarray) -> SE3:
|
114
|
+
assert tangent.shape == (SE3.tangent_dim,)
|
115
|
+
rotation = SO3.exp(tangent[3:])
|
116
|
+
theta_squared = tangent[3:] @ tangent[3:]
|
117
|
+
use_taylor = theta_squared < get_epsilon(theta_squared.dtype)
|
118
|
+
theta_squared_safe = 1.0 if use_taylor else theta_squared
|
119
|
+
theta_safe = np.sqrt(theta_squared_safe)
|
120
|
+
skew_omega = skew(tangent[3:])
|
121
|
+
if use_taylor:
|
122
|
+
V = rotation.as_matrix()
|
123
|
+
else:
|
124
|
+
V = (
|
125
|
+
np.eye(3, dtype=np.float64)
|
126
|
+
+ (1.0 - np.cos(theta_safe)) / (theta_squared_safe) * skew_omega
|
127
|
+
+ (theta_safe - np.sin(theta_safe))
|
128
|
+
/ (theta_squared_safe * theta_safe)
|
129
|
+
* (skew_omega @ skew_omega)
|
130
|
+
)
|
131
|
+
return SE3.from_rotation_and_translation(
|
132
|
+
rotation=rotation,
|
133
|
+
translation=V @ tangent[:3],
|
134
|
+
)
|
135
|
+
|
136
|
+
def inverse(self) -> SE3:
|
137
|
+
R_inv = self.rotation().inverse()
|
138
|
+
return SE3.from_rotation_and_translation(
|
139
|
+
rotation=R_inv,
|
140
|
+
translation=-(R_inv @ self.translation()),
|
141
|
+
)
|
142
|
+
|
143
|
+
def normalize(self) -> SE3:
|
144
|
+
return SE3.from_rotation_and_translation(
|
145
|
+
rotation=self.rotation().normalize(),
|
146
|
+
translation=self.translation(),
|
147
|
+
)
|
148
|
+
|
149
|
+
def apply(self, target: np.ndarray) -> np.ndarray:
|
150
|
+
assert target.shape == (SE3.space_dim,)
|
151
|
+
return self.rotation() @ target + self.translation()
|
152
|
+
|
153
|
+
def multiply(self, other: SE3) -> SE3:
|
154
|
+
return SE3.from_rotation_and_translation(
|
155
|
+
rotation=self.rotation() @ other.rotation(),
|
156
|
+
translation=(self.rotation() @ other.translation()) + self.translation(),
|
157
|
+
)
|
158
|
+
|
159
|
+
def log(self) -> np.ndarray:
|
160
|
+
omega = self.rotation().log()
|
161
|
+
theta_squared = omega @ omega
|
162
|
+
use_taylor = theta_squared < get_epsilon(theta_squared.dtype)
|
163
|
+
skew_omega = skew(omega)
|
164
|
+
theta_squared_safe = 1.0 if use_taylor else theta_squared
|
165
|
+
theta_safe = np.sqrt(theta_squared_safe)
|
166
|
+
half_theta_safe = 0.5 * theta_safe
|
167
|
+
skew_omega_norm = skew_omega @ skew_omega
|
168
|
+
if use_taylor:
|
169
|
+
V_inv = (
|
170
|
+
np.eye(3, dtype=np.float64) - 0.5 * skew_omega + skew_omega_norm / 12.0
|
171
|
+
)
|
172
|
+
else:
|
173
|
+
V_inv = (
|
174
|
+
np.eye(3, dtype=np.float64)
|
175
|
+
- 0.5 * skew_omega
|
176
|
+
+ (
|
177
|
+
1.0
|
178
|
+
- theta_safe
|
179
|
+
* np.cos(half_theta_safe)
|
180
|
+
/ (2.0 * np.sin(half_theta_safe))
|
181
|
+
)
|
182
|
+
/ theta_squared_safe
|
183
|
+
* skew_omega_norm
|
184
|
+
)
|
185
|
+
return np.concatenate([V_inv @ self.translation(), omega])
|
186
|
+
|
187
|
+
def adjoint(self) -> np.ndarray:
|
188
|
+
R = self.rotation().as_matrix()
|
189
|
+
return np.block(
|
190
|
+
[
|
191
|
+
[R, skew(self.translation()) @ R],
|
192
|
+
[np.zeros((3, 3), dtype=np.float64), R],
|
193
|
+
]
|
194
|
+
)
|
195
|
+
|
196
|
+
# Jacobians.
|
197
|
+
|
198
|
+
# Eqn 179 a)
|
199
|
+
@classmethod
|
200
|
+
def ljac(cls, other: np.ndarray) -> np.ndarray:
|
201
|
+
theta = other[3:]
|
202
|
+
if theta @ theta < get_epsilon(theta.dtype):
|
203
|
+
return np.eye(cls.tangent_dim)
|
204
|
+
Q = _getQ(other)
|
205
|
+
J = SO3.ljac(theta)
|
206
|
+
O = np.zeros((3, 3))
|
207
|
+
return np.block([[J, Q], [O, J]])
|
208
|
+
|
209
|
+
# Eqn 179 b)
|
210
|
+
@classmethod
|
211
|
+
def ljacinv(cls, other: np.ndarray) -> np.ndarray:
|
212
|
+
theta = other[3:]
|
213
|
+
if theta @ theta < get_epsilon(theta.dtype):
|
214
|
+
return np.eye(cls.tangent_dim)
|
215
|
+
Q = _getQ(other)
|
216
|
+
J_inv = SO3.ljacinv(theta)
|
217
|
+
O = np.zeros((3, 3))
|
218
|
+
return np.block([[J_inv, -J_inv @ Q @ J_inv], [O, J_inv]])
|
219
|
+
|
220
|
+
|
221
|
+
# Eqn 180.
|
222
|
+
def _getQ(c) -> np.ndarray:
|
223
|
+
theta_sq = c[3:] @ c[3:]
|
224
|
+
A = 0.5
|
225
|
+
if theta_sq < get_epsilon(theta_sq.dtype):
|
226
|
+
B = (1.0 / 6.0) + (1.0 / 120.0) * theta_sq
|
227
|
+
C = -(1.0 / 24.0) + (1.0 / 720.0) * theta_sq
|
228
|
+
D = -(1.0 / 60.0)
|
229
|
+
else:
|
230
|
+
theta = np.sqrt(theta_sq)
|
231
|
+
sin_theta = np.sin(theta)
|
232
|
+
cos_theta = np.cos(theta)
|
233
|
+
B = (theta - sin_theta) / (theta_sq * theta)
|
234
|
+
C = (1.0 - theta_sq / 2.0 - cos_theta) / (theta_sq * theta_sq)
|
235
|
+
D = ((2) * theta - (3) * sin_theta + theta * cos_theta) / (
|
236
|
+
(2) * theta_sq * theta_sq * theta
|
237
|
+
)
|
238
|
+
V = skew(c[:3])
|
239
|
+
W = skew(c[3:])
|
240
|
+
VW = V @ W
|
241
|
+
WV = VW.T
|
242
|
+
WVW = WV @ W
|
243
|
+
VWW = VW @ W
|
244
|
+
return (
|
245
|
+
+A * V
|
246
|
+
+ B * (WV + VW + WVW)
|
247
|
+
- C * (VWW - VWW.T - 3 * WVW)
|
248
|
+
+ D * (WVW @ W + W @ WVW)
|
249
|
+
)
|
mink/lie/so3.py
ADDED
@@ -0,0 +1,224 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from dataclasses import dataclass
|
4
|
+
from typing import NamedTuple
|
5
|
+
|
6
|
+
import mujoco
|
7
|
+
import numpy as np
|
8
|
+
|
9
|
+
from .base import MatrixLieGroup
|
10
|
+
from .utils import get_epsilon, skew
|
11
|
+
|
12
|
+
_IDENTITIY_WXYZ = np.array([1.0, 0.0, 0.0, 0.0], dtype=np.float64)
|
13
|
+
_INVERT_QUAT_SIGN = np.array([1.0, -1.0, -1.0, -1.0], dtype=np.float64)
|
14
|
+
|
15
|
+
|
16
|
+
class RollPitchYaw(NamedTuple):
|
17
|
+
roll: float
|
18
|
+
pitch: float
|
19
|
+
yaw: float
|
20
|
+
|
21
|
+
|
22
|
+
@dataclass(frozen=True)
|
23
|
+
class SO3(MatrixLieGroup):
|
24
|
+
"""Special orthogonal group for 3D rotations.
|
25
|
+
|
26
|
+
Internal parameterization is (qw, qx, qy, qz). Tangent parameterization is
|
27
|
+
(omega_x, omega_y, omega_z).
|
28
|
+
"""
|
29
|
+
|
30
|
+
wxyz: np.ndarray
|
31
|
+
matrix_dim: int = 3
|
32
|
+
parameters_dim: int = 4
|
33
|
+
tangent_dim: int = 3
|
34
|
+
space_dim: int = 3
|
35
|
+
|
36
|
+
def __post_init__(self) -> None:
|
37
|
+
if self.wxyz.shape != (self.parameters_dim,):
|
38
|
+
raise ValueError(
|
39
|
+
f"Expeced wxyz to be a length 4 vector but got {self.wxyz.shape[0]}."
|
40
|
+
)
|
41
|
+
|
42
|
+
def __repr__(self) -> str:
|
43
|
+
wxyz = np.round(self.wxyz, 5)
|
44
|
+
return f"{self.__class__.__name__}(wxyz={wxyz})"
|
45
|
+
|
46
|
+
def parameters(self) -> np.ndarray:
|
47
|
+
return self.wxyz
|
48
|
+
|
49
|
+
def copy(self) -> SO3:
|
50
|
+
return SO3(wxyz=self.wxyz.copy())
|
51
|
+
|
52
|
+
@classmethod
|
53
|
+
def from_x_radians(cls, theta: float) -> SO3:
|
54
|
+
return SO3.exp(np.array([theta, 0.0, 0.0], dtype=np.float64))
|
55
|
+
|
56
|
+
@classmethod
|
57
|
+
def from_y_radians(cls, theta: float) -> SO3:
|
58
|
+
return SO3.exp(np.array([0.0, theta, 0.0], dtype=np.float64))
|
59
|
+
|
60
|
+
@classmethod
|
61
|
+
def from_z_radians(cls, theta: float) -> SO3:
|
62
|
+
return SO3.exp(np.array([0.0, 0.0, theta], dtype=np.float64))
|
63
|
+
|
64
|
+
@classmethod
|
65
|
+
def from_rpy_radians(
|
66
|
+
cls,
|
67
|
+
roll: float,
|
68
|
+
pitch: float,
|
69
|
+
yaw: float,
|
70
|
+
) -> SO3:
|
71
|
+
return (
|
72
|
+
SO3.from_z_radians(yaw)
|
73
|
+
@ SO3.from_y_radians(pitch)
|
74
|
+
@ SO3.from_x_radians(roll)
|
75
|
+
)
|
76
|
+
|
77
|
+
@classmethod
|
78
|
+
def from_matrix(cls, matrix: np.ndarray) -> SO3:
|
79
|
+
assert matrix.shape == (SO3.matrix_dim, SO3.matrix_dim)
|
80
|
+
wxyz = np.zeros(SO3.parameters_dim, dtype=np.float64)
|
81
|
+
mujoco.mju_mat2Quat(wxyz, matrix.ravel())
|
82
|
+
return SO3(wxyz=wxyz)
|
83
|
+
|
84
|
+
@classmethod
|
85
|
+
def identity(cls) -> SO3:
|
86
|
+
return SO3(wxyz=_IDENTITIY_WXYZ)
|
87
|
+
|
88
|
+
@classmethod
|
89
|
+
def sample_uniform(cls) -> SO3:
|
90
|
+
# Ref: https://lavalle.pl/planning/node198.html
|
91
|
+
u1, u2, u3 = np.random.uniform(
|
92
|
+
low=np.zeros(shape=(3,)),
|
93
|
+
high=np.array([1.0, 2.0 * np.pi, 2.0 * np.pi]),
|
94
|
+
)
|
95
|
+
a = np.sqrt(1.0 - u1)
|
96
|
+
b = np.sqrt(u1)
|
97
|
+
wxyz = np.array(
|
98
|
+
[
|
99
|
+
a * np.sin(u2),
|
100
|
+
a * np.cos(u2),
|
101
|
+
b * np.sin(u3),
|
102
|
+
b * np.cos(u3),
|
103
|
+
],
|
104
|
+
dtype=np.float64,
|
105
|
+
)
|
106
|
+
return SO3(wxyz=wxyz)
|
107
|
+
|
108
|
+
# Eq. 138.
|
109
|
+
def as_matrix(self) -> np.ndarray:
|
110
|
+
mat = np.zeros(9, dtype=np.float64)
|
111
|
+
mujoco.mju_quat2Mat(mat, self.wxyz)
|
112
|
+
return mat.reshape(3, 3)
|
113
|
+
|
114
|
+
def compute_roll_radians(self) -> float:
|
115
|
+
q0, q1, q2, q3 = self.wxyz
|
116
|
+
return np.arctan2(2 * (q0 * q1 + q2 * q3), 1 - 2 * (q1**2 + q2**2))
|
117
|
+
|
118
|
+
def compute_pitch_radians(self) -> float:
|
119
|
+
q0, q1, q2, q3 = self.wxyz
|
120
|
+
return np.arcsin(2 * (q0 * q2 - q3 * q1))
|
121
|
+
|
122
|
+
def compute_yaw_radians(self) -> float:
|
123
|
+
q0, q1, q2, q3 = self.wxyz
|
124
|
+
return np.arctan2(2 * (q0 * q3 + q1 * q2), 1 - 2 * (q2**2 + q3**2))
|
125
|
+
|
126
|
+
def as_rpy_radians(self) -> RollPitchYaw:
|
127
|
+
return RollPitchYaw(
|
128
|
+
roll=self.compute_roll_radians(),
|
129
|
+
pitch=self.compute_pitch_radians(),
|
130
|
+
yaw=self.compute_yaw_radians(),
|
131
|
+
)
|
132
|
+
|
133
|
+
# Paragraph above Appendix B.A.
|
134
|
+
def inverse(self) -> SO3:
|
135
|
+
return SO3(wxyz=self.wxyz * _INVERT_QUAT_SIGN)
|
136
|
+
|
137
|
+
def normalize(self) -> SO3:
|
138
|
+
return SO3(wxyz=self.wxyz / np.linalg.norm(self.wxyz))
|
139
|
+
|
140
|
+
# Eq. 136.
|
141
|
+
def apply(self, target: np.ndarray) -> np.ndarray:
|
142
|
+
assert target.shape == (SO3.space_dim,)
|
143
|
+
padded_target = np.concatenate([np.zeros(1, dtype=np.float64), target])
|
144
|
+
return (self @ SO3(wxyz=padded_target) @ self.inverse()).wxyz[1:]
|
145
|
+
|
146
|
+
def multiply(self, other: SO3) -> SO3:
|
147
|
+
res = np.empty(self.parameters_dim, dtype=np.float64)
|
148
|
+
mujoco.mju_mulQuat(res, self.wxyz, other.wxyz)
|
149
|
+
return SO3(wxyz=res)
|
150
|
+
|
151
|
+
##
|
152
|
+
#
|
153
|
+
##
|
154
|
+
|
155
|
+
# Eq. 132.
|
156
|
+
@classmethod
|
157
|
+
def exp(cls, tangent: np.ndarray) -> SO3:
|
158
|
+
assert tangent.shape == (SO3.tangent_dim,)
|
159
|
+
theta_squared = tangent @ tangent
|
160
|
+
theta_pow_4 = theta_squared * theta_squared
|
161
|
+
use_taylor = theta_squared < get_epsilon(tangent.dtype)
|
162
|
+
safe_theta = 1.0 if use_taylor else np.sqrt(theta_squared)
|
163
|
+
safe_half_theta = 0.5 * safe_theta
|
164
|
+
if use_taylor:
|
165
|
+
real = 1.0 - theta_squared / 8.0 + theta_pow_4 / 384.0
|
166
|
+
imaginary = 0.5 - theta_squared / 48.0 + theta_pow_4 / 3840.0
|
167
|
+
else:
|
168
|
+
real = np.cos(safe_half_theta)
|
169
|
+
imaginary = np.sin(safe_half_theta) / safe_theta
|
170
|
+
wxyz = np.concatenate([np.array([real]), imaginary * tangent])
|
171
|
+
return SO3(wxyz=wxyz)
|
172
|
+
|
173
|
+
# Eq. 133.
|
174
|
+
def log(self) -> np.ndarray:
|
175
|
+
w = self.wxyz[0]
|
176
|
+
norm_sq = self.wxyz[1:] @ self.wxyz[1:]
|
177
|
+
use_taylor = norm_sq < get_epsilon(norm_sq.dtype)
|
178
|
+
norm_safe = 1.0 if use_taylor else np.sqrt(norm_sq)
|
179
|
+
w_safe = w if use_taylor else 1.0
|
180
|
+
atan_n_over_w = np.arctan2(-norm_safe if w < 0 else norm_safe, abs(w))
|
181
|
+
if use_taylor:
|
182
|
+
atan_factor = 2.0 / w_safe - 2.0 / 3.0 * norm_sq / w_safe**3
|
183
|
+
else:
|
184
|
+
if abs(w) < get_epsilon(w.dtype):
|
185
|
+
scl = 1.0 if w > 0.0 else -1.0
|
186
|
+
atan_factor = scl * np.pi / norm_safe
|
187
|
+
else:
|
188
|
+
atan_factor = 2.0 * atan_n_over_w / norm_safe
|
189
|
+
return atan_factor * self.wxyz[1:]
|
190
|
+
|
191
|
+
# Eq. 139.
|
192
|
+
def adjoint(self) -> np.ndarray:
|
193
|
+
return self.as_matrix()
|
194
|
+
|
195
|
+
# Jacobians.
|
196
|
+
|
197
|
+
# Eqn. 145, 174.
|
198
|
+
@classmethod
|
199
|
+
def ljac(cls, other: np.ndarray) -> np.ndarray:
|
200
|
+
theta = np.sqrt(other @ other)
|
201
|
+
use_taylor = theta < get_epsilon(theta.dtype)
|
202
|
+
if use_taylor:
|
203
|
+
t2 = theta**2
|
204
|
+
A = (1.0 / 2.0) * (1.0 - t2 / 12.0 * (1.0 - t2 / 30.0 * (1.0 - t2 / 56.0)))
|
205
|
+
B = (1.0 / 6.0) * (1.0 - t2 / 20.0 * (1.0 - t2 / 42.0 * (1.0 - t2 / 72.0)))
|
206
|
+
else:
|
207
|
+
A = (1 - np.cos(theta)) / (theta**2)
|
208
|
+
B = (theta - np.sin(theta)) / (theta**3)
|
209
|
+
skew_other = skew(other)
|
210
|
+
return np.eye(3) + A * skew_other + B * (skew_other @ skew_other)
|
211
|
+
|
212
|
+
@classmethod
|
213
|
+
def ljacinv(cls, other: np.ndarray) -> np.ndarray:
|
214
|
+
theta = np.sqrt(other @ other)
|
215
|
+
use_taylor = theta < get_epsilon(theta.dtype)
|
216
|
+
if use_taylor:
|
217
|
+
t2 = theta**2
|
218
|
+
A = (1.0 / 12.0) * (1.0 + t2 / 60.0 * (1.0 + t2 / 42.0 * (1.0 + t2 / 40.0)))
|
219
|
+
else:
|
220
|
+
A = (1.0 / theta**2) * (
|
221
|
+
1.0 - (theta * np.sin(theta) / (2.0 * (1.0 - np.cos(theta))))
|
222
|
+
)
|
223
|
+
skew_other = skew(other)
|
224
|
+
return np.eye(3) - 0.5 * skew_other + A * (skew_other @ skew_other)
|
File without changes
|
@@ -0,0 +1,51 @@
|
|
1
|
+
"""Tests for group axioms."""
|
2
|
+
|
3
|
+
from typing import Type
|
4
|
+
|
5
|
+
from absl.testing import absltest, parameterized
|
6
|
+
|
7
|
+
from mink import lie
|
8
|
+
|
9
|
+
from ..base import MatrixLieGroup
|
10
|
+
from .utils import assert_transforms_close
|
11
|
+
|
12
|
+
|
13
|
+
@parameterized.named_parameters(
|
14
|
+
("SO3", lie.SO3),
|
15
|
+
("SE3", lie.SE3),
|
16
|
+
)
|
17
|
+
class TestAxioms(parameterized.TestCase):
|
18
|
+
def test_closure(self, group: Type[MatrixLieGroup]):
|
19
|
+
transform_a = group.sample_uniform()
|
20
|
+
transform_b = group.sample_uniform()
|
21
|
+
composed = transform_a @ transform_b
|
22
|
+
assert_transforms_close(composed, composed.normalize())
|
23
|
+
composed = transform_b @ transform_a
|
24
|
+
assert_transforms_close(composed, composed.normalize())
|
25
|
+
composed = transform_a @ transform_b
|
26
|
+
assert_transforms_close(composed, composed.normalize())
|
27
|
+
|
28
|
+
def test_identity(self, group: Type[MatrixLieGroup]):
|
29
|
+
transform = group.sample_uniform()
|
30
|
+
identity = group.identity()
|
31
|
+
assert_transforms_close(transform, identity @ transform)
|
32
|
+
assert_transforms_close(transform, transform @ identity)
|
33
|
+
|
34
|
+
def test_inverse(self, group: Type[MatrixLieGroup]):
|
35
|
+
transform = group.sample_uniform()
|
36
|
+
identity = group.identity()
|
37
|
+
assert_transforms_close(identity, transform.inverse() @ transform)
|
38
|
+
assert_transforms_close(identity, transform @ transform.inverse())
|
39
|
+
|
40
|
+
def test_associative(self, group: Type[MatrixLieGroup]):
|
41
|
+
transform_a = group.sample_uniform()
|
42
|
+
transform_b = group.sample_uniform()
|
43
|
+
transform_c = group.sample_uniform()
|
44
|
+
assert_transforms_close(
|
45
|
+
(transform_a @ transform_b) @ transform_c,
|
46
|
+
transform_a @ (transform_b @ transform_c),
|
47
|
+
)
|
48
|
+
|
49
|
+
|
50
|
+
if __name__ == "__main__":
|
51
|
+
absltest.main()
|
@@ -0,0 +1,77 @@
|
|
1
|
+
"""Tests for general operation definitions."""
|
2
|
+
|
3
|
+
from typing import Type
|
4
|
+
|
5
|
+
import numpy as np
|
6
|
+
from absl.testing import absltest, parameterized
|
7
|
+
|
8
|
+
from ..base import MatrixLieGroup
|
9
|
+
from ..se3 import SE3
|
10
|
+
from ..so3 import SO3
|
11
|
+
from .utils import assert_transforms_close
|
12
|
+
|
13
|
+
|
14
|
+
@parameterized.named_parameters(
|
15
|
+
("SO3", SO3),
|
16
|
+
("SE3", SE3),
|
17
|
+
)
|
18
|
+
class TestOperations(parameterized.TestCase):
|
19
|
+
def test_inverse_bijective(self, group: Type[MatrixLieGroup]):
|
20
|
+
"""Check inverse of inverse."""
|
21
|
+
transform = group.sample_uniform()
|
22
|
+
assert_transforms_close(transform, transform.inverse().inverse())
|
23
|
+
|
24
|
+
def test_matrix_bijective(self, group: Type[MatrixLieGroup]):
|
25
|
+
"""Check that we can convert to and from matrices."""
|
26
|
+
transform = group.sample_uniform()
|
27
|
+
assert_transforms_close(transform, group.from_matrix(transform.as_matrix()))
|
28
|
+
|
29
|
+
def test_log_exp_bijective(self, group: Type[MatrixLieGroup]):
|
30
|
+
"""Check 1-to-1 mapping for log <=> exp operations."""
|
31
|
+
transform = group.sample_uniform()
|
32
|
+
|
33
|
+
tangent = transform.log()
|
34
|
+
self.assertEqual(tangent.shape, (group.tangent_dim,))
|
35
|
+
|
36
|
+
exp_transform = group.exp(tangent)
|
37
|
+
assert_transforms_close(transform, exp_transform)
|
38
|
+
np.testing.assert_allclose(tangent, exp_transform.log())
|
39
|
+
|
40
|
+
def test_adjoint(self, group: Type[MatrixLieGroup]):
|
41
|
+
transform = group.sample_uniform()
|
42
|
+
omega = np.random.randn(group.tangent_dim)
|
43
|
+
assert_transforms_close(
|
44
|
+
transform @ group.exp(omega),
|
45
|
+
group.exp(transform.adjoint() @ omega) @ transform,
|
46
|
+
)
|
47
|
+
|
48
|
+
def test_rminus(self, group: Type[MatrixLieGroup]):
|
49
|
+
T_wa = group.sample_uniform()
|
50
|
+
T_wb = group.sample_uniform()
|
51
|
+
T_ab = T_wa.inverse() @ T_wb
|
52
|
+
np.testing.assert_allclose(T_wb.rminus(T_wa), T_ab.log())
|
53
|
+
|
54
|
+
def test_rplus(self, group: Type[MatrixLieGroup]):
|
55
|
+
T_wa = group.sample_uniform()
|
56
|
+
T_wb = group.sample_uniform()
|
57
|
+
T_ab = T_wa.inverse() @ T_wb
|
58
|
+
assert_transforms_close(T_wa.rplus(T_ab.log()), T_wb)
|
59
|
+
|
60
|
+
def test_jlog(self, group: Type[MatrixLieGroup]):
|
61
|
+
state = group.sample_uniform()
|
62
|
+
w = np.random.rand(state.tangent_dim) * 1e-4
|
63
|
+
state_pert = state.plus(w).log()
|
64
|
+
state_lin = state.log() + state.jlog() @ w
|
65
|
+
np.testing.assert_allclose(state_pert, state_lin, atol=1e-7)
|
66
|
+
|
67
|
+
|
68
|
+
class TestGroupSpecificOperations(absltest.TestCase):
|
69
|
+
"""Group specific tests."""
|
70
|
+
|
71
|
+
def test_so3_rpy_bijective(self):
|
72
|
+
T = SO3.sample_uniform()
|
73
|
+
assert_transforms_close(T, SO3.from_rpy_radians(*T.as_rpy_radians()))
|
74
|
+
|
75
|
+
|
76
|
+
if __name__ == "__main__":
|
77
|
+
absltest.main()
|
mink/lie/tests/utils.py
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
import numpy as np
|
2
|
+
|
3
|
+
from ..base import MatrixLieGroup
|
4
|
+
from ..se3 import SE3, SO3
|
5
|
+
|
6
|
+
|
7
|
+
def assert_transforms_close(a: MatrixLieGroup, b: MatrixLieGroup) -> None:
|
8
|
+
np.testing.assert_allclose(a.as_matrix(), b.as_matrix(), atol=1e-7)
|
9
|
+
|
10
|
+
# Account for quaternion double cover (q = -q).
|
11
|
+
pa = a.parameters()
|
12
|
+
pb = b.parameters()
|
13
|
+
if isinstance(a, SO3):
|
14
|
+
pa *= np.sign(pa[0])
|
15
|
+
pb *= np.sign(pb[0])
|
16
|
+
elif isinstance(a, SE3):
|
17
|
+
pa[:4] *= np.sign(pa[0])
|
18
|
+
pb[:4] *= np.sign(pb[0])
|
19
|
+
|
20
|
+
np.testing.assert_allclose(pa, pb, atol=1e-7)
|
mink/lie/utils.py
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
import mujoco
|
2
|
+
import numpy as np
|
3
|
+
|
4
|
+
|
5
|
+
def get_epsilon(dtype: np.dtype) -> float:
|
6
|
+
return {
|
7
|
+
np.dtype("float32"): 1e-5,
|
8
|
+
np.dtype("float64"): 1e-10,
|
9
|
+
}[dtype]
|
10
|
+
|
11
|
+
|
12
|
+
def skew(x: np.ndarray) -> np.ndarray:
|
13
|
+
assert x.shape == (3,)
|
14
|
+
wx, wy, wz = x
|
15
|
+
return np.array(
|
16
|
+
[
|
17
|
+
[0.0, -wz, wy],
|
18
|
+
[wz, 0.0, -wx],
|
19
|
+
[-wy, wx, 0.0],
|
20
|
+
]
|
21
|
+
)
|
22
|
+
|
23
|
+
|
24
|
+
def mat2quat(mat: np.ndarray):
|
25
|
+
"""Convert a MuJoCo matrix (9,) to a quaternion (4,)."""
|
26
|
+
assert mat.shape == (9,)
|
27
|
+
quat = np.empty(4, dtype=np.float64)
|
28
|
+
mujoco.mju_mat2Quat(quat, mat)
|
29
|
+
return quat
|
mink/limits/__init__.py
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
"""Kinematic limits."""
|
2
|
+
|
3
|
+
from .collision_avoidance_limit import CollisionAvoidanceLimit
|
4
|
+
from .configuration_limit import ConfigurationLimit
|
5
|
+
from .exceptions import LimitDefinitionError
|
6
|
+
from .limit import Constraint, Limit
|
7
|
+
from .velocity_limit import VelocityLimit
|
8
|
+
|
9
|
+
__all__ = (
|
10
|
+
"ConfigurationLimit",
|
11
|
+
"CollisionAvoidanceLimit",
|
12
|
+
"Constraint",
|
13
|
+
"Limit",
|
14
|
+
"VelocityLimit",
|
15
|
+
"LimitDefinitionError",
|
16
|
+
)
|