math.h
Go to the documentation of this file.
1/**
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @author Fabian Reister ( fabian dot reister at kit dot edu )
17 * @date 2021
18 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
19 * GNU General Public License
20 */
21
22#pragma once
23
24#include <algorithm>
25#include <array>
26
27#include <ceres/ceres.h>
28
30{
31
32 /**
33 * @brief Signed, wrapped difference `b - a`, in (-pi, pi].
34 *
35 * `atan2` of the cross and dot products of the two unit vectors. The previous formulation
36 * was `acos` of the dot product alone, which has two problems this one does not have:
37 *
38 * * `acos` is defined on [-1, 1] and the dot product of two unit vectors leaves it by up to
39 * one ulp whenever the angles agree -- which is every straight stretch of a path -- so it
40 * returned NaN for 3.7 % of equal-angle pairs and Ceres rejected the step;
41 * * its derivative is infinite exactly where the angles agree, so the analytic jacobian had
42 * to guard the singularity by returning *zero* there. That is the wrong value: a set of
43 * perfectly aligned waypoints is where the gradient was needed and where it was
44 * suppressed.
45 *
46 * `atan2` is well conditioned for every pair and its derivative is exactly -1 with respect to
47 * `a` and +1 with respect to `b`, everywhere.
48 *
49 * The residual is now signed where it used to be a magnitude. The objective is unchanged:
50 * Ceres squares residuals, and `|b - a|^2 == (b - a)^2` for the wrapped difference.
51 */
52 auto
53 periodicDiff(const auto a, const auto b)
54 {
55 const auto cross = ceres::cos(a) * ceres::sin(b) - ceres::sin(a) * ceres::cos(b);
56 const auto dot = ceres::cos(a) * ceres::cos(b) + ceres::sin(a) * ceres::sin(b);
57
58 return ceres::atan2(cross, dot);
59 }
60
61 /// Partial derivatives of `periodicDiff(a, b)` with respect to `a` and `b`.
62 ///
63 /// Constant, and no longer a guarded singularity: the wrapped difference is locally just
64 /// `b - a`. The wrap itself is not differentiable at +-pi, where the shortest way round
65 /// swaps -- a measure-zero point the minimizer has no reason to sit on, and one the old
66 /// formulation could not represent either.
67 std::array<double, 2> inline periodicDiffJacobian(const auto /*a*/, const auto /*b*/)
68 {
69 return {-1.0, 1.0};
70 }
71
72} // namespace armarx::navigation::global_planning::optimization
std::array< double, 2 > periodicDiffJacobian(const auto, const auto)
Partial derivatives of periodicDiff(a, b) with respect to a and b.
Definition math.h:67
auto periodicDiff(const auto a, const auto b)
Signed, wrapped difference b - a, in (-pi, pi].
Definition math.h:53
Point cross(const Point &x, const Point &y)
Definition point.hpp:35
double dot(const Point &x, const Point &y)
Definition point.hpp:57