Qrack  1.7
General classical-emulating-quantum development framework
complex16simd.hpp
Go to the documentation of this file.
1 //
3 // (C) Daniel Strano and the Qrack contributors 2017, 2018. All rights reserved.
4 //
5 // This is a SIMD implementation of the double precision complex type.
6 // The API is designed to (almost entirely) mirror that of the C++ standard library
7 // double precision complex type.
8 //
9 // Licensed under the GNU Lesser General Public License V3.
10 // See LICENSE.md in the project root or https://www.gnu.org/licenses/lgpl-3.0.en.html
11 // for details.
12 
13 #pragma once
14 
15 #include <emmintrin.h>
16 
17 #if ENABLE_AVX
18 #include <smmintrin.h>
19 #endif
20 
21 namespace Qrack {
22 
24 struct Complex16Simd {
25  __m128d _val;
26 
27  inline Complex16Simd(){};
28  inline Complex16Simd(const __m128d& v) { _val = v; }
29  inline Complex16Simd(const double& real, const double& imag) { _val = _mm_set_pd(imag, real); }
30  inline Complex16Simd operator+(const Complex16Simd& other) const { return _mm_add_pd(_val, other._val); }
31  inline Complex16Simd operator+=(const Complex16Simd& other)
32  {
33  _val = _mm_add_pd(_val, other._val);
34  return _val;
35  }
36  inline Complex16Simd operator-(const Complex16Simd& other) const { return _mm_sub_pd(_val, other._val); }
37  inline Complex16Simd operator-=(const Complex16Simd& other)
38  {
39  _val = _mm_sub_pd(_val, other._val);
40  return _val;
41  }
42  inline Complex16Simd operator*(const Complex16Simd& other) const
43  {
44  return _mm_add_pd(_mm_mul_pd(_mm_shuffle_pd(_val, _val, 1), _mm_shuffle_pd((-other._val), other._val, 3)),
45  _mm_mul_pd(_val, _mm_shuffle_pd(other._val, other._val, 0)));
46  }
47  inline Complex16Simd operator*=(const Complex16Simd& other)
48  {
49  _val = _mm_add_pd(_mm_mul_pd(_mm_shuffle_pd(_val, _val, 1), _mm_shuffle_pd((-other._val), other._val, 3)),
50  _mm_mul_pd(_val, _mm_shuffle_pd(other._val, other._val, 0)));
51  return _val;
52  }
53  inline Complex16Simd operator*(const double rhs) const { return _mm_mul_pd(_val, _mm_set1_pd(rhs)); }
54  inline Complex16Simd operator/(const Complex16Simd& other) const
55  {
56 #if ENABLE_AVX
57  double nrm = _mm_cvtsd_f64(_mm_dp_pd(other._val, other._val, 0xf1));
58 #else
59  __v2df temp = (__v2df)_mm_mul_pd(other._val, other._val);
60  double nrm = (temp[0] + temp[1]);
61 #endif
62  return _mm_div_pd(
63  _mm_add_pd(_mm_mul_pd(_mm_shuffle_pd(_val, _val, 1), _mm_shuffle_pd(other._val, -(other._val), 3)),
64  _mm_mul_pd(_val, _mm_shuffle_pd(other._val, other._val, 0))),
65  _mm_set1_pd(nrm));
66  }
67  inline Complex16Simd operator/=(const Complex16Simd& other)
68  {
69 #if ENABLE_AVX
70  double nrm = _mm_cvtsd_f64(_mm_dp_pd(other._val, other._val, 0xf1));
71 #else
72  __v2df temp = (__v2df)_mm_mul_pd(other._val, other._val);
73  double nrm = (temp[0] + temp[1]);
74 #endif
75  _val = _mm_div_pd(
76  _mm_add_pd(_mm_mul_pd(_mm_shuffle_pd(_val, _val, 1), _mm_shuffle_pd(other._val, -(other._val), 3)),
77  _mm_mul_pd(_val, _mm_shuffle_pd(other._val, other._val, 0))),
78  _mm_set1_pd(nrm));
79  return _val;
80  }
81  inline Complex16Simd operator/(const double rhs) const { return _mm_div_pd(_val, _mm_set1_pd(rhs)); }
82  inline Complex16Simd operator/=(const double rhs)
83  {
84  _val = _mm_div_pd(_val, _mm_set1_pd(rhs));
85  return _val;
86  }
87  inline Complex16Simd operator-() const { return -_val; }
88  inline Complex16Simd operator*=(const double& other)
89  {
90  _val = _mm_mul_pd(_val, _mm_set1_pd(other));
91  return _val;
92  }
93  inline bool operator==(const Complex16Simd& rhs) const
94  {
95  __v2df vec = (__v2df)(_val == rhs._val);
96  return vec[0] && vec[1];
97  }
98  inline bool operator!=(const Complex16Simd& rhs) const
99  {
100  __v2df vec = (__v2df)(_val != rhs._val);
101  return vec[0] && vec[1];
102  }
103 };
104 
105 inline Complex16Simd operator*(const double& lhs, const Complex16Simd& rhs)
106 {
107  return _mm_mul_pd(_mm_set1_pd(lhs), rhs._val);
108 }
109 inline Complex16Simd operator/(const double& lhs, const Complex16Simd& rhs)
110 {
111  __v2df temp = (__v2df)_mm_mul_pd(rhs._val, rhs._val);
112  double denom = temp[0] + temp[1];
113  temp = (__v2df)_mm_div_pd(_mm_mul_pd(rhs._val, _mm_set1_pd(lhs)), _mm_set1_pd(denom));
114  return Complex16Simd(temp[0], -temp[1]);
115 }
116 
117 inline double real(const Complex16Simd& cmplx) { return ((__v2df)(cmplx._val))[0]; }
118 inline double imag(const Complex16Simd& cmplx) { return ((__v2df)(cmplx._val))[1]; }
119 
120 inline double arg(const Complex16Simd& cmplx)
121 {
122  if (cmplx == Complex16Simd(0.0, 0.0))
123  return 0.0;
124  return atan2(imag(cmplx), real(cmplx));
125 }
126 inline Complex16Simd conj(const Complex16Simd& cmplx)
127 {
128  return _mm_shuffle_pd(cmplx._val, _mm_sub_pd(_mm_set1_pd(0.0), cmplx._val), 2);
129 }
130 inline double norm(const Complex16Simd& cmplx)
131 {
132 #if ENABLE_AVX
133  return _mm_cvtsd_f64(_mm_dp_pd(cmplx._val, cmplx._val, 0xf1));
134 #else
135  __v2df temp = (__v2df)_mm_mul_pd(cmplx._val, cmplx._val);
136  return (temp[0] + temp[1]);
137 #endif
138 }
139 inline double abs(const Complex16Simd& cmplx) { return sqrt(norm(cmplx)); }
140 inline Complex16Simd polar(const double rho, const double theta = 0)
141 {
142  return _mm_set1_pd(rho) * _mm_set_pd(sin(theta), cos(theta));
143 }
144 } // namespace Qrack
Complex16Simd operator/(const Complex16Simd &other) const
Definition: complex16simd.hpp:54
Complex16Simd operator/=(const double rhs)
Definition: complex16simd.hpp:82
Complex16Simd operator*(const Complex16Simd &other) const
Definition: complex16simd.hpp:42
Complex16Simd(const __m128d &v)
Definition: complex16simd.hpp:28
Complex16Simd operator*=(const double &other)
Definition: complex16simd.hpp:88
Complex16Simd(const double &real, const double &imag)
Definition: complex16simd.hpp:29
Complex16Simd operator/(const double rhs) const
Definition: complex16simd.hpp:81
double arg(const Complex16Simd &cmplx)
Definition: complex16simd.hpp:120
double imag(const Complex16Simd &cmplx)
Definition: complex16simd.hpp:118
bool operator==(const Complex16Simd &rhs) const
Definition: complex16simd.hpp:93
bool operator!=(const Complex16Simd &rhs) const
Definition: complex16simd.hpp:98
Complex16Simd operator+(const Complex16Simd &other) const
Definition: complex16simd.hpp:30
double abs(const Complex16Simd &cmplx)
Definition: complex16simd.hpp:139
Complex16Simd operator*(const double rhs) const
Definition: complex16simd.hpp:53
Complex16Simd conj(const Complex16Simd &cmplx)
Definition: complex16simd.hpp:126
double real(const Complex16Simd &cmplx)
Definition: complex16simd.hpp:117
Complex16Simd operator-(const Complex16Simd &other) const
Definition: complex16simd.hpp:36
__m128d _val
Definition: complex16simd.hpp:25
Complex16Simd operator*=(const Complex16Simd &other)
Definition: complex16simd.hpp:47
double norm(const Complex16Simd &cmplx)
Definition: complex16simd.hpp:130
SIMD implementation of the double precision complex type.
Definition: complex16simd.hpp:24
Complex16Simd polar(const double rho, const double theta=0)
Definition: complex16simd.hpp:140
Complex16Simd operator/=(const Complex16Simd &other)
Definition: complex16simd.hpp:67
Definition: complex16simd.hpp:21
Complex16Simd operator+=(const Complex16Simd &other)
Definition: complex16simd.hpp:31
Complex16Simd operator-() const
Definition: complex16simd.hpp:87
Complex16Simd operator-=(const Complex16Simd &other)
Definition: complex16simd.hpp:37
Complex16Simd()
Definition: complex16simd.hpp:27