Chemical Data Processing Library C++ API - Version 1.4.0
KabschAlgorithm.hpp
Go to the documentation of this file.
1 /*
2  * KabschAlgorithm.hpp
3  *
4  * Copyright (C) 2003 Thomas Seidel <thomas.seidel@univie.ac.at>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library; see the file COPYING. If not, write to
18  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 
27 #ifndef CDPL_MATH_KABSCHALGORITHM_HPP
28 #define CDPL_MATH_KABSCHALGORITHM_HPP
29 
30 #include <cstddef>
31 
32 #include "CDPL/Math/Check.hpp"
33 #include "CDPL/Math/TypeTraits.hpp"
34 #include "CDPL/Math/Matrix.hpp"
35 #include "CDPL/Math/Vector.hpp"
39 #include "CDPL/Base/Exceptions.hpp"
40 
41 
42 namespace CDPL
43 {
44 
45  namespace Math
46  {
47 
60  template <typename T>
62  {
63 
64  public:
68  typedef T ValueType;
69 
74 
79 
96  template <typename M1, typename M2, typename V>
97  bool align(const MatrixExpression<M1>& points, const MatrixExpression<M2>& ref_points, const VectorExpression<V>& weights,
98  bool do_center = true, std::size_t max_svd_iter = 0)
99  {
100 
102  typename V::SizeType>::Type SizeType;
103 
104  SizeType dim = points().getSize1();
105  SizeType num_pts = points().getSize2();
106 
107  CDPL_MATH_CHECK(dim == SizeType(ref_points().getSize1()) && num_pts == SizeType(ref_points().getSize2()),
108  "KabschAlgorithm: Point-sets of different size", Base::SizeError);
109 
110  CDPL_MATH_CHECK(num_pts == SizeType(weights().getSize()),
111  "KabschAlgorithm: Number of points != number of weights", Base::SizeError);
112 
113  ValueType w_sum = ValueType();
114 
115  for (SizeType i = 0; i < num_pts; i++) {
116  CDPL_MATH_CHECK(ValueType(weights()(i)) >= ValueType(), "KabschAlgorithm: weights must be non-negative entries", Base::ValueError);
117  w_sum += weights()(i);
118  }
119 
120  CDPL_MATH_CHECK(w_sum > ValueType(), "KabschAlgorithm: weights must contain some positive entry", Base::ValueError);
121 
122  if (do_center) {
123  prod(points, weights, centroid1);
124  prod(ref_points, weights, centroid2);
125 
126  centroid1 /= w_sum;
127  centroid2 /= w_sum;
128 
129  tmpPoints.resize(dim, num_pts, false);
130  tmpPoints.assign(points);
131 
132  tmpRefPoints.resize(dim, num_pts, false);
133  tmpRefPoints.assign(ref_points);
134 
135  for (SizeType i = 0; i < num_pts; i++) {
136  column(tmpPoints, i).minusAssign(centroid1) *= weights()(i) / w_sum;
137  column(tmpRefPoints, i).minusAssign(centroid2);
138  }
139 
140  } else {
141  tmpPoints.resize(dim, num_pts, false);
142  tmpPoints.assign(points);
143 
144  for (SizeType i = 0; i < num_pts; i++)
145  column(tmpPoints, i) *= weights()(i) / w_sum;
146  }
147 
148  covarMatrix.resize(dim, dim, false);
149 
150  if (do_center)
151  prod(tmpPoints, trans(tmpRefPoints), covarMatrix);
152  else
153  prod(tmpPoints, trans(ref_points), covarMatrix);
154 
155  return align(dim, do_center, max_svd_iter);
156  }
157 
171  template <typename M1, typename M2>
172  bool align(const MatrixExpression<M1>& points, const MatrixExpression<M2>& ref_points,
173  bool do_center = true, std::size_t max_svd_iter = 0)
174  {
175 
177 
178  SizeType dim = points().getSize1();
179  SizeType num_pts = points().getSize2();
180 
181  CDPL_MATH_CHECK(dim == SizeType(ref_points().getSize1()) && num_pts == SizeType(ref_points().getSize2()),
182  "KabschAlgorithm: Point-sets of different size", Base::SizeError);
183 
184  if (do_center) {
185  prod(points, ScalarVector<ValueType>(num_pts, ValueType(1) / num_pts), centroid1);
186  prod(ref_points, ScalarVector<ValueType>(num_pts, ValueType(1) / num_pts), centroid2);
187 
188  tmpPoints.resize(dim, num_pts, false);
189  tmpPoints.assign(points);
190 
191  tmpRefPoints.resize(dim, num_pts, false);
192  tmpRefPoints.assign(ref_points);
193 
194  for (SizeType i = 0; i < num_pts; i++) {
195  column(tmpPoints, i).minusAssign(centroid1);
196  column(tmpRefPoints, i).minusAssign(centroid2);
197  }
198  }
199 
200  covarMatrix.resize(dim, dim, false);
201 
202  if (do_center)
203  prod(tmpPoints, trans(tmpRefPoints), covarMatrix);
204  else
205  prod(points, trans(ref_points), covarMatrix);
206 
207  return align(dim, do_center, max_svd_iter);
208  }
209 
214  const MatrixType& getTransform() const
215  {
216  return transform;
217  }
218 
219  private:
220  template <typename SizeType>
221  bool align(SizeType dim, bool do_center, std::size_t max_svd_iter)
222  {
223  svdW.resize(dim);
224  svdV.resize(dim, dim, false);
225 
226  if (!svDecompose(covarMatrix, svdW, svdV, max_svd_iter))
227  return false;
228 
229  if (det(prod(covarMatrix, trans(svdV))) < ValueType())
230  column(svdV, dim - 1) *= -ValueType(1);
231 
232  SizeType xform_dim = dim + 1;
233 
234  transform.resize(xform_dim, xform_dim, false);
235 
236  range(transform, 0, dim, 0, dim).assign(prod(svdV, trans(covarMatrix)));
237 
238  MatrixRow<MatrixType> last_row(transform, dim);
239  MatrixColumn<MatrixType> last_col(transform, dim);
240 
241  range(last_row, 0, dim).assign(ZeroVector<ValueType>(dim));
242 
243  if (do_center)
244  range(last_col, 0, dim).assign(centroid2 - prod(range(transform, 0, dim, 0, dim), centroid1));
245  else
246  range(last_col, 0, dim).assign(ZeroVector<ValueType>(dim));
247 
248  transform(dim, dim) = ValueType(1);
249 
250  return true;
251  }
252 
253  MatrixType transform;
254  MatrixType tmpPoints;
255  MatrixType tmpRefPoints;
256  MatrixType covarMatrix;
257  VectorType svdW;
258  MatrixType svdV;
259  VectorType centroid1;
260  VectorType centroid2;
261  };
262  } // namespace Math
263 } // namespace CDPL
264 
265 #endif // CDPL_MATH_KABSCHALGORITHM_HPP
Definition of exception classes.
Definition of various preprocessor macros for error checking.
#define CDPL_MATH_CHECK(expr, msg, e)
Throws the exception e with message msg when the boolean expression expr evaluates to false.
Definition: Check.hpp:47
Definition of matrix proxy types.
Definition of matrix data types.
Implementation of matrix singular value decomposition and associated operations.
Definition of type traits.
Definition of vector proxy types.
Definition of vector data types.
Thrown to indicate that the size of a (multidimensional) array is not correct.
Definition: Base/Exceptions.hpp:133
Thrown to indicate errors caused by some invalid value.
Definition: Base/Exceptions.hpp:76
Implementation of the Kabsch algorithm [KABA].
Definition: KabschAlgorithm.hpp:62
Vector< T > VectorType
The vector type used for the centroids and singular-value vectors.
Definition: KabschAlgorithm.hpp:78
bool align(const MatrixExpression< M1 > &points, const MatrixExpression< M2 > &ref_points, bool do_center=true, std::size_t max_svd_iter=0)
Computes the rigid body transformation that aligns a set of -dimensional points points with a corres...
Definition: KabschAlgorithm.hpp:172
const MatrixType & getTransform() const
Returns the rigid-body transformation produced by the most recent successful align() call.
Definition: KabschAlgorithm.hpp:214
Matrix< T > MatrixType
The matrix type used for the transformation, the covariance matrix and the working buffers.
Definition: KabschAlgorithm.hpp:73
bool align(const MatrixExpression< M1 > &points, const MatrixExpression< M2 > &ref_points, const VectorExpression< V > &weights, bool do_center=true, std::size_t max_svd_iter=0)
Computes the rigid body transformation that aligns a set of -dimensional points points with a corres...
Definition: KabschAlgorithm.hpp:97
T ValueType
The scalar value type.
Definition: KabschAlgorithm.hpp:68
Vector expression proxy that views a single column of an underlying matrix.
Definition: MatrixProxy.hpp:346
CRTP base class of all matrix expression types.
Definition: Expression.hpp:108
Vector expression proxy that views a single row of an underlying matrix.
Definition: MatrixProxy.hpp:53
Dynamically-sized dense row-major matrix with configurable underlying storage.
Definition: Matrix.hpp:510
Constant vector expression in which every element equals the same scalar value.
Definition: Vector.hpp:2883
CRTP base class of all vector expression types.
Definition: Expression.hpp:68
Dynamically-sized dense vector with configurable underlying storage.
Definition: Vector.hpp:480
Constant vector expression whose elements are all zero.
Definition: Vector.hpp:2524
constexpr unsigned int T
Specifies Hydrogen (Tritium).
Definition: AtomType.hpp:67
MatrixTranspose< E > trans(MatrixExpression< E > &e)
Returns a mutable Math::MatrixTranspose view of the matrix expression e.
Definition: MatrixExpression.hpp:1943
MatrixColumn< M > column(MatrixExpression< M > &e, typename MatrixColumn< M >::SizeType j)
Returns a mutable column proxy for column j of the matrix expression e.
Definition: MatrixProxy.hpp:1400
E::ValueType det(const MatrixExpression< E > &e)
Returns the determinant of the matrix expression e.
Definition: Matrix.hpp:3311
bool svDecompose(MatrixExpression< A > &a, VectorExpression< W > &w, MatrixExpression< V > &v, std::size_t max_iter=0)
Computes the Singular Value Decomposition [WSVD] of a -dimensional matrix a.
Definition: SVDecomposition.hpp:70
MatrixRange< E > range(MatrixExpression< E > &e, const typename MatrixRange< E >::RangeType &r1, const typename MatrixRange< E >::RangeType &r2)
Returns a mutable matrix range proxy viewing rows in r1 and columns in r2 of e.
Definition: MatrixProxy.hpp:1429
Matrix1VectorBinaryTraits< E1, E2, MatrixVectorProduct< E1, E2 > >::ResultType prod(const MatrixExpression< E1 > &e1, const VectorExpression< E2 > &e2)
Returns the matrix-vector product as a vector expression (named-function form of operator*).
Definition: MatrixExpression.hpp:1731
The namespace of the Chemical Data Processing Library.
Trait that resolves the common arithmetic type of T1 and T2 via std::common_type.
Definition: CommonType.hpp:46
std::common_type< T1, T2 >::type Type
The common type.
Definition: CommonType.hpp:51