Skip to content

Instantly share code, notes, and snippets.

@alok
Last active July 18, 2024 00:57
Show Gist options
  • Save alok/a8c0d575b3d39eab28d894968990f866 to your computer and use it in GitHub Desktop.
Save alok/a8c0d575b3d39eab28d894968990f866 to your computer and use it in GitHub Desktop.
author comments layout mathjax slug title
Alok Singh
true
post
true
noncommutative-3d-rotations
Exploring Non-Commutative 3D Rotations with Grassmann Algebra

People find rotation hard because when we try to visualize something, often we project it onto a 2D plane. But for rotations, this loses the plot because 2D rotations DO commute. In this post, we will (symbolically) explore this non-commutative nature of 3D rotations using Grassmann algebra in Julia. We'll use the Grassmann package to define rotors and demonstrate how the order of rotations matters in three-dimensional space.

I'll set up our 3D space and define a function to create rotors:

using Grassmann

@basis 3 # Define a 3D space

# Function to create a rotor from a bivector and an angle
function rotor(bivector, angle)
    return exp(-angle/2 * bivector)
end

Next, we'll create two different rotations:

# Create two different rotations
rotation_xy = rotor(v12, π/4)  # Rotation in xy-plane by π/4
rotation_yz = rotor(v23, π/3)  # Rotation in yz-plane by π/3

Now, let's compute the composition of rotations in different orders:

# Compute the composition of rotations in different orders
rotor_ab = rotation_yz * rotation_xy
rotor_ba = rotation_xy * rotation_yz
# Demonstrate that squaring rotation_xy results in a π/2 rotation
rotation_xy_squared = rotation_xy * rotation_xy

We'll also create a π/2 rotation in the xy-plane for comparison:

# Create a π/2 rotation in the xy-plane for comparison
rotation_xy_pi_half = rotor(v12, π/2)

Let's print out the results:

println("\nRotation XY squared:")
println(rotation_xy_squared)
println("\nRotation XY by π/2:")
println(rotation_xy_pi_half)
println("\nAre they equal?")
println(rotation_xy_squared  rotation_xy_pi_half)

Optional: Apply to a test vector for visual confirmation:

# Optional: Apply to a test vector for visual confirmation
test_vector_xy = v1 + v2
result_squared = rotation_xy_squared * test_vector_xy * ~rotation_xy_squared
result_pi_half = rotation_xy_pi_half * test_vector_xy * ~rotation_xy_pi_half

println("\nApplied to test vector (1,1,0):")
println("Result of squared rotation:", result_squared)
println("Result of π/2 rotation:", result_pi_half)
println("Are the results equal?", result_squared  result_pi_half)

Now, let's print out the rotors:

println("Rotor XY then YZ:")
println(rotor_ab)
println("\nRotor YZ then XY:")
println(rotor_ba)
println("\nAre the rotors equal?")
println(rotor_ab  rotor_ba)

Optional: Verify the non-commutativity by applying to a test vector:

test_vector = v1 + v2 + v3
result_ab = rotor_ab * test_vector * ~rotor_ab
result_ba = rotor_ba * test_vector * ~rotor_ba

println("\nApplied to test vector (1,1,1):")
println("Result AB:", result_ab)
println("Result BA:", result_ba)
println("Are the results equal?", result_ab  result_ba)

println("\n--- Demonstrating 2D Rotation Commutativity ---")

Create a random complex number

z = complex(rand(), rand()) println("Random complex number z: ", z)

Create two random angles for rotation

θ1, θ2 = 2π * rand(), 2π * rand() println("Random angles: θ1 = ", θ1, ", θ2 = ", θ2)

Perform rotations in different orders

rotation1 = exp(im * θ1) * exp(im * θ2) * z rotation2 = exp(im * θ2) * exp(im * θ1) * z

println("\nRotation 1 (θ1 then θ2): ", rotation1) println("Rotation 2 (θ2 then θ1): ", rotation2) println("Are the results equal? ", isapprox(rotation1, rotation2, atol=1e-10))

Convert complex numbers to Grassmann algebra representation

function complex_to_grassmann(z::Complex) return real(z) + imag(z) * v12 end

Perform the same rotations using Grassmann algebra

z_grassmann = complex_to_grassmann(z) rotation1_grassmann = rotor(v12, θ1) * rotor(v12, θ2) * z_grassmann * ~rotor(v12, θ2) * ~rotor(v12, θ1) rotation2_grassmann = rotor(v12, θ2) * rotor(v12, θ1) * z_grassmann * ~rotor(v12, θ1) * ~rotor(v12, θ2)

println("\nGrassmann Rotation 1 (θ1 then θ2): ", rotation1_grassmann) println("Grassmann Rotation 2 (θ2 then θ1): ", rotation2_grassmann) println("Are the Grassmann results equal? ", rotation1_grassmann ≈ rotation2_grassmann)

Results:

# Rotation XY squared:
0.7071067811865475 - 0.7071067811865476v₁₂

# Rotation XY by π/2:
0.7071067811865476 - 0.7071067811865475v₁₂

# Are they equal?
true

# Applied to test vector (1,1,0):
# Result of squared rotation:
-1.0v₁ + 1.0v₂ + 0.0v₃ + 0.0v₁₂₃

# Result of π/2 rotation:
-1.0v₁ + 1.0v₂ + 0.0v₃ + 0.0v₁₂₃

# Are the results equal?
true

# Rotor XY then YZ:
0.800103 - 0.331414v₁₂ - 0.191342v₁₃ - 0.46194v₂₃

# Rotor YZ then XY:
0.800103 - 0.331414v₁₂ + 0.191342v₁₃ - 0.46194v₂₃

# Are the rotors equal?
false

# Applied to test vector (1,1,1):
# AB:
-5.55112e-17v₁ - 0.158919v₂ + 1.72474v₃ + 0.0v₁₂₃
# BA:
0.965926v₁ + 0.448288v₂ + 1.36603v₃ + 0.0v₁₂₃
# Are the results equal?
false

# Random complex number z: 0.5 + 0.5im
# Random angles: θ1 = 3.141592653589793, θ2 = 1.5707963267948966
# Rotation 1 (θ1 then θ2): 0.5 - 0.5im
# Rotation 2 (θ2 then θ1): 0.5 - 0.5im
# Are the results equal? true
# Grassmann Rotation 1 (θ1 then θ2): 0.5 - 0.5v₁₂
# Grassmann Rotation 2 (θ2 then θ1): 0.5 - 0.5v₁₂
# Are the Grassmann results equal? true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment