-
Notifications
You must be signed in to change notification settings - Fork 8
Add support for the S1 (circle) manifold and its tangent space #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Add simple S1 manifold
Thanks @edxmorgan for the PR! This is indeed a nice addition. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds support for the 1-D circle manifold (S1) and its tangent space, integrates it into the package API, and provides corresponding tests.
- Introduces
S1
andS1Tangent
classes with wrapping, multiplication, inverse, and exp/log maps - Updates exports and generic operations to include S1 and S1Tangent
- Adds unit tests for identity, multiplication, subtraction, and log/exp consistency
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
File | Description |
---|---|
tests/test_liecasadi.py | Adds tests for S1 and S1Tangent functionality |
src/liecasadi/s1.py | Implements S1 manifold and S1Tangent operations |
src/liecasadi/init.py | Exports S1 and S1Tangent |
README.md | Updates documentation to include S1 support |
Comments suppressed due to low confidence (2)
src/liecasadi/s1.py:24
- Using a raw float for the identity angle may cause type mismatches with CasADi symbolic types; consider using
cs.DM(0)
or a CasADi scalar constructor to maintain consistency.
return S1(0.0)
src/liecasadi/s1.py:78
- [nitpick] For consistency with
S1.as_angle()
, consider renamingvalue()
toas_value()
oras_scalar()
to clearly convey its purpose.
def value(self) -> Scalar:
tests/test_liecasadi.py
Outdated
# S1 objects | ||
S1_angle = (np.random.rand() - 0.5) * 2 * np.pi | ||
myS1 = S1(S1_angle) | ||
|
||
# S1Tangent objects | ||
S1_tangent_ang = (np.random.rand() - 0.5) * 2 * np.pi | ||
myS1Tang = S1Tangent(S1_tangent_ang) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Remove or utilize the unused variables S1_angle
, myS1
, S1_tangent_ang
, and myS1Tang
in the test file to eliminate noise and improve maintainability.
# S1 objects | |
S1_angle = (np.random.rand() - 0.5) * 2 * np.pi | |
myS1 = S1(S1_angle) | |
# S1Tangent objects | |
S1_tangent_ang = (np.random.rand() - 0.5) * 2 * np.pi | |
myS1Tang = S1Tangent(S1_tangent_ang) | |
# Removed unused variables S1_angle, myS1, S1_tangent_ang, and myS1Tang. |
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
S1_angle, myS1, S1_tangent_ang, and myS1Tang unused variables removed
@Giulero review required. thanks |
Hi @edxmorgan ! Left a comment related to the function that wraps to pi - see the review. What do you think? |
@Giulero I'm sorry but i am unable to find this comment. can you please point it out with a quote reply |
No worries! I mean this comment #19 (comment) |
okay . I see. I am able to partially read it like this. I think github has a bug (https://github.com/orgs/community/discussions/30638). The comment itself does not exist for me. |
Uh I see! This is what i wrote, related to https://github.com/edxmorgan/liecasadi/blob/e02f79e6d090ced2e95bf72ae0d41540eee0e6c9/src/liecasadi/s1.py#L7-L9 I'm not sure this function is continuous and differentiable :/ def _wrap_to_pi(angle: Scalar) -> Scalar:
s = cs.sin(angle)
c = cs.cos(angle)
return cs.atan2(s, c) which should be continuous. |
Hi @Giulero, excellent catch!
I’ll replace the current implementation with this function. Thanks for spotting it! 🚀 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me! Thanks @edxmorgan :)
I think we can merge
from liecasadi.hints import Angle, Scalar | ||
|
||
|
||
def _wrap_to_pi(angle: Scalar) -> Scalar: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this function is continuous and differentiable :/
A possible solution could be to use something like
def _wrap_to_pi(angle: Scalar) -> Scalar:
s = cs.sin(angle)
c = cs.cos(angle)
return cs.atan2(s, c)
which should be continuous.
The issue is when angle == 0.0
, but maybe adding a small tolerance np.finfo().eps
could solve this.
@edxmorgan what do you think?
cc @edxmorgan
assert float(rebuilt.as_angle()) == pytest.approx(float(cs.pi / 3)) | ||
|
||
tangent = a.log() | ||
assert float(tangent.exp().as_angle()) == pytest.approx(float(cs.pi / 3)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
End of line missing!
@@ -2,8 +2,8 @@ | |||
import numpy as np | |||
import pytest | |||
from scipy.spatial.transform import Rotation | |||
|
|||
from liecasadi import SE3, SO3, SE3Tangent, SO3Tangent | |||
import casadi as cs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With a new module, it could make sense to split the tests into multiple files. But we can do it in a different pr
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right! Splitting the tests into separate files will make it look organized. I’ll open a PR for that.
Support for the 1-D circle manifold (S1) by: