Skip to content
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

Correct UnitQuaternion with Quaternions.jl #175

Merged
merged 23 commits into from
Nov 10, 2021

Conversation

hyrodium
Copy link
Collaborator

@hyrodium hyrodium commented Oct 29, 2021

This PR branch is based on #173, so please merge the PR first.

Done

  • Add dependency on Quaternions.jl
  • Remove some incorrect methods
    • conj(::UnitQuaternion)
    • -(::UnitQuaternion)
    • *(::Real, ::UnitQuaternion)
    • LinearAlgebra.norm(::Real, ::UnitQuaternion)
    • LinearAlgebra.normalize(::Real, ::UnitQuaternion)
    • (and etc.)
  • Add type conversion
    • UnitQuaterinon <-> Quaternion
  • Update Rotations.pure_quaternion
    • Rename to _pure_quaternion because this is "private" method.
    • The return value type is now Quaternion. (previously, UnitQuaternion)

WIP, not in this PR

  • UnitQuaternoin{T} sitll have fields w::T, x::T, y::T and z::T, not q::Quaternion{T}.
    • I'd like to keep this PR small, so this filed will be changed in another PR.
  • The name of unit quaternion type is still UnitQuaternion.
    • This will be changed to QuatRotation in the future.
  • The return value type of _pure_quaternion is Quaternion.
    • This should be InfinitesimalQuatRotation <: InfinitesimalRotation in the future.

@hyrodium hyrodium changed the title Correct quaternion with Quaternions.jl Correct UnitQuaternion with Quaternions.jl Oct 29, 2021
@codecov
Copy link

codecov bot commented Oct 29, 2021

Codecov Report

Merging #175 (de9cb6c) into master (d34316c) will decrease coverage by 0.22%.
The diff coverage is 68.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #175      +/-   ##
==========================================
- Coverage   86.33%   86.11%   -0.23%     
==========================================
  Files          14       14              
  Lines        1325     1340      +15     
