IMP  2.2.0
The Integrative Modeling Platform
VectorBaseD.h
Go to the documentation of this file.
1 /**
2  * \file IMP/algebra/VectorBaseD.h \brief Simple D vector class.
3  *
4  * Copyright 2007-2014 IMP Inventors. All rights reserved.
5  *
6  */
7 
8 #ifndef IMPALGEBRA_VECTOR_BASE_D_H
9 #define IMPALGEBRA_VECTOR_BASE_D_H
10 
11 #include <IMP/algebra/algebra_config.h>
12 #include "GeometricPrimitiveD.h"
13 #include <IMP/base/check_macros.h>
14 #include <IMP/base/exception.h>
15 #include <IMP/base/random.h>
16 #include <IMP/base/utility.h>
17 #include <IMP/base/types.h>
18 #include <boost/random/variate_generator.hpp>
19 #include <boost/random/normal_distribution.hpp>
20 #include <boost/range.hpp>
21 #include "internal/vector.h"
22 
23 #include <limits>
24 #include <cmath>
25 #include <boost/random/normal_distribution.hpp>
26 #include <boost/static_assert.hpp>
27 
28 #if IMP_HAS_CHECKS >= IMP_USAGE
29 #define IMP_ALGEBRA_VECTOR_CHECK check_vector()
30 #define IMP_ALGEBRA_VECTOR_CHECK_INDEX(i) check_index(i)
31 #define IMP_ALGEBRA_VECTOR_CHECK_COMPATIBLE(o) \
32  check_compatible_vector(o); \
33  o.check_vector()
34 #else
35 #define IMP_ALGEBRA_VECTOR_CHECK
36 #define IMP_ALGEBRA_VECTOR_CHECK_INDEX(i)
37 #define IMP_ALGEBRA_VECTOR_CHECK_COMPATIBLE(o)
38 #endif
39 
40 IMPALGEBRA_BEGIN_NAMESPACE
41 //! A Cartesian vector in D-dimensions.
42 /** Store a vector of Cartesian coordinates. It supports all expected
43  mathematical operators, including using * for the dot product.
44  \see Vector3D
45  \see Vector2D
46 
47  \geometry
48  */
49 template <int D>
50 class VectorBaseD : public GeometricPrimitiveD<D> {
51  void check_vector() const {
52  IMP_USAGE_CHECK(!data_.get_is_null(),
53  "Attempt to use uninitialized vector.");
54  }
55  template <int OD>
56  void check_compatible_vector(const VectorBaseD<OD> &o) const {
58  IMP_USAGE_CHECK(o.get_dimension() == get_dimension(),
59  "Dimensions don't match: " << get_dimension() << " vs "
60  << o.get_dimension());
61  }
62  void check_index(unsigned int i) const {
63 #if IMP_HAS_CHECKS < IMP_INTERNAL
64  IMP_UNUSED(i);
65 #endif
66  IMP_INTERNAL_CHECK(i < data_.get_dimension(),
67  "Invalid component of vector requested: "
68  << i << " of " << get_dimension());
69  }
70 
71  public:
72  /** Will accept a list of floats from python. */
73  template <class Range>
74  explicit VectorBaseD(const Range &r) {
75  if (D != -1 && static_cast<int>(boost::distance(r)) != D) {
76  IMP_THROW("Expected " << D << " but got " << boost::distance(r),
78  }
80  IMP_FOREACH(double f, r) {
81  IMP_UNUSED(f);
82  IMP_USAGE_CHECK(!base::is_nan(f), "NaN passed to constructor");
83  }
84  }
85  data_.set_coordinates(boost::begin(r), boost::end(r));
86  }
87 
88 #ifndef SWIG
89  template <class R>
90  VectorBaseD<D> &operator=(const R &r) {
91  if (D != -1 && static_cast<int>(boost::distance(r)) != D) {
92  IMP_THROW("Expected " << D << " but got " << boost::distance(r),
94  }
96  IMP_FOREACH(double f, r) {
97  IMP_USAGE_CHECK(!base::is_nan(f), "NaN passed in equals");
98  }
99  }
100  data_.set_coordinates(boost::begin(r), boost::end(r));
101  }
102  /** Return the ith Cartesian coordinate. In 3D use [0] to get
103  the x coordinate etc.*/
104  inline double operator[](unsigned int i) const {
105  IMP_ALGEBRA_VECTOR_CHECK_INDEX(i);
106  IMP_ALGEBRA_VECTOR_CHECK;
107  return data_.get_data()[i];
108  }
109  /** Return the ith Cartesian coordinate. In 3D use [0] to get
110  the x coordinate etc. */
111  inline double &operator[](unsigned int i) {
112  IMP_ALGEBRA_VECTOR_CHECK_INDEX(i);
113  return data_.get_data()[i];
114  }
115 
116 #endif
117  //! Default constructor
119 
120  double get_scalar_product(const VectorBaseD<D> &o) const {
121  IMP_ALGEBRA_VECTOR_CHECK_COMPATIBLE(o);
122  IMP_ALGEBRA_VECTOR_CHECK;
123  double ret = 0;
124  for (unsigned int i = 0; i < get_dimension(); ++i) {
125  ret += operator[](i) * o.operator[](i);
126  }
127  return ret;
128  }
129 
130  double get_squared_magnitude() const { return get_scalar_product(*this); }
131 
132  double get_magnitude() const { return std::sqrt(get_squared_magnitude()); }
133 
134 #ifndef IMP_DOXYGEN
135  double operator*(const VectorBaseD<D> &o) const {
136  IMP_ALGEBRA_VECTOR_CHECK_COMPATIBLE(o);
137  return get_scalar_product(o);
138  }
139 
140  VectorBaseD &operator+=(const VectorBaseD &o) {
141  IMP_ALGEBRA_VECTOR_CHECK_COMPATIBLE(o);
142  IMP_ALGEBRA_VECTOR_CHECK;
143  for (unsigned int i = 0; i < get_dimension(); ++i) {
144  operator[](i) += o[i];
145  }
146  return *this;
147  }
148 
149  VectorBaseD &operator-=(const VectorBaseD &o) {
150  IMP_ALGEBRA_VECTOR_CHECK_COMPATIBLE(o);
151  IMP_ALGEBRA_VECTOR_CHECK;
152  for (unsigned int i = 0; i < get_dimension(); ++i) {
153  operator[](i) -= o[i];
154  }
155  return *this;
156  }
157 
158  VectorBaseD &operator/=(double f) {
159  IMP_ALGEBRA_VECTOR_CHECK;
160  for (unsigned int i = 0; i < get_dimension(); ++i) {
161  operator[](i) /= f;
162  }
163  return *this;
164  }
165 
166  VectorBaseD &operator*=(double f) {
167  IMP_ALGEBRA_VECTOR_CHECK;
168  for (unsigned int i = 0; i < get_dimension(); ++i) {
169  operator[](i) *= f;
170  }
171  return *this;
172  }
173 
174  void show(std::ostream &out, std::string delim, bool parens = true) const {
175  IMP_ALGEBRA_VECTOR_CHECK;
176  if (parens) out << "(";
177  for (unsigned int i = 0; i < get_dimension(); ++i) {
178  out << operator[](i);
179  if (i != get_dimension() - 1) {
180  out << delim;
181  }
182  }
183  if (parens) out << ")";
184  }
185  IMP_SHOWABLE_INLINE(VectorBaseD, show(out, ", "););
186 #endif
187 
188 #ifndef SWIG
189  typedef double *iterator;
190  typedef const double *const_iterator;
191  /** \deprecated_at{2.2} Use begin(). */
192  IMPALGEBRA_DEPRECATED_FUNCTION_DECL(2.2)
193  iterator coordinates_begin() { return data_.get_data(); }
194  iterator coordinates_end() { return data_.get_data() + get_dimension(); }
195  /** \deprecated_at{2.2} Use begin(). */
196  IMPALGEBRA_DEPRECATED_FUNCTION_DECL(2.2)
197  const_iterator coordinates_begin() const { return data_.get_data(); }
198  const_iterator coordinates_end() const {
199  return data_.get_data() + get_dimension();
200  }
201  iterator begin() { return data_.get_data(); }
202  iterator end() { return data_.get_data() + get_dimension(); }
203  const_iterator begin() const { return data_.get_data(); }
204  const_iterator end() const { return data_.get_data() + get_dimension(); }
205 
206  typedef double value_type;
207  typedef std::random_access_iterator_tag iterator_category;
208  typedef std::ptrdiff_t difference_type;
209  typedef double *pointer;
210  typedef double &reference;
211  typedef const double &const_reference;
212 
213  static const int DIMENSION = D;
214 #endif
215 
216 #ifndef SWIG
217  // For some reason, this method breaks IMP::atom::get_rmsd() in Python, so
218  // hide it from SWIG
219  Floats get_coordinates() const {
220  return Floats(coordinates_begin(), coordinates_end());
221  }
222 
223  /** Return a pointer to the data stored.
224 
225  Useful for conversion to other types. */
226  const double *get_data() const { return data_.get_data(); }
227 #endif
228  unsigned int get_dimension() const { return data_.get_dimension(); }
229 
230  private:
231  internal::VectorData<double, D, false> data_;
232 };
233 
234 /**
235  Returns a unit vector pointing at the same direction as this vector.
236 
237  @note If the magnitude of this vector is smaller than 1e-12
238  (an arbitrarily selected small number), returns a unit
239  vector pointing at a random direction
240  */
241 template <class VT>
242 inline VT get_unit_vector(VT vt) {
243  const double tiny_double = 1e-12;
244  double mag = vt.get_magnitude();
245  if (mag > tiny_double) {
246  return vt / mag;
247  } else {
248  // avoid division by zero - return random unit v
249  // NOTE: (1) avoids vector_generators / SphereD to prevent recursiveness
250  // (2) D might be -1, so use get_dimension()
251  boost::variate_generator<base::RandomNumberGenerator,
252  boost::normal_distribution<> >
254  ::boost::normal_distribution<>(0, 1.0));
255  for (unsigned int i = 0; i < vt.get_dimension(); ++i) {
256  vt[i] = generator();
257  }
258  return get_unit_vector(vt);
259  }
260 }
261 
262 IMPALGEBRA_END_NAMESPACE
263 
264 #endif /* IMPALGEBRA_VECTOR_BASE_D_H */
Basic types used by IMP.
Basic types used by IMP.
RandomNumberGenerator random_number_generator
A shared random number generator.
VectorBaseD()
Default constructor.
Definition: VectorBaseD.h:118
VectorBaseD(const Range &r)
Definition: VectorBaseD.h:74
#define IMP_UNUSED(variable)
#define IMP_SHOWABLE_INLINE(Name, how_to_show)
Declare the methods needed by an object that can be printed.
VT get_unit_vector(VT vt)
Definition: VectorBaseD.h:242
Random number generators used by IMP.
#define IMP_USAGE_CHECK(expr, message)
A runtime test for incorrect usage of a class or method.
#define IMP_USAGE_CHECK_VARIABLE(variable)
#define IMP_INTERNAL_CHECK(expr, message)
An assertion to check for internal errors in IMP. An IMP::ErrorException will be thrown.
Various general useful functions for IMP.
#define IMP_IF_CHECK(level)
Execute the code block if a certain level checks are on.
Exception definitions and assertions.
void show(Hierarchy h, std::ostream &out=std::cout)
Print out a molecular hierarchy.
IMP::base::Vector< Float > Floats
Standard way to pass a bunch of Float values.
Definition: base/types.h:47
#define IMP_THROW(message, exception_name)
Throw an exception with a message.
VectorD< D > operator*(double s, VectorD< D > o)
Definition: VectorD.h:193
Exception definitions and assertions.
const double * get_data() const
Definition: VectorBaseD.h:226
A Cartesian vector in D-dimensions.
Definition: VectorBaseD.h:50
double operator[](unsigned int i) const
Definition: VectorBaseD.h:104
An exception for an invalid value being passed to IMP.
double & operator[](unsigned int i)
Definition: VectorBaseD.h:111