Cached Rot3::transpose(). Inspired by @cbeall3 fix of Unit3, I realized that with one million points and 1000 cameras, the same Matrix3 (R_.transpose()) was computed a 1000 more times than needed. Especially with quaternions this would be expensive, even with Rot3Q.

release/4.3a0
dellaert 2014-10-15 11:51:41 +02:00
parent 4a854f7e22
commit c4bf680e96
5 changed files with 21 additions and 14 deletions

View File

@ -263,7 +263,7 @@ Point3 Pose3::transform_to(const Point3& p, boost::optional<Matrix36&> Dpose,
boost::optional<Matrix3&> Dpoint) const { boost::optional<Matrix3&> Dpoint) const {
// Only get transpose once, to avoid multiple allocations, // Only get transpose once, to avoid multiple allocations,
// as well as multiple conversions in the Quaternion case // as well as multiple conversions in the Quaternion case
Matrix3 Rt(R_.transpose()); const Matrix3& Rt = R_.transpose();
const Point3 q(Rt*(p - t_).vector()); const Point3 q(Rt*(p - t_).vector());
if (Dpose) { if (Dpose) {
const double wx = q.x(), wy = q.y(), wz = q.z(); const double wx = q.x(), wy = q.y(), wz = q.z();
@ -280,7 +280,7 @@ Point3 Pose3::transform_to(const Point3& p, boost::optional<Matrix36&> Dpose,
/* ************************************************************************* */ /* ************************************************************************* */
Point3 Pose3::transform_to(const Point3& p, boost::optional<Matrix&> Dpose, Point3 Pose3::transform_to(const Point3& p, boost::optional<Matrix&> Dpose,
boost::optional<Matrix&> Dpoint) const { boost::optional<Matrix&> Dpoint) const {
Matrix3 Rt(R_.transpose()); const Matrix3& Rt = R_.transpose();
const Point3 q(Rt*(p - t_).vector()); const Point3 q(Rt*(p - t_).vector());
if (Dpose) { if (Dpose) {
const double wx = q.x(), wy = q.y(), wz = q.z(); const double wx = q.x(), wy = q.y(), wz = q.z();

View File

@ -101,7 +101,7 @@ Unit3 Rot3::operator*(const Unit3& p) const {
// see doc/math.lyx, SO(3) section // see doc/math.lyx, SO(3) section
Point3 Rot3::unrotate(const Point3& p, boost::optional<Matrix3&> H1, Point3 Rot3::unrotate(const Point3& p, boost::optional<Matrix3&> H1,
boost::optional<Matrix3&> H2) const { boost::optional<Matrix3&> H2) const {
Matrix3 Rt(transpose()); const Matrix3& Rt = transpose();
Point3 q(Rt * p.vector()); // q = Rt*p Point3 q(Rt * p.vector()); // q = Rt*p
const double wx = q.x(), wy = q.y(), wz = q.z(); const double wx = q.x(), wy = q.y(), wz = q.z();
if (H1) if (H1)
@ -115,7 +115,7 @@ Point3 Rot3::unrotate(const Point3& p, boost::optional<Matrix3&> H1,
// see doc/math.lyx, SO(3) section // see doc/math.lyx, SO(3) section
Point3 Rot3::unrotate(const Point3& p, Point3 Rot3::unrotate(const Point3& p,
boost::optional<Matrix&> H1, boost::optional<Matrix&> H2) const { boost::optional<Matrix&> H1, boost::optional<Matrix&> H2) const {
Matrix3 Rt(transpose()); const Matrix3& Rt = transpose();
Point3 q(Rt * p.vector()); // q = Rt*p Point3 q(Rt * p.vector()); // q = Rt*p
const double wx = q.x(), wy = q.y(), wz = q.z(); const double wx = q.x(), wy = q.y(), wz = q.z();
if (H1) { if (H1) {

View File

@ -70,6 +70,12 @@ namespace gtsam {
Matrix3 rot_; Matrix3 rot_;
#endif #endif
/**
* transpose() is used millions of times in linearize, so cache it
* This also avoids multiple expensive conversions in the quaternion case
*/
mutable boost::optional<Matrix3> transpose_; ///< Cached R_.transpose()
public: public:
/// @name Constructors and named constructors /// @name Constructors and named constructors
@ -368,8 +374,15 @@ namespace gtsam {
/** return 3*3 rotation matrix */ /** return 3*3 rotation matrix */
Matrix3 matrix() const; Matrix3 matrix() const;
/** return 3*3 transpose (inverse) rotation matrix */ /**
Matrix3 transpose() const; * Return 3*3 transpose (inverse) rotation matrix
* Actually returns cached transpose, or computes it if not yet done
*/
const Matrix3& transpose() const {
if (!transpose_)
transpose_.reset(inverse().matrix());
return *transpose_;
}
/// @deprecated, this is base 1, and was just confusing /// @deprecated, this is base 1, and was just confusing
Point3 column(int index) const; Point3 column(int index) const;
@ -439,6 +452,7 @@ namespace gtsam {
GTSAM_EXPORT friend std::ostream &operator<<(std::ostream &os, const Rot3& p); GTSAM_EXPORT friend std::ostream &operator<<(std::ostream &os, const Rot3& p);
private: private:
/** Serialization function */ /** Serialization function */
friend class boost::serialization::access; friend class boost::serialization::access;
template<class ARCHIVE> template<class ARCHIVE>
@ -463,6 +477,7 @@ namespace gtsam {
ar & boost::serialization::make_nvp("z", quaternion_.z()); ar & boost::serialization::make_nvp("z", quaternion_.z());
#endif #endif
} }
}; };
/// @} /// @}

View File

@ -295,11 +295,6 @@ Matrix3 Rot3::matrix() const {
return rot_; return rot_;
} }
/* ************************************************************************* */
Matrix3 Rot3::transpose() const {
return rot_.transpose();
}
/* ************************************************************************* */ /* ************************************************************************* */
Point3 Rot3::r1() const { return Point3(rot_.col(0)); } Point3 Rot3::r1() const { return Point3(rot_.col(0)); }

View File

@ -156,9 +156,6 @@ namespace gtsam {
/* ************************************************************************* */ /* ************************************************************************* */
Matrix3 Rot3::matrix() const {return quaternion_.toRotationMatrix();} Matrix3 Rot3::matrix() const {return quaternion_.toRotationMatrix();}
/* ************************************************************************* */
Matrix3 Rot3::transpose() const {return quaternion_.toRotationMatrix().transpose();}
/* ************************************************************************* */ /* ************************************************************************* */
Point3 Rot3::r1() const { return Point3(quaternion_.toRotationMatrix().col(0)); } Point3 Rot3::r1() const { return Point3(quaternion_.toRotationMatrix().col(0)); }