This page demonstrates a method for iterative optimization of a function from SO(3) to the real numbers using Python. The theory behind the method is described in
@article{taylor1994minimization, title={Minimization on the Lie group SO (3) and related manifolds}, author={Taylor, Camillo J and Kriegman, David J}, journal={Yale University}, volume={16}, pages={155}, year={1994} }
Consider the vectors uⱼ ∈ R³ and vⱼ ∈ R³ indexed by j. The code below finds the rotation matrix R ∈ SO(3) that gives the maximal value of the function f(R) = ∑ⱼ (uⱼᵀ R vⱼ )^2.
The output from the program shows that Rn ∈ SO(3) comes closer to the desired Rd ∈ SO(3) for each iteration.
optimize.py
import numpy from scipy.linalg import expm numpy.set_printoptions(formatter={'float': '{: 0.3f}'.format}) def cv(vec): return numpy.array(vec, dtype=float).reshape(-1,1) def hat(v): return numpy.array([[0, -v[2], v[1]], [v[2], 0, -v[0]], [-v[1], v[0], 0]]) # R desired. This is the rotation matrix that we want to recover # by finding the maximal value of f(R). Rd = expm(hat([0.4, 0, 0])) @ expm(hat([0, 0.2, 0])) @ expm(hat([0, 0, -0.2])) v_vecs = [cv([0, 0, 1]), cv([0, 1, 0]), cv([1, 0, 0])] u_vecs = [Rd @ v for v in v_vecs] def f(R): Σ = 0.0 for u,v in zip(u_vecs, v_vecs): Σ += (u.T @ R @ v)[0,0]**2 return Σ def df_domega(R): Σ1, Σ2, Σ3 = 0.0, 0.0, 0.0 ω1, ω2, ω3 = hat([1, 0, 0]), hat([0, 1, 0]), hat([0, 0, 1]) for u,v in zip(u_vecs, v_vecs): Σ1 += (u.T @ R @ v)[0,0] * (u.T @ R @ ω1 @ v)[0,0] Σ2 += (u.T @ R @ v)[0,0] * (u.T @ R @ ω2 @ v)[0,0] Σ3 += (u.T @ R @ v)[0,0] * (u.T @ R @ ω3 @ v)[0,0] return Σ1, Σ2, Σ3 def print_result(Rn): diff = Rd.T @ Rn output = '''Fasit: {0} Rn: {3} diff: {6} {1} {4} {7} {2} {5} {8}'''.format(Rd[0], Rd[1], Rd[2], Rn[0], Rn[1], Rn[2], diff[0], diff[1], diff[2]) print(output) Rn = numpy.eye(3) def step(Rn): dω = df_domega(Rn) return Rn @ expm(hat(dω) * 0.04) for i in range(100): Rn = step(Rn) print_result(Rn)