==========================================
+ Hits         1144     1154      +10     
- Misses        181      186       +5     
Impacted Files Coverage Δ
src/mrps.jl 33.56% <ø> (-0.47%) ⬇️
src/rodrigues_params.jl 98.61% <ø> (-0.02%) ⬇️
src/core_types.jl 90.22% <50.00%> (-0.46%) ⬇️
src/unitquaternion.jl 94.05% <71.42%> (-2.13%) ⬇️
src/principal_value.jl 100.00% <0.00%> (+4.16%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update d34316c...de9cb6c. Read the comment docs.

@hyrodium
Copy link
Collaborator Author

Please ignore the coverage changes. This will be fixed when changing the field of UnitQuaternion.

@hyrodium
Copy link
Collaborator Author

hyrodium commented Oct 29, 2021

The operators for UnitQuaternion such as conj, * and - were bugs, but some users might think that was a feature.
Is it okay to release these changes in patch version(v1.0.4)? Or, should we release minor version(v1.1.0)? (cf. #176)

@hyrodium
Copy link
Collaborator Author

hyrodium commented Oct 29, 2021

I haven't added the [compat] table in Project.toml for Quaternions because I'd like to check that CompatHeler works fine. (#145)

Copy link
Contributor

@andyferris andyferris left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice @hyrodium.

I have no idea whether this is a bugfix or a breaking change. It's not exactly a new feature. It's possible that someone will rely on the current functionality.

vecnorm(q::UnitQuaternion) = sqrt(q.x^2 + q.y^2 + q.z^2)
vecnorm(q::Quaternion) = sqrt(q.v1^2 + q.v2^2 + q.v3^2)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't be defining things on behalf of Quaternions.jl.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that was my mistake. I've removed the line.


# Norms
LinearAlgebra.norm(q::UnitQuaternion) = sqrt(q.w^2 + q.x^2 + q.y^2 + q.z^2)
vecnorm(q::UnitQuaternion) = sqrt(q.x^2 + q.y^2 + q.z^2)
Copy link
Contributor

@andyferris andyferris Oct 31, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The vecnorm must be defined in terms of the matrix. Which is orthogonal, so that's easy. Should we just define this instead?

vecnorm(::Rotation{N, T}) where {N, T} = convert(T, N)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The vecnorm function was to calculate the norm of the imaginary part of a quaternion, and it was used only in _log_as_quat. So, I've removed the function. (09e0313)

Comment on lines 315 to 318
(\)(q1::UnitQuaternion, q2::UnitQuaternion) = inv(q1)*q2 # Equivalent to inv(q1)*q2
(/)(q1::UnitQuaternion, q2::UnitQuaternion) = q1*inv(q2) # Equivalent to q1*inv(q2)


(\)(q1::UnitQuaternion, q2::UnitQuaternion) = conj(q1)*q2 # Equivalent to inv(q1)*q2
(/)(q1::UnitQuaternion, q2::UnitQuaternion) = q1*conj(q2) # Equivalent to q1*inv(q2)

(\)(q::UnitQuaternion, r::SVector{3}) = conj(q)*r # Equivalent to inv(q)*r
(\)(q::UnitQuaternion, r::SVector{3}) = inv(q)*r # Equivalent to inv(q)*r
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't these defined for all rotations? (I.e. can they be deleted instead?)

Copy link
Collaborator Author

@hyrodium hyrodium Oct 31, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With original definition:

julia> @benchmark q\SVector(1,2,3)  # q isa UnitQuaternion
BenchmarkTools.Trial: 10000 samples with 996 evaluations.
 Range (min  max):  25.933 ns   1.724 μs  ┊ GC (min  max): 0.00%  97.61%
 Time  (median):     26.546 ns              ┊ GC (median):    0.00%
 Time  (mean ± σ):   28.727 ns ± 42.051 ns  ┊ GC (mean ± σ):  3.85% ±  2.59%

  ▂▆█▇▄▂                        ▁▂▂▂▂▂▁▁                      ▁
  ██████▇▆▇▆▆▆▅▅▅▅▃▅▅▆▆▆▅▅▅▆▇▇▇██████████▇▆▆▆▅▄▄▆▆▆▅▅▆▅▄▅▄▄▄▆ █
  25.9 ns      Histogram: log(frequency) by time      38.8 ns <

 Memory estimate: 32 bytes, allocs estimate: 1.

If Removing the definition:

julia> @benchmark q\SVector(1,2,3)  # q isa UnitQuaternion
BenchmarkTools.Trial: 10000 samples with 780 evaluations.
 Range (min  max):  160.083 ns   2.153 μs  ┊ GC (min  max): 0.00%  92.03%
 Time  (median):     164.683 ns              ┊ GC (median):    0.00%
 Time  (mean ± σ):   167.640 ns ± 44.395 ns  ┊ GC (mean ± σ):  0.59% ±  2.06%

        ▂▃█▁▁                                                   
  ▂▂▁▁▃▇█████▇▇▇▄▄▃▃▃▃▃▃▃▄▄▄▄▃▃▃▃▃▃▃▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂ ▃
  160 ns          Histogram: frequency by time          186 ns <

 Memory estimate: 32 bytes, allocs estimate: 1.

This performance deterioration is because (\)(::Rotation, ::SVector{3}) is not defined.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, we need to update the \ definition here. With this update, we'll get more performance with other rotation types.

julia> using Rotations, StaticArrays, BenchmarkTools

julia> r = RotX(2.3)
3×3 RotX{Float64} with indices SOneTo(3)×SOneTo(3)(2.3):
 1.0   0.0        0.0
 0.0  -0.666276  -0.745705
 0.0   0.745705  -0.666276

julia> @benchmark r\SVector(1,2,3)
BenchmarkTools.Trial: 10000 samples with 861 evaluations.
 Range (min  max):  138.636 ns   1.605 μs  ┊ GC (min  max): 0.00%  90.34%
 Time  (median):     154.602 ns              ┊ GC (median):    0.00%
 Time  (mean ± σ):   156.485 ns ± 31.911 ns  ┊ GC (mean ± σ):  0.45% ±  2.01%

                             ▂▇▇▅█▆▄▃▄                          
  ▂▁▁▁▁▂▁▂▂▁▂▂▂▂▂▂▂▂▃▂▂▃▃▄▄▄▆█████████▇█▄▃▄▃▄▃▄▄▄▄▅▅▅▄▃▃▂▂▂▂▂▂ ▄
  139 ns          Histogram: frequency by time          168 ns <

 Memory estimate: 32 bytes, allocs estimate: 1.

julia> Base.:\(r::Rotation, v::SVector{3}) = inv(r)*v

julia> @benchmark r\SVector(1,2,3)
BenchmarkTools.Trial: 10000 samples with 994 evaluations.
 Range (min  max):  29.926 ns   1.726 μs  ┊ GC (min  max): 0.00%  97.98%
 Time  (median):     30.742 ns              ┊ GC (median):    0.00%
 Time  (mean ± σ):   32.839 ns ± 44.139 ns  ┊ GC (mean ± σ):  3.54% ±  2.59%

  ▃███▇▅▃▂                     ▁▂▂▂▂▂▂▂▁                      ▂
  ██████████▇▇▇▆▇█▆▆▆▆▅▆▇▆▆▇▇▇███████████▇▆▆▅▅▅▆▅▅▆▅▄▄▄▅▅▅▅▅▆ █
  29.9 ns      Histogram: log(frequency) by time      43.2 ns <

 Memory estimate: 32 bytes, allocs estimate: 1.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added the method. (9647c84)

@hyrodium
Copy link
Collaborator Author

hyrodium commented Nov 4, 2021

I have no idea whether this is a bugfix or a breaking change. It's not exactly a new feature. It's possible that someone will rely on the current functionality.

Should we release v2.0.0? I'd like to think that was a bug...

@hyrodium
Copy link
Collaborator Author

hyrodium commented Nov 8, 2021

@andyferris
Can I merge this PR? I've committed after your approval.

Copy link
Contributor

@andyferris andyferris left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hyrodium yes feel free to merge

@hyrodium hyrodium merged commit 39a2f3c into JuliaGeometry:master Nov 10, 2021
@bzinberg bzinberg mentioned this pull request Nov 12, 2021
hyrodium added a commit that referenced this pull request Nov 13, 2021
* remove incorrect log(::Quaternion)

* add method for log(::Rotation) and return SMatrix

* fix log method for Rotation{2}

* update tests for logarithm function

* add dependency on Quaternions.jl

* update exports for deprecated types

* update around pure_quaternion

* remove incorrect LinearAlgebra.norm

* remove incorrect *(::Real, UnitQuaternion)

* remove incorrect conj(Quaternion)

* remove incorrect -(::UnitQuaternion)

* update tests around norm related functions

* update src and test around norm related functions

* remove unnecessary import from Base

* remove exp method for Quaternion

* update type conversions UnitQuaternion <-> Quaternion

* fix tests for Julia under v1.5

* remove unnecessary lines

* remove vecnorm(q::UnitQuaternion) function

* update comments

* add methods for Base.:\(r::Rotation, v)

* update UnitQuaternion constructor
@hyrodium hyrodium mentioned this pull request Nov 17, 2021
@dehann
Copy link

dehann commented Nov 22, 2021

Kindly request in future to please add deprecation cycles as per semver for breaking changes. You can easily overload Base.get/setproperty with a deprecation warning. In our case I had to dig to find out why quat.w no longer worked, which was replaced by quat.q.s or .v1/v2/v3. Here is a pattern example we use in such cases:
https://github.com/JuliaRobotics/IncrementalInference.jl/wiki/Coding-Templates#deprecate-struct-field

@hyrodium
Copy link
Collaborator Author

hyrodium commented Nov 22, 2021

@dehann
Sorry for the inconvenience. I thought the fields are just internal parameters because we provide Rotations.params method.
This function is not exported, but will be maintained.

And related things, I think we need to distinguish among exported method, non-exported method and internal use method.

  • exported method
    • e.g.RotXYZ, nearest_rotation
    • These methods should be maintained.
  • non-exported method
    • e.g. Rotations.params, Rotations.jacobian
    • These methods also should be maintained.
    • The reason for non-exported is just avoiding name conflict.
  • internal use method

@bzinberg
Copy link

@dehann, thanks for your insights on this! The breakage now has its own issue, #208, let's move discussion there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants