ALPSCore reference
complex_op.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1998-2018 ALPS Collaboration. See COPYRIGHT.TXT
3  * All rights reserved. Use is subject to license terms. See LICENSE.TXT
4  * For use in publications, see ACKNOWLEDGE.TXT
5  */
6 #pragma once
7 
8 #include <complex>
9 #include <algorithm>
10 #include <functional>
11 #include <cmath>
12 #include <type_traits>
13 
14 #include <iosfwd>
15 #include <Eigen/Core>
16 
17 // Forward declarations
18 
19 namespace alps { namespace alea {
20  template <typename T> class complex_op;
21 }}
22 namespace Eigen {
23  template <typename T> struct NumTraits;
24  template <typename S1, typename S2, typename Op> struct ScalarBinaryOpTraits;
25 }
26 
27 // Actual declarations
28 
29 namespace alps { namespace alea {
30 
48 template <typename T>
49 class complex_op
50 {
51 public:
52  static_assert(std::is_floating_point<T>::value,
53  "T argument of complex_op<T> must be real scalar type");
54 
55  static complex_op outer(std::complex<T> a, std::complex<T> b)
56  {
57  return complex_op(a.real() * b.real(), a.real() * b.imag(),
58  a.imag() * b.real(), a.imag() * b.imag());
59  }
60 
61  static complex_op diag(std::complex<T> a)
62  {
63  return complex_op(a.real(), 0, 0, a.imag());
64  }
65 
66  static complex_op diag(T a) { return complex_op(a, 0, 0, a); }
67 
68 public:
70  complex_op() { }
71 
73  complex_op(double x) : complex_op(x, 0, 0, x) { }
74 
76  complex_op(T rere, T reim, T imre, T imim)
77  {
78  vals_[0][0] = rere;
79  vals_[0][1] = reim;
80  vals_[1][0] = imre;
81  vals_[1][1] = imim;
82  }
83 
84  T &rere() { return vals_[0][0]; }
85  T &reim() { return vals_[0][1]; }
86  T &imre() { return vals_[1][0]; }
87  T &imim() { return vals_[1][1]; }
88 
89  const T &rere() const { return vals_[0][0]; }
90  const T &reim() const { return vals_[0][1]; }
91  const T &imre() const { return vals_[1][0]; }
92  const T &imim() const { return vals_[1][1]; }
93 
95  {
96  std::transform(&vals_[0][0], &vals_[2][0], &x.vals_[0][0],
97  &vals_[0][0], std::plus<T>());
98  return *this;
99  }
100 
102  {
103  std::transform(&vals_[0][0], &vals_[2][0], &x.vals_[0][0],
104  &vals_[0][0], std::minus<T>());
105  return *this;
106  }
107 
109  {
110  vals_[0][0] *= x;
111  vals_[0][1] *= x;
112  vals_[1][0] *= x;
113  vals_[1][1] *= x;
114  return *this;
115  }
116 
117  complex_op &operator/=(double x) { return *this *= 1/x; }
118 
120  {
121  return complex_op(-x.rere(), -x.reim(), -x.imre(), -x.imim());
122  }
123 
125  {
126  return complex_op(l) += r;
127  }
128 
130  {
131  return complex_op(l) -= r;
132  }
133 
134  friend complex_op operator*(complex_op x, double f)
135  {
136  return complex_op(x) *= f;
137  }
138 
139  friend complex_op operator*(double f, complex_op x) { return x * f; }
140 
141  friend complex_op operator/(complex_op x, double f)
142  {
143  return complex_op(x) /= f;
144  }
145 
147  {
148  // Matrix multiplication of two 2x2 matrices
149  return complex_op(l.rere() * r.rere() + l.reim() * r.imre(),
150  l.rere() * r.reim() + l.reim() * r.imim(),
151  l.imre() * r.rere() + l.imim() * r.imre(),
152  l.imre() * r.reim() + l.imim() * r.imim());
153  }
154 
156  {
157  return dot(l, inv(r));
158  }
159 
161  {
162  return std::equal(&l.vals_[0][0], &l.vals_[2][0], &r.vals_[0][0]);
163  }
164 
166  {
167  return !std::equal(&l.vals_[0][0], &l.vals_[2][0], &r.vals_[0][0]);
168  }
169 
171  {
172  // [a, b; c, d]^(-1) = 1/(ad - bc) * [d, -b; -c, a]
173  T inv_det = 1/(x.rere() * x.imim() - x.reim() * x.imre());
174  return complex_op(inv_det * x.imim(), inv_det * -x.reim(),
175  inv_det * -x.imre(), inv_det * x.rere());
176  }
177 
179  {
180  // |x|^2 = conj(x) * x = x.T * x
181  T off_diag = x.rere() * x.reim() + x.imre() * x.imim();
182  return complex_op(x.rere() * x.rere() + x.imre() * x.imre(),
183  off_diag, off_diag,
184  x.reim() * x.reim() + x.imim() * x.imim());
185  }
186 
188  {
189  // Levinger, Math. Mag. 53(4), 222-224, 1980
190  T det = x.rere() * x.imim() - x.reim() * x.imre();
191  T tr = x.rere() + x.imim();
192 
193  // ensure that the matrix is pos definite
194  if (det < 0 || tr < 0)
195  return complex_op(NAN, NAN, NAN, NAN);
196 
197  // choosing + here ensures that the result is also pos definite
198  T s = std::sqrt(det);
199  T inv_t = 1/std::sqrt(tr + 2 * s);
200  return complex_op(inv_t * (x.rere() + s), inv_t * x.reim(),
201  inv_t * x.imre(), inv_t * (x.imim() + s));
202  }
203 
204  friend bool isnan(complex_op x)
205  {
206  return std::any_of(&x.vals_[0][0], &x.vals_[2][0], [](T y) {return std::isnan(y); });
207  }
208 
209  friend bool isfinite(complex_op x)
210  {
211  return std::all_of(&x.vals_[0][0], &x.vals_[2][0], [](T y) {return std::isfinite(y); });
212  }
213 
214  friend bool isinf(complex_op x)
215  {
216  // An object cannot be inf and nan at the same time, for multi-
217  // component objects nan takes precedence
218  if (isnan(x))
219  return false;
220 
221  return std::any_of(&x.vals_[0][0], &x.vals_[2][0], [](T y) {return std::isinf(y); });
222  }
223 
224  friend complex_op abs(complex_op x) { return sqrt(abs2(x)); }
225 
226  friend std::ostream &operator<<(std::ostream &out, complex_op x)
227  {
228  out << '(' << x.rere() << ',' << x.reim()
229  << ';' << x.imre() << ',' << x.imim() << ')';
230  return out;
231  }
232 
233 
234 private:
235  T vals_[2][2];
236 };
237 
238 }} /* namespace alps::alea */
239 
240 namespace Eigen {
241 
245 template <typename T>
246 struct NumTraits< alps::alea::complex_op<T> >
247  : NumTraits<T> // gets epsilon, dummy_precision, lowest, highest functions
248 {
252 
253  enum {
254  IsComplex = 0, // Since typeof(real(x)) == typeof(x)
255  IsInteger = 0,
256  IsSigned = 1,
257  RequireInitialization = 1,
258  ReadCost = 1,
259  AddCost = 3,
260  MulCost = 5 // ~ (8 SMUL + 4 ADD)/4 with SMUL = 3
261  };
262 };
263 
264 template <typename T, typename BinaryOp>
265 struct ScalarBinaryOpTraits<alps::alea::complex_op<T>, T, BinaryOp>
266 {
268 };
269 
270 template <typename T, typename BinaryOp>
271 struct ScalarBinaryOpTraits<T, alps::alea::complex_op<T>, BinaryOp>
272 {
274 };
275 
276 } /* namespace Eigen */
friend complex_op abs(complex_op x)
Definition: complex_op.hpp:224
friend complex_op operator-(complex_op x)
Definition: complex_op.hpp:119
friend complex_op abs2(complex_op x)
Definition: complex_op.hpp:178
friend bool operator==(complex_op l, complex_op r)
Definition: complex_op.hpp:160
friend complex_op operator/(complex_op x, double f)
Definition: complex_op.hpp:141
boost::array< T, N > sqrt(boost::array< T, N > arg)
friend complex_op operator*(complex_op x, double f)
Definition: complex_op.hpp:134
friend bool isfinite(complex_op x)
Definition: complex_op.hpp:209
friend complex_op operator-(complex_op l, complex_op r)
Definition: complex_op.hpp:129
friend complex_op operator*(double f, complex_op x)
Definition: complex_op.hpp:139
static complex_op diag(std::complex< T > a)
Definition: complex_op.hpp:61
mean_result< T > transform(no_prop, const transformer< T > &tf, const InResult &in)
Definition: transform.hpp:27
const T & imre() const
Definition: complex_op.hpp:91
complex_op & operator/=(double x)
Definition: complex_op.hpp:117
friend bool isnan(complex_op x)
Definition: complex_op.hpp:204
const T & imim() const
Definition: complex_op.hpp:92
complex_op(T rere, T reim, T imre, T imim)
Definition: complex_op.hpp:76
friend complex_op operator+(complex_op l, complex_op r)
Definition: complex_op.hpp:124
friend std::ostream & operator<<(std::ostream &out, complex_op x)
Definition: complex_op.hpp:226
static complex_op diag(T a)
Definition: complex_op.hpp:66
complex_op & operator*=(double x)
Definition: complex_op.hpp:108
friend bool operator!=(complex_op l, complex_op r)
Definition: complex_op.hpp:165
const T & reim() const
Definition: complex_op.hpp:90
friend complex_op inv(complex_op x)
Definition: complex_op.hpp:170
static complex_op outer(std::complex< T > a, std::complex< T > b)
Definition: complex_op.hpp:55
friend complex_op dot(complex_op l, complex_op r)
Definition: complex_op.hpp:146
friend complex_op sqrt(complex_op x)
Definition: complex_op.hpp:187
friend complex_op solve(complex_op l, complex_op r)
Definition: complex_op.hpp:155
T r(T x, T y=T(), T z=T())
const T & rere() const
Definition: complex_op.hpp:89
complex_op & operator-=(complex_op x)
Definition: complex_op.hpp:101
friend bool isinf(complex_op x)
Definition: complex_op.hpp:214
complex_op & operator+=(complex_op x)
Definition: complex_op.hpp:94