gtsam
Loading...
Searching...
No Matches
QuadraticRangeFactor.h
Go to the documentation of this file.
1/* ----------------------------------------------------------------------------
2
3 * GTSAM Copyright 2010, Georgia Tech Research Corporation,
4 * Atlanta, Georgia 30332-0415
5 * All Rights Reserved
6 * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
7
8 * See LICENSE for the license information
9
10 * -------------------------------------------------------------------------- */
11
38
39#pragma once
40
41#include <gtsam/base/Matrix.h>
42#include <gtsam/constrained/QcqpProblem.h>
43#include <gtsam/constrained/QpCost.h>
44#include <gtsam/constrained/QuadraticConstraint.h>
45#include <gtsam/geometry/Rot2.h>
46#include <gtsam/geometry/Unit3.h>
49
50#include <cmath>
51#include <stdexcept>
52#include <string>
53#include <type_traits>
54
55namespace gtsam {
56
57template <int d>
59 : public NoiseModelFactorN<
60 Eigen::Matrix<double, d, 1>, Eigen::Matrix<double, d, 1>,
61 typename std::conditional<d == 2, Rot2, Unit3>::type> {
62 static_assert(d == 2 || d == 3, "QuadraticRangeFactor supports d = 2 or 3.");
63
64 using Point = Eigen::Matrix<double, d, 1>;
66 using Direction = typename std::conditional<d == 2, Rot2, Unit3>::type;
68
69 double range_;
70 double weight_;
71
72 public:
75 static constexpr int kDirectionRows = (d == 2) ? 2 : 1;
76
78
86 QuadraticRangeFactor(Key translationKey, Key targetKey, Key unitVectorKey,
87 double range, double weight)
88 : Base(noiseModel::Unit::Create(d), translationKey, targetKey,
89 unitVectorKey),
90 range_(range),
91 weight_(weight) {
92 if (weight <= 0.0) {
93 throw std::invalid_argument(
94 "QuadraticRangeFactor: weight must be positive.");
95 }
96 if (range < 0.0) {
97 throw std::invalid_argument(
98 "QuadraticRangeFactor: range must be non-negative.");
99 }
100 }
101
102 double range() const { return range_; }
103 double weight() const { return weight_; }
104
105 void print(
106 const std::string& s = "",
107 const KeyFormatter& keyFormatter = DefaultKeyFormatter) const override {
108 std::cout << s << "QuadraticRangeFactor(" << keyFormatter(this->key1())
109 << "," << keyFormatter(this->key2()) << ","
110 << keyFormatter(this->key3()) << ") range=" << range_
111 << " weight=" << weight_ << "\n";
112 }
113
114 bool equals(const NonlinearFactor& other, double tol = 1e-9) const override {
115 const auto* e = dynamic_cast<const QuadraticRangeFactor*>(&other);
116 return e != nullptr && Base::equals(other, tol) &&
117 std::abs(range_ - e->range_) < tol &&
118 std::abs(weight_ - e->weight_) < tol;
119 }
120
123 Vector evaluateError(const Point& translation, const Point& target,
124 const Direction& direction, OptionalMatrixType H1,
126 OptionalMatrixType H3) const override {
127 const double sw = std::sqrt(weight_);
128 const Point u = [&direction] {
129 if constexpr (d == 2)
130 return Point(direction.c(), direction.s());
131 else
132 return direction.unitVector();
133 }();
134 if (H1) *H1 = -sw * Matrix::Identity(d, d);
135 if (H2) *H2 = sw * Matrix::Identity(d, d);
136 if (H3) {
137 Matrix J = Matrix::Zero(d, Direction::dimension);
138 if constexpr (d == 2) {
139 J(0, 0) = -u(1);
140 J(1, 0) = u(0);
141 } else {
142 J = direction.basis();
143 }
144 *H3 = -sw * range_ * J;
145 }
146 return sw * (target - translation - range_ * u);
147 }
148
149 gtsam::NonlinearFactor::shared_ptr clone() const override {
150 return std::static_pointer_cast<gtsam::NonlinearFactor>(
151 gtsam::NonlinearFactor::shared_ptr(new QuadraticRangeFactor(*this)));
152 }
153
156 NonlinearEqualityConstraints* constraints,
157 size_t columnDimension = 1) const override {
158 if (columnDimension == 0) {
159 throw std::invalid_argument(
160 "QuadraticRangeFactor::qcqpFactors requires a positive "
161 "columnDimension.");
162 }
163 if (columnDimension == 1) {
164 qcqpFactorsForVector(costs, constraints);
165 return;
166 }
167 if (columnDimension < static_cast<size_t>(d)) {
168 throw std::invalid_argument(
169 "QuadraticRangeFactor::qcqpFactors requires columnDimension "
170 ">= d.");
171 }
172 if (!costs) {
173 throw std::invalid_argument(
174 "QuadraticRangeFactor::qcqpFactors: costs is null.");
175 }
176
177 InsertQcqpConstraints<Direction, d>(this->key3(), constraints);
178
179 // The direction is a Rot2 in 2D, which takes 2 rows, and a Unit3 in 3D,
180 // which takes 1. Only the first row is used; any others stay zero.
181 const double sw = std::sqrt(weight_);
182 Matrix B = Matrix::Zero(1, 2 + kDirectionRows);
183 B(0, 0) = -sw; // pose translation
184 B(0, 1) = sw; // target
185 B(0, 2) = -sw * range_; // leading row of the auxiliary direction
186
187 const Matrix Q = B.transpose() * B;
188 const SymmetricBlockMatrix blockQ(
189 std::vector<DenseIndex>{1, 1, kDirectionRows}, Q);
190 costs->push_back(std::make_shared<QpCost>(
191 KeyVector{this->key1(), this->key2(), this->key3()}, blockQ,
192 columnDimension));
193 }
194
195 private:
197 void qcqpFactorsForVector(NonlinearFactorGraph* costs,
198 NonlinearEqualityConstraints* constraints) const {
199 if (!costs) {
200 throw std::invalid_argument(
201 "QuadraticRangeFactor::qcqpFactors: costs is null.");
202 }
203
204 constexpr int kPointDim = traits<Point>::QcqpVectorDim;
205 constexpr int kDirectionDim = traits<Direction>::QcqpVectorDim;
206 const double sw = std::sqrt(weight_);
207
208 // Both Rot2 and Unit3 store the relevant direction in the d entries after
209 // the homogeneous coordinate (Rot2's first matrix column in 2D).
210 Matrix directionSelector = Matrix::Zero(d, kDirectionDim);
211 directionSelector.block(0, 1, d, d).setIdentity();
212
213 Matrix B = Matrix::Zero(d, 2 * kPointDim + kDirectionDim);
214 B.block(0, 1, d, d) = -sw * Matrix::Identity(d, d);
215 B.block(0, kPointDim + 1, d, d) = sw * Matrix::Identity(d, d);
216 B.block(0, 2 * kPointDim, d, kDirectionDim) =
217 -sw * range_ * directionSelector;
218
219 InsertQcqpConstraints<Point, 1>(this->key1(), constraints);
220 InsertQcqpConstraints<Point, 1>(this->key2(), constraints);
221 InsertQcqpConstraints<Direction, 1>(this->key3(), constraints);
222
223 const Matrix Q = B.transpose() * B;
224 const SymmetricBlockMatrix blockQ(
225 std::vector<DenseIndex>{kPointDim, kPointDim, kDirectionDim}, Q);
226 costs->push_back(std::make_shared<QpCost>(
227 KeyVector{this->key1(), this->key2(), this->key3()}, blockQ));
228 }
229};
230
231using QuadraticRangeFactor2 = QuadraticRangeFactor<2>;
232using QuadraticRangeFactor3 = QuadraticRangeFactor<3>;
233
234} // namespace gtsam
typedef and functions to augment Eigen's MatrixXd
2D rotation
Base class for noise model factors with N variables.
Non-linear factor base classes.
Global functions in a separate testing namespace.
Definition chartTesting.h:28
KeyFormatter DefaultKeyFormatter
Assign default key formatter.
Definition Key.cpp:30
FastVector< Key > KeyVector
Define collection type once and for all - also used in wrappers.
Definition Key.h:91
Matrix * OptionalMatrixType
This typedef will be used everywhere boost::optional<Matrix&> reference was used previously.
Definition NonlinearFactor.h:57
NoiseModelFactorT< Vector, ValueTypes... > NoiseModelFactorN
Noise model factor with N value types and dynamic-sized error vector.
Definition NoiseModelFactorN.h:561
std::function< std::string(Key)> KeyFormatter
Typedef for a function to format a key, i.e. to convert it to a string.
Definition Key.h:35
std::uint64_t Key
Integer nonlinear key type.
Definition types.h:43
All noise models live in the noiseModel namespace.
Definition LossFunctions.cpp:33
This class stores a dense matrix and allows it to be accessed as a collection of blocks.
Definition SymmetricBlockMatrix.h:80
IsDerived< DERIVEDFACTOR > push_back(std::shared_ptr< DERIVEDFACTOR > factor)
Add a factor directly using a shared_ptr.
Definition FactorGraph.h:147
bool equals(const This &other, double tol=1e-9) const
check equality
Definition Factor.cpp:42
virtual Vector evaluateError(const ValueTypes &... x, OptionalMatrixTypeT< ValueTypes >... H) const=0
Nonlinear factor base class.
Definition NonlinearFactor.h:70
Definition NonlinearFactorGraph.h:57
Definition QuadraticRangeFactor.h:61
void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const override
Print.
Definition QuadraticRangeFactor.h:105
bool equals(const NonlinearFactor &other, double tol=1e-9) const override
Check if two factors are equal.
Definition QuadraticRangeFactor.h:114
QuadraticRangeFactor(Key translationKey, Key targetKey, Key unitVectorKey, double range, double weight)
Definition QuadraticRangeFactor.h:86
gtsam::NonlinearFactor::shared_ptr clone() const override
Creates a shared_ptr clone of the factor - needs to be specialized to allow for subclasses.
Definition QuadraticRangeFactor.h:149
static constexpr int kDirectionRows
Definition QuadraticRangeFactor.h:75
Vector evaluateError(const Point &translation, const Point &target, const Direction &direction, OptionalMatrixType H1, OptionalMatrixType H2, OptionalMatrixType H3) const override
Weighted residual sqrt(weight) * (target - t_i - range * u).
Definition QuadraticRangeFactor.h:123
void qcqpFactors(NonlinearFactorGraph *costs, NonlinearEqualityConstraints *constraints, size_t columnDimension=1) const override
Add this range factor as a QCQP cost when traits exist.
Definition QuadraticRangeFactor.h:155