Qrack  9.0
General classical-emulating-quantum development framework
complex8x2simd.hpp
Go to the documentation of this file.
1 //
3 // (C) Daniel Strano and the Qrack contributors 2017-2023. All rights reserved.
4 //
5 // This is a SIMD implementation of the float precision complex type.
6 // The API is designed to (almost entirely) mirror that of the C++ standard library
7 // float 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 #if defined(_WIN32)
16 #include <intrin.h>
17 #elif ENABLE_SSE3
18 #include <pmmintrin.h>
19 #else
20 #include <xmmintrin.h>
21 #endif
22 
23 #include <complex>
24 
25 namespace Qrack {
26 
27 static const __m128 SIGNMASK = _mm_set_ps(0.0f, -0.0f, 0.0f, -0.0f);
28 
32 union complex2 {
33  __m128 c2;
34  float f[4];
35 
36  inline complex2() {}
37  inline complex2(const __m128& cm2) { c2 = cm2; }
38  inline complex2(const complex2& cm2) { c2 = cm2.c2; }
39  inline complex2(const std::complex<float>& cm1, const std::complex<float>& cm2)
40  {
41  c2 = _mm_set_ps(cm2.imag(), cm2.real(), cm1.imag(), cm1.real());
42  }
43  inline complex2(const float& r1, const float& i1, const float& r2, const float& i2)
44  {
45  c2 = _mm_set_ps(i2, r2, i1, r1);
46  }
47  inline std::complex<float> c(const size_t& i) const { return complex(f[i << 1U], f[(i << 1U) + 1U]); }
48  inline complex2 operator+(const complex2& other) const { return _mm_add_ps(c2, other.c2); }
49  inline complex2 operator+=(const complex2& other)
50  {
51  c2 = _mm_add_ps(c2, other.c2);
52  return c2;
53  }
54  inline complex2 operator-(const complex2& other) const { return _mm_sub_ps(c2, other.c2); }
55  inline complex2 operator-=(const complex2& other)
56  {
57  c2 = _mm_sub_ps(c2, other.c2);
58  return c2;
59  }
60  inline complex2 operator*(const complex2& other) const
61  {
62  const __m128& oVal2 = other.c2;
63  return _mm_add_ps(
64  _mm_mul_ps(_mm_shuffle_ps(c2, c2, 177), _mm_xor_ps(SIGNMASK, _mm_shuffle_ps(oVal2, oVal2, 245))),
65  _mm_mul_ps(c2, _mm_shuffle_ps(oVal2, oVal2, 160)));
66  }
67  inline complex2 operator*=(const complex2& other)
68  {
69  const __m128& oVal2 = other.c2;
70  c2 =
71  _mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(c2, c2, 177), _mm_xor_ps(SIGNMASK, _mm_shuffle_ps(oVal2, oVal2, 245))),
72  _mm_mul_ps(c2, _mm_shuffle_ps(oVal2, oVal2, 160)));
73  return c2;
74  }
75  inline complex2 operator*(const float& rhs) const { return _mm_mul_ps(c2, _mm_set1_ps(rhs)); }
76  inline complex2 operator-() const { return _mm_mul_ps(_mm_set1_ps(-1.0f), c2); }
77  inline complex2 operator*=(const float& other)
78  {
79  c2 = _mm_mul_ps(c2, _mm_set1_ps(other));
80  return c2;
81  }
82 };
83 
84 inline complex2 mtrxColShuff(const complex2& mtrxCol) { return _mm_shuffle_ps(mtrxCol.c2, mtrxCol.c2, 177); }
85 inline complex2 matrixMul(const complex2& mtrxCol1, const complex2& mtrxCol2, const complex2& mtrxCol1Shuff,
86  const complex2& mtrxCol2Shuff, const complex2& qubit)
87 {
88  const __m128& col1 = mtrxCol1.c2;
89  const __m128& col2 = mtrxCol2.c2;
90  const __m128 dupeLo = _mm_shuffle_ps(qubit.c2, qubit.c2, 68);
91  const __m128 dupeHi = _mm_shuffle_ps(qubit.c2, qubit.c2, 238);
92  return _mm_add_ps(
93  _mm_add_ps(_mm_mul_ps(mtrxCol1Shuff.c2, _mm_xor_ps(SIGNMASK, _mm_shuffle_ps(dupeLo, dupeLo, 245))),
94  _mm_mul_ps(col1, _mm_shuffle_ps(dupeLo, dupeLo, 160))),
95  _mm_add_ps(_mm_mul_ps(mtrxCol2Shuff.c2, _mm_xor_ps(SIGNMASK, _mm_shuffle_ps(dupeHi, dupeHi, 245))),
96  _mm_mul_ps(col2, _mm_shuffle_ps(dupeHi, dupeHi, 160))));
97 }
98 inline complex2 matrixMul(const float& nrm, const complex2& mtrxCol1, const complex2& mtrxCol2,
99  const complex2& mtrxCol1Shuff, const complex2& mtrxCol2Shuff, const complex2& qubit)
100 {
101  return matrixMul(mtrxCol1, mtrxCol2, mtrxCol1Shuff, mtrxCol2Shuff, qubit) * nrm;
102 }
103 inline complex2 operator*(const float& lhs, const complex2& rhs) { return _mm_mul_ps(_mm_set1_ps(lhs), rhs.c2); }
104 
105 // See
106 // https://stackoverflow.com/questions/6996764/fastest-way-to-do-horizontal-sse-vector-sum-or-other-reduction#answer-35270026
107 inline float norm(const complex2& c)
108 {
109  const __m128 n = _mm_mul_ps(c.c2, c.c2);
110 #if ENABLE_SSE3
111  __m128 shuf = _mm_movehdup_ps(n);
112 #else
113  __m128 shuf = _mm_shuffle_ps(n, n, _MM_SHUFFLE(2, 3, 0, 1));
114 #endif
115  __m128 sums = _mm_add_ps(n, shuf);
116  shuf = _mm_movehl_ps(shuf, sums);
117  return _mm_cvtss_f32(_mm_add_ss(sums, shuf));
118 }
119 } // namespace Qrack
Definition: complex16x2simd.hpp:25
std::complex< half_float::half > complex
Definition: qrack_types.hpp:62
static const __m256d SIGNMASK
Definition: complex16x2simd.hpp:27
double norm(const complex2 &c)
Definition: complex16x2simd.hpp:101
complex2 matrixMul(const complex2 &mtrxCol1, const complex2 &mtrxCol2, const complex2 &mtrxCol1Shuff, const complex2 &mtrxCol2Shuff, const complex2 &qubit)
Definition: complex16x2simd.hpp:81
complex2 mtrxColShuff(const complex2 &mtrxCol)
Definition: complex16x2simd.hpp:80
complex2 operator*(const double &lhs, const complex2 &rhs)
Definition: complex16x2simd.hpp:99
SIMD implementation of the double precision complex vector type of 2 complex numbers,...
Definition: complex16x2simd.hpp:30
__m128 c2
Definition: complex8x2simd.hpp:33
complex2(const float &r1, const float &i1, const float &r2, const float &i2)
Definition: complex8x2simd.hpp:43
complex2 operator*(const complex2 &other) const
Definition: complex8x2simd.hpp:60
complex2(const complex2 &cm2)
Definition: complex8x2simd.hpp:38
complex2(const std::complex< float > &cm1, const std::complex< float > &cm2)
Definition: complex8x2simd.hpp:39
double f[4]
Definition: complex16x2simd.hpp:32
__m256d c2
Definition: complex16x2simd.hpp:31
complex2 operator*=(const complex2 &other)
Definition: complex8x2simd.hpp:67
complex2()
Definition: complex8x2simd.hpp:36
complex2(const __m128 &cm2)
Definition: complex8x2simd.hpp:37
complex2 operator-(const complex2 &other) const
Definition: complex8x2simd.hpp:54
complex2 operator+=(const complex2 &other)
Definition: complex8x2simd.hpp:49
complex2 operator*(const float &rhs) const
Definition: complex8x2simd.hpp:75
std::complex< float > c(const size_t &i) const
Definition: complex8x2simd.hpp:47
complex2 operator-() const
Definition: complex8x2simd.hpp:76
complex2 operator*=(const float &other)
Definition: complex8x2simd.hpp:77
complex2 operator+(const complex2 &other) const
Definition: complex8x2simd.hpp:48
complex2 operator-=(const complex2 &other)
Definition: complex8x2simd.hpp:55