1 // 2 // util.h 3 // pb_solvers_code 4 // 5 /* 6 Copyright (c) 2015, Teresa Head-Gordon, Lisa Felberg, Enghui Yap, David Brookes 7 All rights reserved. 8 9 Redistribution and use in source and binary forms, with or without 10 modification, are permitted provided that the following conditions are met: 11 * Redistributions of source code must retain the above copyright 12 notice, this list of conditions and the following disclaimer. 13 * Redistributions in binary form must reproduce the above copyright 14 notice, this list of conditions and the following disclaimer in the 15 documentation and/or other materials provided with the distribution. 16 * Neither the name of UC Berkeley nor the 17 names of its contributors may be used to endorse or promote products 18 derived from this software without specific prior written permission. 19 20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS BE LIABLE FOR ANY 24 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #ifndef util_hpp 33 #define util_hpp 34 35 #ifdef _WIN32 36 #include <iso646.h> 37 #define _USE_MATH_DEFINES 38 #endif 39 40 #include <math.h> 41 #include <stdio.h> 42 #include <algorithm> 43 #include <complex> 44 #include <iostream> 45 #include <iomanip> 46 #include <unordered_map> 47 #include "MyMatrix.h" 48 #include "MyExpansion.h" 49 50 #ifdef _WIN32 51 extern double drand48(); 52 #endif 53 54 /* 55 Right scalar multiplication of a matrix 56 */ 57 template<typename T> 58 MyMatrix<T> operator*(MyMatrix<T> mat, const T& rhs) 59 { 60 MyMatrix<T> result = MyMatrix<T>(mat.get_nrows(), mat.get_ncols()); 61 int i, j; 62 for (i = 0; i < mat.get_nrows(); i++) 63 { 64 for (j= 0; j < mat.get_ncols(); j++) 65 { 66 result.set_val(i, j, rhs * mat(i, j)); 67 } 68 } 69 return result; 70 } 71 72 73 /* 74 lhs scalar multiplication of a matrix 75 */ 76 template<typename T> 77 MyMatrix<T> operator*(const T& lhs, MyMatrix<T> mat) 78 { 79 MyMatrix<T> result = MyMatrix<T>(mat.get_nrows(), mat.get_ncols()); 80 int i, j; 81 for (i = 0; i < mat.get_nrows(); i++) 82 { 83 for (j= 0; j < mat.get_ncols(); j++) 84 { 85 result.set_val(i, j, lhs * mat(i, j)); 86 } 87 } 88 return result; 89 } 90 91 /* 92 Class for storing three dimensional points in spherical or 93 euclidean coordinates 94 Should note that THETA = polar angle [ 0 <= THETA <= PI ] 95 and PHI = azimuthal angle [ 0 <= PHI <= 2*PI ] 96 */ 97 template<typename T> 98 class Point 99 { 100 protected: 101 T p1_; // x or r 102 T p2_; // y or theta 103 T p3_; // z or phi 104 bool sph_; // whether or not the point is in spherical coordinates 105 106 // convert between coordinatre systems: convert_to_spherical()107 void convert_to_spherical() 108 { 109 if (sph_) 110 return; // do nothing if already spherical 111 112 T theta, phi; 113 T r = sqrt(p1_*p1_ + p2_*p2_ + p3_*p3_); 114 115 if (r < fabs(p3_)) 116 r = fabs(p3_); 117 118 if (r == 0.0) 119 theta = 0.0; 120 else 121 theta = acos(p3_/r); 122 123 if ((p1_ == 0.0) && (p2_ == 0.0)) 124 phi = 0.0; 125 else 126 phi = atan2(p2_, p1_); 127 128 p1_ = r; 129 p2_ = theta; 130 p3_ = phi; 131 sph_ = true; 132 } 133 convert_to_euclidean()134 void convert_to_euclidean() 135 { 136 if (!sph_) 137 return; // do nothing if already euclidean 138 139 T x, y, z; 140 x = (abs(p1_*sin(p2_)*cos(p3_)) < 1e-15) ? 0 : p1_*sin(p2_)*cos(p3_); 141 y = (abs(p1_*sin(p2_)*sin(p3_)) < 1e-15) ? 0 : p1_*sin(p2_)*sin(p3_); 142 z = (abs(p1_*cos(p2_)) < 1e-15) ? 0 : p1_*cos(p2_); 143 144 p1_ = x; 145 p2_ = y; 146 p3_ = z; 147 sph_ = false; 148 } 149 150 public: 151 152 // constructor given three coordinate values and whether those are spherical 153 // default is to assum euclidean 154 Point(T p1=T(), T p2=T(), T p3=T(), bool sph=false) p1_(p1)155 :p1_(p1), p2_(p2), p3_(p3), sph_(sph) 156 { 157 } 158 159 //constructor given a vector 160 Point(MyVector<T> vec, bool sph=false) p1_(vec[0])161 :p1_(vec[0]), p2_(vec[1]), p3_(vec[2]), sph_(sph) 162 { 163 } 164 165 Point<T> operator=(Point<T> other) 166 { 167 if (this != &other) // protect against invalid self-assignment 168 { 169 p1_ = other.p1_; 170 p2_ = other.p2_; 171 p3_ = other.p3_; 172 sph_ = other.sph_; 173 } 174 return *this; 175 } 176 177 T operator[](int i) 178 { 179 if (i == 0) return p1_; 180 else if (i == 1) return p2_; 181 else if (i == 2) return p3_; 182 else return T(); 183 } 184 185 bool operator==(const Point<T> &other) const 186 { 187 return (p1_ == other.p1_ && p2_ == other.p2_ && p3_ == other.p3_); 188 } 189 set_x(T val)190 void set_x(T val) { convert_to_euclidean(); p1_ = val; } set_y(T val)191 void set_y(T val) { convert_to_euclidean(); p2_ = val; } set_z(T val)192 void set_z(T val) { convert_to_euclidean(); p3_ = val; } 193 set_r(T val)194 void set_r(T val) { convert_to_spherical(); p1_ = val; } set_theta(T val)195 void set_theta(T val) { convert_to_spherical(); p2_ = val; } set_phi(T val)196 void set_phi(T val) { convert_to_spherical(); p3_ = val; } 197 198 // 199 //arithmetic operators: 200 201 //scalar multiplication 202 Point<T> operator*(T scalar) 203 { 204 Point<T> pout; 205 if (sph_) convert_to_euclidean(); //for simplicity 206 pout.p1_ = p1_ * scalar; 207 pout.p2_ = p2_ * scalar; 208 pout.p3_ = p3_ * scalar; 209 return pout; 210 } 211 212 213 Point<T> operator*=(T scalar) 214 { 215 if (sph_) convert_to_euclidean(); 216 p1_ *= scalar; 217 p2_ *= scalar; 218 p3_ *= scalar; 219 return *this; 220 } 221 222 Point<T> operator+=(Point<T>& rhs) 223 { 224 if (sph_) convert_to_euclidean(); 225 p1_ += rhs.p1_; 226 p2_ += rhs.p2_; 227 p3_ += rhs.p3_; 228 return *this; 229 } 230 231 Point<T> operator+(Point<T> other) 232 { 233 Point<T> pout; 234 if (sph_) convert_to_euclidean(); 235 pout.p1_ = p1_ + other.p1_; 236 pout.p2_ = p2_ + other.p2_; 237 pout.p3_ = p3_ + other.p3_; 238 return pout; 239 } 240 241 Point<T> operator-(Point<T> other) 242 { 243 Point<T> pout; 244 if (sph_) convert_to_euclidean(); //for simplicity 245 pout.p1_ = p1_ - other.p1_; 246 pout.p2_ = p2_ - other.p2_; 247 pout.p3_ = p3_ - other.p3_; 248 return pout; 249 } 250 251 // calculate the distance to another point dist(Point<T> other)252 double dist(Point<T> other) 253 { 254 convert_to_euclidean(); 255 double d = pow(this->x() - other.x(), 2); 256 d += pow(this->y() - other.y(), 2); 257 d += pow(this->z() - other.z(), 2); 258 d = sqrt(d); 259 return d; 260 } 261 dot(Point<T> & other)262 double dot(Point<T>& other) 263 { 264 convert_to_euclidean(); 265 double dot = p1_ * other.x() + p2_ * other.y() + p3_ * other.z(); 266 return dot; 267 } 268 rotate(MyMatrix<T> & rotmat)269 Point<T> rotate(MyMatrix<T>& rotmat) 270 { 271 convert_to_euclidean(); 272 T x, y, z; 273 x = rotmat(0, 0) * p1_ + rotmat(0, 1) * p2_ + rotmat(0, 2) * p3_; 274 y = rotmat(1, 0) * p1_ + rotmat(1, 1) * p2_ + rotmat(1, 2) * p3_; 275 z = rotmat(2, 0) * p1_ + rotmat(2, 1) * p2_ + rotmat(2, 2) * p3_; 276 return Point<T>(x, y, z); 277 } 278 279 // Method to set xyz using numbers 0=x, 1=y, 2=z set_cart(int dim,T val)280 void set_cart(int dim, T val) 281 { 282 if (sph_) convert_to_euclidean(); 283 284 if (dim == 0) p1_ = val; 285 else if (dim == 1) p2_ = val; 286 else p3_ = val; 287 } 288 289 // Method to get xyz using numbers 0=x, 1=y, 2=z get_cart(int val)290 const T& get_cart(int val) 291 { 292 if (sph_) convert_to_euclidean(); 293 294 if (val == 0) return p1_; 295 else if (val == 1) return p2_; 296 297 return p3_; 298 } 299 get_p1()300 const T& get_p1() const { return p1_; } get_p2()301 const T& get_p2() const { return p2_; } get_p3()302 const T& get_p3() const { return p3_; } 303 304 305 // Getter methods perform necessary conversions: x()306 const T& x() 307 { 308 if (sph_) convert_to_euclidean(); 309 return p1_; 310 } y()311 const T& y() 312 { 313 if (sph_) convert_to_euclidean(); 314 return p2_; 315 } z()316 const T& z() 317 { 318 if (sph_) convert_to_euclidean(); 319 return p3_; 320 } r()321 const T& r() 322 { 323 if (!sph_) convert_to_spherical(); 324 return p1_; 325 } theta()326 const T& theta() 327 { 328 if (!sph_) convert_to_spherical(); 329 return p2_; 330 } phi()331 const T& phi() 332 { 333 if (!sph_) convert_to_spherical(); 334 return p3_; 335 } 336 norm2()337 T norm2() { return p1_*p1_ + p2_*p2_ + p3_*p3_; } 338 norm()339 T norm() { return sqrt(norm2()); } 340 341 342 }; 343 344 345 346 /* 347 Class for storing quaternions, which are defined as a real part and a vector 348 part 349 */ 350 class Quaternion 351 { 352 protected: 353 double w_; // real part 354 355 //imaginary coefficients: 356 double a_; 357 double b_; 358 double c_; 359 360 public: 361 typedef Quaternion Quat; 362 363 /* 364 Construct a quaternion given all the coefficients explicitly 365 */ 366 Quaternion(double w=1, double a=0, double b=0, double c=0, bool norm=true): w_(w)367 w_(w), a_(a), b_(b), c_(c) 368 { 369 if (norm) normalize(); 370 } 371 372 /* 373 Construct a quarernion given an angle and axis of rotation 374 */ 375 Quaternion(double theta, Point<double> axis, bool norm=true) 376 { 377 w_ = cos(theta/2.0); 378 double scal = sin(theta/2.0); 379 a_ = (axis.x()/axis.norm()) * scal; 380 b_ = (axis.y()/axis.norm()) * scal; 381 c_ = (axis.z()/axis.norm()) * scal; 382 if (norm) normalize(); 383 } 384 385 /* 386 Construct a quarernion from another 387 */ Quaternion(const Quaternion & q)388 Quaternion(const Quaternion & q) { *this = q; } 389 390 /* 391 Normalize the quaternion 392 */ normalize()393 void normalize() 394 { 395 double in_norm = 1.0/sqrt(w_*w_ + a_*a_ + b_*b_ + c_*c_); 396 w_ *= in_norm; a_ *= in_norm; b_ *= in_norm; c_ *= in_norm; 397 } 398 399 // return parts of quaternion get_w()400 double get_w() { return w_; } get_a()401 double get_a() { return a_; } get_b()402 double get_b() { return b_; } get_c()403 double get_c() { return c_; } get_imag()404 Point<double> get_imag() { return Point <double> ( a_, b_, c_ ); } 405 406 // returns the conjugate of this quarternion, negates all complex terms conj()407 Quat conj() { return Quat(w_, -a_, -b_, -c_); } 408 409 /* 410 Quaternion = operator 411 */ 412 Quaternion & operator=(const Quaternion & q) 413 { 414 w_ = q.w_; a_ = q.a_; b_ = q.b_; c_ = q.c_; 415 return *this; 416 } 417 418 /* 419 Right multiply this by another quarternion 420 */ 421 Quat operator*(Quat rhs) 422 { 423 double t0, t1, t2, t3; // resulting coefficients 424 double q0, q1, q2, q3; // this coeffs 425 double r0, r1, r2, r3; // rhs coeffs 426 427 q0=w_; q1=a_; q2=b_; q3=c_; 428 r0=rhs.w_; r1=rhs.a_; r2=rhs.b_; r3=rhs.c_; 429 430 t0 = q0*r0 - q1*r1 - q2*r2 - q3*r3; 431 t1 = q0*r1 + q1*r0 + q2*r3 - q3*r2; 432 t2 = q0*r2 - q1*r3 + q2*r0 + q3*r1; 433 t3 = q0*r3 + q1*r2 - q2*r1 + q3*r0; 434 435 return Quat(t0, t1, t2, t3, false); 436 } 437 chooseRandom()438 Quat chooseRandom() 439 { 440 double s = drand48(); 441 double sig1 = sqrt(1.0-s); 442 double sig2 = sqrt(s); 443 double t1 = 2.0*drand48()*M_PI; 444 double t2 = 2.0*drand48()*M_PI; 445 Quat Q(cos(t2)*sig2, sin(t1)*sig1, cos(t1)*sig1, sin(t2)*sig2); 446 447 return Q; 448 } 449 450 /* 451 Rotate a point with this quarternion. If the quarternion is q and the point 452 is p, then this returns q*p*conj(q) 453 */ rotate_point(Point<double> pt)454 Point<double> rotate_point(Point<double> pt) 455 { 456 //make the point a quarternion with real part=0 457 Quat p (0, pt.x(), pt.y(), pt.z(), false); 458 Quat q_conj = conj(); 459 460 Quat result = *this * p; 461 result = result * q_conj; 462 463 Point<double> pp (result.a_, result.b_, result.c_); 464 return pp; 465 } 466 // 467 }; 468 469 typedef complex<double> cmplx; 470 typedef Point<double> Pt; 471 typedef Point<cmplx> Ptx; 472 typedef Quaternion Quat; 473 474 475 namespace std { 476 //hash for Point classes: 477 template <> 478 struct hash<Pt> 479 { 480 size_t operator()(const Pt& k) const 481 { 482 size_t h1 = std::hash<double>()(k.get_p1()); 483 size_t h2 = std::hash<double>()(k.get_p2()); 484 size_t h3 = std::hash<double>()(k.get_p3()); 485 return (h1 ^ (h2 << 1)) ^ h3; 486 } 487 }; 488 } 489 490 491 #endif /* util_h */ 492