IMP  2.0.1
The Integrative Modeling Platform
VectorD.h
Go to the documentation of this file.
1 /**
2  * \file IMP/algebra/VectorD.h \brief Simple D vector class.
3  *
4  * Copyright 2007-2013 IMP Inventors. All rights reserved.
5  *
6  */
7 
8 #ifndef IMPALGEBRA_VECTOR_D_H
9 #define IMPALGEBRA_VECTOR_D_H
10 
11 #include <IMP/algebra/algebra_config.h>
12 #include "GeometricPrimitiveD.h"
13 #include <IMP/base/types.h>
14 #include <IMP/base/base_macros.h>
15 #include <IMP/base/exception.h>
16 #include <IMP/base/utility.h>
17 #include <IMP/base/InputAdaptor.h>
18 #include <IMP/base/random.h>
19 #include "internal/vector.h"
20 
21 #include <limits>
22 #include <cmath>
23 #include <boost/random/normal_distribution.hpp>
24 #include <boost/static_assert.hpp>
25 
26 #if IMP_HAS_CHECKS >= IMP_USAGE
27 #define IMP_VECTOR_CHECK check_vector()
28 #define IMP_VECTOR_CHECK_INDEX(i) check_index(i)
29 #define IMP_VECTOR_CHECK_COMPATIBLE(o) \
30  check_compatible_vector(o); o.check_vector()
31 #else
32 #define IMP_VECTOR_CHECK
33 #define IMP_VECTOR_CHECK_INDEX(i)
34 #define IMP_VECTOR_CHECK_COMPATIBLE(o)
35 #endif
36 
37 
38 IMPALGEBRA_BEGIN_NAMESPACE
39 //! A Cartesian vector in D-dimensions.
40 /** Store a vector of Cartesian coordinates. It supports all expected
41  mathematical operators, including using * for the dot product.
42  \see Vector3D
43  \see Vector2D
44 
45  \geometry
46  */
47 template <int D>
48 class VectorD: public GeometricPrimitiveD<D>
49 {
50  void check_vector() const {
51  IMP_USAGE_CHECK(!data_.get_is_null(),
52  "Attempt to use uninitialized vector.");
53  }
54  template <int OD>
55  void check_compatible_vector(const VectorD<OD> &o) const {
57  IMP_USAGE_CHECK(o.get_dimension() == get_dimension(),
58  "Dimensions don't match: "
59  << 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 public:
71 #if !defined(SWIG) && !defined(IMP_DOXYGEN)
72  template <int OD>
73  VectorD(const VectorD<OD> &o) {
74  BOOST_STATIC_ASSERT(D==-1 || OD==-1 || D==OD);
75  IMP_USAGE_CHECK(D==-1
76  || o.get_dimension() ==static_cast<unsigned int>(D),
77  "Dimensions don't match in conversion");
78  data_.set_coordinates(o.coordinates_begin(),
79  o.coordinates_end());
80  }
81  template <int OD>
82  VectorD & operator=(const VectorD<OD> &o) {
83  BOOST_STATIC_ASSERT(D==-1 || OD==-1 || D==OD);
84  IMP_USAGE_CHECK(D==-1 || o.get_dimension() ==D,
85  "Dimensions don't match in conversion");
86  data_.set_coordinates(o.coordinates_begin(),
87  o.coordinates_end());
88  }
89 #endif
90 
91  /** \throw base::ValueException if f.size() is not appropriate.*/
92  VectorD(const Floats &f) {
93  if (D!=-1 && static_cast<int>(f.size()) != D) {
94  IMP_THROW("Expected " << D << " but got " << f.size(),
96  }
97  data_.set_coordinates(f.begin(), f.end());
98  }
99 
100  /** The distance between b and e must be equal to D.
101  */
102  template <class It>
103  VectorD(It b, It e) {
104  data_.set_coordinates(b,e);
105  }
106 
107  //! Initialize the 1-vector from its value.
108  explicit VectorD(double x) {
109  /* Note that MSVC gets confused with static asserts if we try to subclass
110  VectorD, as we do for example in the various IMP::display Geometry
111  subclasses, so replace with runtime checks. */
112 #if defined(IMP_SWIG_WRAPPER) || defined(_MSC_VER)
113  IMP_USAGE_CHECK(D==1 || D==-1,
114  "Need " << D << " to construct a "
115  << D << "-vector.");
116 #else
117  BOOST_STATIC_ASSERT(D==1);
118 #endif
119  data_.set_coordinates(&x, &x+1);
120  }
121 
122  //! Initialize a 2-vector from separate x,y values.
123  VectorD(double x, double y) {
124 #if defined(IMP_SWIG_WRAPPER) || defined(_MSC_VER)
125  IMP_USAGE_CHECK(D==2 || D==-1, "Need " << D << " to construct a "
126  << D << "-vector.");
127 #else
128  BOOST_STATIC_ASSERT(D==2);
129 #endif
130  double d[]={x,y};
131  data_.set_coordinates(d, d+2);
132  }
133 
134  //! Initialize a 3-vector from separate x,y,z values.
135  VectorD(double x, double y, double z) {
136 #ifdef IMP_SWIG_WRAPPER
137  IMP_USAGE_CHECK(D==3 || D==-1, "Need " << D << " to construct a "
138  << D << "-vector.");
139 #else
140  BOOST_STATIC_ASSERT(D==3);
141 #endif
142  double d[]={x,y,z};
143  data_.set_coordinates(d, d+3);
144  }
145 
146  //! Initialize a 4-vector from separate w,x,y,z values.
147  VectorD(double x0, double x1, double x2, double x3) {
148 #if defined(IMP_SWIG_WRAPPER) || defined(_MSC_VER)
149  IMP_USAGE_CHECK(D==4 || D==-1, "Need " << D << " to construct a "
150  << D << "-vector.");
151 #else
152  BOOST_STATIC_ASSERT(D==4);
153 #endif
154  double d[]={x0, x1, x2, x3};
155  data_.set_coordinates(d, d+4);
156  }
157 
158  //! Default constructor
160  }
161 
162  /** Return the ith Cartesian coordinate. In 3D use [0] to get
163  the x coordinate etc.*/
164  inline double operator[](unsigned int i) const {
165  IMP_VECTOR_CHECK_INDEX(i);
166  IMP_VECTOR_CHECK;
167  return data_.get_data()[i];
168  }
169  /** Return the ith Cartesian coordinate. In 3D use [0] to get
170  the x coordinate etc. */
171  inline double& operator[](unsigned int i) {
172  IMP_VECTOR_CHECK_INDEX(i);
173  return data_.get_data()[i];
174  }
175 
176  double get_scalar_product(const VectorD<D> &o) const {
177  IMP_VECTOR_CHECK_COMPATIBLE(o);
178  IMP_VECTOR_CHECK;
179  double ret=0;
180  for (unsigned int i=0; i< get_dimension(); ++i) {
181  ret += operator[](i)* o.operator[](i);
182  }
183  return ret;
184  }
185 
186  double get_squared_magnitude() const {
187  return get_scalar_product(*this);
188  }
189 
190  double get_magnitude() const {
191  return std::sqrt(get_squared_magnitude());
192  }
193 
194  /**
195  Returns a unit vector pointing at the same direction as this vector.
196 
197  @note If the magnitude of this vector is smaller than 1e-12
198  (an arbitrarily selected small number), returns a unit
199  vector pointing at a random direction
200  */
202  const double tiny_double = 1e-12;
203  double mag = get_magnitude();
204  if(mag > tiny_double){
205  return operator/(mag) ;
206  }
207  else {
208  // avoid division by zero - return random unit v
209  // NOTE: (1) avoids vector_generators / SphereD to prevent recursiveness
210  // (2) D might be -1, so use get_dimension()
211  Floats rand_v(get_dimension());
212  boost::variate_generator<boost::rand48, boost::normal_distribution<> >
214  ::boost::normal_distribution<>(0,1.0) );
215  for (unsigned int i=0; i< get_dimension(); ++i) {
216  rand_v[i] = generator();
217  }
218  return VectorD<D>(rand_v).get_unit_vector();
219  }
220  }
221 
222 #ifndef IMP_DOXYGEN
223  double operator*(const VectorD<D> &o) const {
224  IMP_VECTOR_CHECK_COMPATIBLE(o);
225  return get_scalar_product(o);
226  }
227 
228  VectorD operator*(double s) const {
229  IMP_VECTOR_CHECK;
230  VectorD ret=*this;
231  ret*=s;
232  return ret;
233  }
234 
235  VectorD operator/(double s) const {
236  IMP_VECTOR_CHECK;
237  VectorD ret=*this;
238  ret/=s;
239  return ret;
240  }
241 
242  VectorD operator-() const {
243  IMP_VECTOR_CHECK;
244  VectorD ret=*this;
245  for (unsigned int i=0; i<get_dimension(); ++i) {
246  ret[i] = -ret[i];
247  }
248  return ret;
249  }
250 
251  VectorD operator-(const VectorD &o) const {
252  IMP_VECTOR_CHECK_COMPATIBLE(o);
253  IMP_VECTOR_CHECK;
254  VectorD ret=*this;
255  ret-=o;
256  return ret;
257  }
258 
259  VectorD operator+(const VectorD &o) const {
260  IMP_VECTOR_CHECK_COMPATIBLE(o);
261  IMP_VECTOR_CHECK;
262  VectorD ret=*this;
263  ret+=o;
264  return ret;
265  }
266 
267  VectorD& operator+=(const VectorD &o) {
268  IMP_VECTOR_CHECK_COMPATIBLE(o);
269  IMP_VECTOR_CHECK;
270  for (unsigned int i=0; i<get_dimension(); ++i) {
271  operator[](i) += o[i];
272  }
273  return *this;
274  }
275 
276  VectorD& operator-=(const VectorD &o) {
277  IMP_VECTOR_CHECK_COMPATIBLE(o);
278  IMP_VECTOR_CHECK;
279  for (unsigned int i=0; i<get_dimension(); ++i) {
280  operator[](i) -= o[i];
281  }
282  return *this;
283  }
284 
285  VectorD& operator/=(double f) {
286  IMP_VECTOR_CHECK;
287  for (unsigned int i=0; i<get_dimension(); ++i) {
288  operator[](i) /= f;
289  }
290  return *this;
291  }
292 
293  VectorD& operator*=(double f) {
294  IMP_VECTOR_CHECK;
295  for (unsigned int i=0; i<get_dimension(); ++i) {
296  operator[](i) *= f;
297  }
298  return *this;
299  }
300 
301  void show(std::ostream &out, std::string delim,
302  bool parens=true) const {
303  IMP_VECTOR_CHECK;
304  if (parens) out << "(";
305  for (unsigned int i=0; i<get_dimension(); ++i) {
306  out << operator[](i);
307  if (i != get_dimension()-1) {
308  out << delim;
309  }
310  }
311  if (parens) out << ")";
312  }
313  IMP_SHOWABLE_INLINE(VectorD, show(out, ", "););
314 #endif
315 
316 #ifndef SWIG
317  typedef double* CoordinateIterator;
318  CoordinateIterator coordinates_begin() {return data_.get_data();}
319  CoordinateIterator coordinates_end() {
320  return data_.get_data()+get_dimension();
321  }
322  typedef const double* CoordinateConstIterator;
323  CoordinateConstIterator coordinates_begin() const {
324  return data_.get_data();
325  }
326  CoordinateConstIterator coordinates_end() const {
327  return data_.get_data()+get_dimension();
328  }
329 #endif
330 
331 #ifndef SWIG
332  // For some reason, this method breaks IMP::atom::get_rmsd() in Python, so
333  // hide it from SWIG
334  Floats get_coordinates() const {
335  return Floats(coordinates_begin(), coordinates_end());
336  }
337 #endif
338 
339 #if !defined(IMP_DOXYGEN) && !defined(SWIG)
340  const double *get_data() const {return data_.get_data();}
341 #endif
342  unsigned int get_dimension() const {
343  return data_.get_dimension();
344  }
345 private:
346 
347  internal::VectorData<double, D, false> data_;
348 };
349 
350 #ifndef IMP_DOXYGEN
351 
352 
353 template <int D>
354 inline std::ostream &operator<<(std::ostream &out, const VectorD<D> &v) {
355  v.show(out);
356  return out;
357 }
358 
359 template <int D>
360 inline std::istream &operator>>(std::istream &in, VectorD<D> &v) {
361  for (unsigned int i=0; i< D; ++i) {
362  in >> v[i];
363  }
364  return in;
365 }
366 
367 #endif
368 
369 //! lexicographic comparison of two vectors
370 /** Note that this is not very reliable and probably should not be used.
371  \relates VectorD
372  */
373 template <int D>
374 inline int compare(const VectorD<D> &a, const VectorD<D> &b) {
375  IMP_USAGE_CHECK(a.get_dimension()== b.get_dimension(),
376  "Dimensions don't match.");
377  for (unsigned int i=0; i< a.get_dimension(); ++i) {
378  if (a[i] < b[i]) return -1;
379  else if (a[i] > b[i]) return 1;
380  }
381  return 0;
382 }
383 
384 /** \relates VectorD */
385 template <int D>
386 inline VectorD<D> operator*(double s, const VectorD<D> &o) {
387  return o*s;
388 }
389 
390 //! compute the squared distance between two vectors
391 /** \relates VectorD
392  */
393 template <int D>
394 inline double get_squared_distance(const VectorD<D> &v1, const VectorD<D> &v2) {
395  return (v1-v2).get_squared_magnitude();
396 }
397 
398 //! compute the distance between two vectors
399 /** \relates VectorD
400  */
401 template <int D>
402 inline double get_distance(const VectorD<D> &v1, const VectorD<D> &v2) {
403  return std::sqrt(get_squared_distance(v1, v2));
404 }
405 
406 //! Return the basis vector for the given coordinate
407 /** Return the unit vector pointing in the direction of the requested
408  coordinate. That is
409  \code
410  get_basis_vector_d<3>(2)== Vector3D(0,0,1);
411  \endcode
412  \relatesalso VectorD
413  */
414 template <int D>
415 inline VectorD<D> get_basis_vector_d(unsigned int coordinate) {
416  IMP_USAGE_CHECK(coordinate<D, "There are only " << D << " basis vectors");
417  double vs[D];
418  for (unsigned int i=0; i< D; ++i) {
419  if (i==coordinate) vs[i]=1;
420  else vs[i]=0;
421  }
422  return VectorD<D>(vs, vs+D);
423 }
424 
425 //! Return a dynamically sized basis vector
426 inline VectorD<-1> get_basis_vector_kd( int D,
427  unsigned int coordinate) {
428  IMP_USAGE_CHECK(D>0, "D must be positive");
429  IMP_USAGE_CHECK(coordinate<static_cast<unsigned int>(D),
430  "There are only " << D << " basis vectors");
431  boost::scoped_array<double> vs(new double[D]);
432  for (int i=0; i< D; ++i) {
433  if (i==static_cast<int>(coordinate)) vs[i]=1;
434  else vs[i]=0;
435  }
436  return VectorD<-1>(vs.get(), vs.get()+D);
437 }
438 
439 //! Return a vector of zeros
440 template <int D>
442  IMP_USAGE_CHECK(D>0, "D must be positive");
443  Floats vs(D, 0);
444  return VectorD<D>(vs.begin(), vs.end());
445 }
446 
447 //! Return a dynamically sized vector of zeros
448 inline VectorD<-1> get_zero_vector_kd( int D) {
449  IMP_USAGE_CHECK(D>0, "D must be positive");
450  Floats vs(D, 0);
451  return VectorD<-1>(vs.begin(), vs.end());
452 }
453 
454 
455 //! Return a vector of ones (or another constant)
456 inline VectorD<-1> get_ones_vector_kd(unsigned int D, double v=1) {
457  IMP_USAGE_CHECK(D>0, "D must be positive");
458  boost::scoped_array<double> vv(new double[D]);
459  for ( unsigned int i=0; i< D; ++i) {
460  vv[i]=v;
461  }
462  return VectorD<-1>(vv.get(), vv.get()+D);
463 }
464 
465 //! Return a vector of ones (or another constant)
466 template <int D>
467 inline VectorD<D> get_ones_vector_d(double v=1) {
468  IMP_USAGE_CHECK(D>0, "D must be positive");
469  boost::scoped_array<double> vv(new double[D]);
470  for (unsigned int i=0; i< D; ++i) {
471  vv[i]=v;
472  }
473  return VectorD<D>(vv.get(), vv.get()+D);
474 }
475 
476 
477 #ifndef SWIG
478 
479 /** \name Norms
480  We define a number of standard, \f$L^p\f$, norms on VectorD.
481  - \f$L^1\f$ is the Manhattan distance, the sum of the components
482  - \f$L^2\f$ is the standard Euclidean length
483  - \f$L^{\inf}\f$ is the maximum of the components
484  @{
485 */
486 
487 template <int D>
488 inline double get_l2_norm(const VectorD<D> &v) {
489  return v.get_magnitude();
490 }
491 
492 template <int D>
493 inline double get_l1_norm(const VectorD<D> &v) {
494  double n=std::abs(v[0]);
495  for (unsigned int i=1; i< v.get_dimension(); ++i) {
496  n+= std::abs(v[i]);
497  }
498  return n;
499 }
500 
501 template <int D>
502 inline double get_linf_norm(const VectorD<D> &v) {
503  double n=std::abs(v[0]);
504  for (unsigned int i=1; i< v.get_dimension(); ++i) {
505  n= std::max(n, std::abs(v[i]));
506  }
507  return n;
508 }
509 
510 /** @} */
511 
512 #ifndef IMP_DOXYGEN
513 
514 template <int D>
515 struct SpacesIO
516 {
517  const VectorD<D> &v_;
518  SpacesIO(const VectorD<D> &v): v_(v){}
519 };
520 
521 template <int D>
522 struct CommasIO
523 {
524  const VectorD<D> &v_;
525  CommasIO(const VectorD<D> &v): v_(v){}
526 };
527 template <int D>
528 inline std::ostream &operator<<(std::ostream &out, const SpacesIO<D> &s)
529 {
530  s.v_.show(out, " ", false);
531  return out;
532 }
533 template <int D>
534 inline std::ostream &operator<<(std::ostream &out, const CommasIO<D> &s)
535 {
536  s.v_.show(out, ", ", false);
537  return out;
538 }
539 
540 //! Use this before outputing to delimited vector entries with a space
541 /** std::cout << spaces_io(v);
542  produces "1.0 2.0 3.0"
543  \relatesalso VectorD
544  */
545 template <int D>
546 inline SpacesIO<D> spaces_io(const VectorD<D> &v) {
547  return SpacesIO<D>(v);
548 }
549 
550 
551 
552 
553 //! Use this before outputing to delimited vector entries with a comma
554 /** std::cout << commas_io(v);
555  produces "1.0, 2.0, 3.0"
556  \relatesalso VectorD
557  */
558 template <int D>
559 inline CommasIO<D> commas_io(const VectorD<D> &v) {
560  return CommasIO<D>(v);
561 }
562 #endif // doxygen
563 
564 #endif //swig
565 /** 1D vector typedef for swig */
567 /** 1D vectors typedef for swig */
569 /** 2D vector typedef for swig */
571 /** 2D vectors typedef for swig */
573 /** 3D vector typedef for swig */
575 /** 3D vectors typedef for swig */
577 /** 4D vector typedef for swig */
579 /** 4D vectors typedef for swig */
581 /** 5D vector typedef for swig */
583 /** 5D vectors typedef for swig */
585 /** 6D vector typedef for swig */
587 /** 6D vector typedef for swig */
589 /** KD vector typedef for swig */
590 typedef VectorD<-1> VectorKD;
591 /** KD vectors typedef for swig */
593 
594 
595 /** \relates VectorD */
596 template <int D>
597 inline const VectorD<D> &get_vector_d_geometry(const VectorD<D> &g) {return g;}
598 /** \relates VectorD */
599 template <int D>
600 inline void set_vector_d_geometry(VectorD<D> &g, const VectorD<D> &v) {g=v;}
601 
602 
603 /** \relatesalso VectorD
604  Return the vector that is the elementwise product of the two.
605 */
606 template <int D>
608  const algebra::VectorD<D>& b) {
609  VectorD<D> ret(a);
610  for (unsigned int i=0; i< ret.get_dimension(); ++i) {
611  ret[i]*=b[i];
612  }
613  return ret;
614 }
615 
616 /** \relatesalso VectorD
617  Return the vector that is the elementwise product of the two.
618 */
619 template <int D>
621  const algebra::VectorD<D>& b) {
622  IMP_USAGE_CHECK(a.size()== b.get_dimension(),
623  "Dimensions don't match,");
624  VectorD<D> ret(b);
625  for (unsigned int i=0; i< ret.get_dimension(); ++i) {
626  ret[i]*=a[i];
627  }
628  return ret;
629 }
630 
631 
632 
633 
634 /** A class to flexibly accept vectors as inputs to functions.
635  \relates VectorD
636  */
637 template <int D>
638 class VectorInputD: public VectorD<D>, public base::InputAdaptor {
639 public:
640  VectorInputD(const VectorD<D> &v): VectorD<D>(v){}
641  VectorInputD(const Floats &v): VectorD<D>(v){}
642 };
643 
644 /** Also accept floating point values for Vector1Ds
645 
646  \relates VectorD
647  */
648 template <>
649 class VectorInputD<1>: public VectorD<1>, public base::InputAdaptor {
650 public:
651  VectorInputD(const VectorD<1> &v): VectorD<1>(v){}
652  VectorInputD(const Floats &v): VectorD<1>(v){}
653  VectorInputD(double v): VectorD<1>(v){}
654 };
655 
656 /** Typedef for python. */
658 /** Typedef for python. */
660 /** Typedef for python. */
662 /** Typedef for python.*/
664 /** Typedef for python. */
666 /** Typedef for python. */
668 /** Typedef for python. */
670 /** Typedef for python. */
672 /** Typedef for python. */
674 /** Typedef for python. */
676 /** Typedef for python. */
678 /** Typedef for python. */
680 /** Typedef for python. */
682 /** Typedef for python. */
684 
685 
686 
687 
688 
689 
690 IMPALGEBRA_END_NAMESPACE
691 
692 #endif /* IMPALGEBRA_VECTOR_D_H */