Line | Branch | Decision | Exec | Source |
---|---|---|---|---|
1 | // Copyright 2019-2022 Cambridge Quantum Computing | |||
2 | // | |||
3 | // Licensed under the Apache License, Version 2.0 (the "License"); | |||
4 | // you may not use this file except in compliance with the License. | |||
5 | // You may obtain a copy of the License at | |||
6 | // | |||
7 | // http://www.apache.org/licenses/LICENSE-2.0 | |||
8 | // | |||
9 | // Unless required by applicable law or agreed to in writing, software | |||
10 | // distributed under the License is distributed on an "AS IS" BASIS, | |||
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
12 | // See the License for the specific language governing permissions and | |||
13 | // limitations under the License. | |||
14 | ||||
15 | #include "Rotation.hpp" | |||
16 | ||||
17 | #include "OpType/OpDesc.hpp" | |||
18 | #include "OpType/OpType.hpp" | |||
19 | #include "Utils/Expression.hpp" | |||
20 | #include "Utils/Symbols.hpp" | |||
21 | #include "symengine/constants.h" | |||
22 | ||||
23 | namespace tket { | |||
24 | ||||
25 | 5966 | static Expr atan2_bypi(const Expr &a, const Expr &b) { | ||
26 |
1/2✓ Branch 1 taken 5966 times.
✗ Branch 2 not taken.
|
5966 | std::optional<double> va = eval_expr(a); | |
27 |
1/2✓ Branch 1 taken 5966 times.
✗ Branch 2 not taken.
|
5966 | std::optional<double> vb = eval_expr(b); | |
28 |
6/6✓ Branch 1 taken 5915 times.
✓ Branch 2 taken 51 times.
✓ Branch 4 taken 5914 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 5914 times.
✓ Branch 7 taken 52 times.
|
2/2✓ Decision 'true' taken 5914 times.
✓ Decision 'false' taken 52 times.
|
5966 | if (va && vb) { |
29 |
1/2✓ Branch 1 taken 5914 times.
✗ Branch 2 not taken.
|
5914 | double vva = va.value(); | |
30 |
1/2✓ Branch 1 taken 5914 times.
✗ Branch 2 not taken.
|
5914 | double vvb = vb.value(); | |
31 |
4/8✓ Branch 1 taken 46 times.
✓ Branch 2 taken 5868 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 46 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 5914 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
|
1/2✓ Decision 'true' taken 5914 times.
✗ Decision 'false' not taken.
|
5914 | if (std::abs(vva) < EPS && std::abs(vvb) < EPS) return Expr(0.); |
32 |
1/2✓ Branch 1 taken 5914 times.
✗ Branch 2 not taken.
|
5914 | return atan2(vva, vvb) / PI; | |
33 | } else { | |||
34 | // Convert symbolic zero to 0. This is a workaround for | |||
35 | // https://github.com/symengine/symengine/issues/1875 . | |||
36 |
2/4✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 52 times.
✗ Branch 5 not taken.
|
52 | Expr a1 = a, b1 = b; | |
37 |
5/8✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 52 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 51 times.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
|
1/2✓ Decision 'true' taken 52 times.
✗ Decision 'false' not taken.
|
52 | if (a1 == SymEngine::zero) a1 = 0.; |
38 |
3/8✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 52 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 52 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
0/1? Decision couldn't be analyzed.
|
52 | if (b1 == SymEngine::zero) b1 = 0.; |
39 |
4/8✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 52 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 52 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 52 times.
✗ Branch 13 not taken.
|
104 | return SymEngine::div(SymEngine::atan2(a1, b1), SymEngine::pi); | |
40 | 52 | } | ||
41 | } | |||
42 | ||||
43 | 741 | static Expr acos_bypi(const Expr &a) { | ||
44 |
1/2✓ Branch 1 taken 741 times.
✗ Branch 2 not taken.
|
741 | std::optional<double> va = eval_expr(a); | |
45 |
2/2✓ Branch 1 taken 731 times.
✓ Branch 2 taken 10 times.
|
2/2✓ Decision 'true' taken 731 times.
✓ Decision 'false' taken 10 times.
|
741 | if (va) { |
46 |
1/2✓ Branch 1 taken 731 times.
✗ Branch 2 not taken.
|
731 | double vva = va.value(); | |
47 | // avoid undefined values due to rounding | |||
48 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 731 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
1/2✓ Decision 'true' taken 731 times.
✗ Decision 'false' not taken.
|
731 | if (vva >= 1.) return 0.; |
49 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 731 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
1/2✓ Decision 'true' taken 731 times.
✗ Decision 'false' not taken.
|
731 | if (vva <= -1.) return 1.; |
50 |
1/2✓ Branch 1 taken 731 times.
✗ Branch 2 not taken.
|
731 | return acos(vva) / PI; | |
51 | } else { | |||
52 |
4/8✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 10 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 10 times.
✗ Branch 12 not taken.
|
20 | return SymEngine::div(SymEngine::acos(a), SymEngine::pi); | |
53 | } | |||
54 | } | |||
55 | ||||
56 | // SymEngine::div does not always spot when the numerator is a scalar multiple | |||
57 | // of the denominator, for example in expressions like (-a + b) / (a - b) where | |||
58 | // a and b are symbolic. This function picks out the common cases. | |||
59 | 1150 | static Expr expr_div(const Expr &num, const Expr &den) { | ||
60 |
4/6✓ Branch 2 taken 1150 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1150 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 504 times.
✓ Branch 10 taken 646 times.
|
2/2✓ Decision 'true' taken 646 times.
✓ Decision 'false' taken 504 times.
|
1150 | if (approx_0(SymEngine::expand(num - den))) return 1; |
61 |
4/6✓ Branch 2 taken 646 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 646 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 294 times.
✓ Branch 10 taken 352 times.
|
0/1? Decision couldn't be analyzed.
|
646 | if (approx_0(SymEngine::expand(num + den))) return -1; |
62 |
1/2✓ Branch 4 taken 352 times.
✗ Branch 5 not taken.
|
704 | return SymEngine::div(num, den); | |
63 | } | |||
64 | ||||
65 | 3600 | static std::tuple<Expr, Expr, Expr> xyx_angles_from_coeffs( | ||
66 | const Expr &s, const Expr &i, const Expr &j, const Expr &k) { | |||
67 | // Handle exceptional cases first. | |||
68 |
1/2✓ Branch 1 taken 3600 times.
✗ Branch 2 not taken.
|
3600 | bool s_zero = approx_0(s); | |
69 |
3/6✓ Branch 1 taken 3600 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3600 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3600 times.
✗ Branch 8 not taken.
|
3600 | bool s_one = approx_0(s - 1); | |
70 |
1/2✓ Branch 1 taken 3600 times.
✗ Branch 2 not taken.
|
3600 | bool i_zero = approx_0(i); | |
71 |
3/6✓ Branch 1 taken 3600 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3600 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3600 times.
✗ Branch 8 not taken.
|
3600 | bool i_one = approx_0(i - 1); | |
72 |
1/2✓ Branch 1 taken 3600 times.
✗ Branch 2 not taken.
|
3600 | bool j_zero = approx_0(j); | |
73 |
3/6✓ Branch 1 taken 3600 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3600 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3600 times.
✗ Branch 8 not taken.
|
3600 | bool j_one = approx_0(j - 1); | |
74 |
1/2✓ Branch 1 taken 3600 times.
✗ Branch 2 not taken.
|
3600 | bool k_zero = approx_0(k); | |
75 |
3/6✓ Branch 1 taken 3600 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3600 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3600 times.
✗ Branch 8 not taken.
|
3600 | bool k_one = approx_0(k - 1); | |
76 |
5/6✓ Branch 0 taken 503 times.
✓ Branch 1 taken 3097 times.
✓ Branch 2 taken 358 times.
✓ Branch 3 taken 145 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 358 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 3600 times.
|
3600 | if (i_zero && j_zero && k_zero) { |
77 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if (s_one) | |
78 | ✗ | return {0, 0, 0}; | ||
79 | else | |||
80 | ✗ | return {2, 0, 0}; | ||
81 | } | |||
82 |
5/6✓ Branch 0 taken 1398 times.
✓ Branch 1 taken 2202 times.
✓ Branch 2 taken 268 times.
✓ Branch 3 taken 1130 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 268 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 3600 times.
|
3600 | if (s_zero && j_zero && k_zero) { |
83 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if (i_one) | |
84 | ✗ | return {1, 0, 0}; | ||
85 | else | |||
86 | ✗ | return {3, 0, 0}; | ||
87 | } | |||
88 |
5/6✓ Branch 0 taken 1398 times.
✓ Branch 1 taken 2202 times.
✓ Branch 2 taken 152 times.
✓ Branch 3 taken 1246 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 152 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 3600 times.
|
3600 | if (s_zero && i_zero && k_zero) { |
89 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if (j_one) | |
90 | ✗ | return {0, 1, 0}; | ||
91 | else | |||
92 | ✗ | return {0, 3, 0}; | ||
93 | } | |||
94 |
6/6✓ Branch 0 taken 1398 times.
✓ Branch 1 taken 2202 times.
✓ Branch 2 taken 152 times.
✓ Branch 3 taken 1246 times.
✓ Branch 4 taken 43 times.
✓ Branch 5 taken 109 times.
|
2/2✓ Decision 'true' taken 43 times.
✓ Decision 'false' taken 3557 times.
|
3600 | if (s_zero && i_zero && j_zero) { |
95 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 27 times.
|
2/2✓ Decision 'true' taken 32 times.
✓ Decision 'false' taken 11 times.
|
43 | if (k_one) |
96 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
32 | return {3, 1, 0}; | |
97 | else | |||
98 |
1/2✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
|
54 | return {1, 1, 0}; | |
99 | } | |||
100 |
8/12✓ Branch 0 taken 1355 times.
✓ Branch 1 taken 2202 times.
✓ Branch 2 taken 109 times.
✓ Branch 3 taken 1246 times.
✓ Branch 5 taken 109 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 109 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 109 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 109 times.
✗ Branch 15 not taken.
|
0/1? Decision couldn't be analyzed.
|
3666 | if (s_zero && i_zero) return {-2 * atan2_bypi(k, j), 1, 0}; |
101 |
8/12✓ Branch 0 taken 1246 times.
✓ Branch 1 taken 2202 times.
✓ Branch 2 taken 225 times.
✓ Branch 3 taken 1021 times.
✓ Branch 5 taken 225 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 225 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 225 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 225 times.
✗ Branch 15 not taken.
|
0/1? Decision couldn't be analyzed.
|
3673 | if (s_zero && j_zero) return {0, 2 * atan2_bypi(k, i), 1}; |
102 |
8/12✓ Branch 0 taken 1021 times.
✓ Branch 1 taken 2202 times.
✓ Branch 2 taken 1017 times.
✓ Branch 3 taken 4 times.
✓ Branch 5 taken 1017 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1017 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 1017 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 1017 times.
✗ Branch 15 not taken.
|
2/2✓ Decision 'true' taken 2521 times.
✓ Decision 'false' taken 1719 times.
|
4240 | if (s_zero && k_zero) return {0.5, 2 * atan2_bypi(j, i), 0.5}; |
103 |
8/12✓ Branch 0 taken 351 times.
✓ Branch 1 taken 1855 times.
✓ Branch 2 taken 315 times.
✓ Branch 3 taken 36 times.
✓ Branch 5 taken 315 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 315 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 315 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 315 times.
✗ Branch 15 not taken.
|
2/2✓ Decision 'true' taken 1891 times.
✓ Decision 'false' taken 630 times.
|
2521 | if (i_zero && j_zero) return {-0.5, 2 * atan2_bypi(k, s), 0.5}; |
104 |
3/12✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1855 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 36 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
1/2✓ Decision 'true' taken 1891 times.
✗ Decision 'false' not taken.
|
1891 | if (i_zero && k_zero) return {0, 2 * atan2_bypi(j, s), 0}; |
105 |
3/12✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1885 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
1/2✓ Decision 'true' taken 1891 times.
✗ Decision 'false' not taken.
|
1891 | if (j_zero && k_zero) return {2 * atan2_bypi(i, s), 0, 0}; |
106 | ||||
107 | // This is a (partial) workaround for | |||
108 | // https://github.com/symengine/symengine/issues/1806 | |||
109 | // (since it avoids the use of atan2 with proportional symbolics). | |||
110 | // Explanation: When the quaternion is of the form | |||
111 | // A + uA i + B j -/+ uB k | |||
112 | // where u is a pure number (with no free symbols) but A and B are symbolic, | |||
113 | // symengine wrongly simplifies atan2(uA, A) and atan2(uB, B), ignoring the | |||
114 | // symbols (whose sign ought to affect the result). So the general formula | |||
115 | // below does not work. We therefore handle these cases differently, noting | |||
116 | // that the quaternion factorizes as either | |||
117 | // (A + Bj) (1 + ui) or (1 + ui) (A + Bj) | |||
118 | // -- that is, an Rx followed by an Ry or vice versa. | |||
119 | // We will analyse the first case; the second is similar. | |||
120 | // Let alpha = atan(u). Note that -pi/2 < alpha < pi/2, so cos(alpha) > 0. | |||
121 | // The quaternion is then | |||
122 | // (A/cos(alpha) + B/cos(alpha) j) (cos(alpha) + sin(alpha) i) | |||
123 | // So we can take the angle of the Rx as 2*alpha, and the angle of the Ry as | |||
124 | // 2 * atan2(B, A). | |||
125 | // Finally, note that u must be well-defined because we have already dealt | |||
126 | // with all cases where s = 0. | |||
127 |
7/12✓ Branch 1 taken 1891 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1891 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1891 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1891 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1891 times.
✗ Branch 14 not taken.
✓ Branch 19 taken 456 times.
✓ Branch 20 taken 1435 times.
|
2/2✓ Decision 'true' taken 456 times.
✓ Decision 'false' taken 1435 times.
|
1891 | if (approx_0(SymEngine::expand(i * j + s * k))) { |
128 |
1/2✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
|
456 | Expr u = expr_div(i, s); | |
129 |
3/6✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 456 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 456 times.
✗ Branch 9 not taken.
|
1/2✓ Decision 'true' taken 456 times.
✗ Decision 'false' not taken.
|
456 | if (SymEngine::free_symbols(u).empty()) { |
130 |
2/4✓ Branch 2 taken 456 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 456 times.
✗ Branch 6 not taken.
|
456 | Expr a = SymEngine::atan(u); | |
131 |
3/6✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 456 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 456 times.
✗ Branch 8 not taken.
|
912 | Expr q = 2 * atan2_bypi(j, s); | |
132 |
5/10✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 456 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 456 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 456 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 456 times.
✗ Branch 15 not taken.
|
912 | Expr two_a_by_pi = SymEngine::div(2 * a, SymEngine::pi); | |
133 |
1/2✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
|
456 | return std::tuple<Expr, Expr, Expr>(two_a_by_pi, q, 0); | |
134 | 456 | } | ||
135 |
8/14✗ Branch 1 not taken.
✓ Branch 2 taken 456 times.
✓ Branch 4 taken 1435 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1435 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1435 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1435 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1435 times.
✗ Branch 17 not taken.
✓ Branch 22 taken 694 times.
✓ Branch 23 taken 741 times.
|
2/2✓ Decision 'true' taken 694 times.
✓ Decision 'false' taken 1197 times.
|
1891 | } else if (approx_0(SymEngine::expand(i * j - s * k))) { |
136 |
1/2✓ Branch 1 taken 694 times.
✗ Branch 2 not taken.
|
694 | Expr u = expr_div(i, s); | |
137 |
3/6✓ Branch 1 taken 694 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 694 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 694 times.
✗ Branch 9 not taken.
|
1/2✓ Decision 'true' taken 694 times.
✗ Decision 'false' not taken.
|
694 | if (SymEngine::free_symbols(u).empty()) { |
138 |
2/4✓ Branch 2 taken 694 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 694 times.
✗ Branch 6 not taken.
|
694 | Expr a = SymEngine::atan(u); | |
139 |
3/6✓ Branch 1 taken 694 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 694 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 694 times.
✗ Branch 8 not taken.
|
1388 | Expr q = 2 * atan2_bypi(j, s); | |
140 |
5/10✓ Branch 1 taken 694 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 694 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 694 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 694 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 694 times.
✗ Branch 15 not taken.
|
1388 | Expr two_a_by_pi = SymEngine::div(2 * a, SymEngine::pi); | |
141 |
1/2✓ Branch 1 taken 694 times.
✗ Branch 2 not taken.
|
694 | return std::tuple<Expr, Expr, Expr>(0, q, two_a_by_pi); | |
142 | 694 | } | ||
143 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 694 times.
|
694 | } | |
144 | ||||
145 | // Now the general case. | |||
146 |
1/2✓ Branch 1 taken 741 times.
✗ Branch 2 not taken.
|
741 | Expr a = atan2_bypi(i, s); | |
147 |
1/2✓ Branch 1 taken 741 times.
✗ Branch 2 not taken.
|
741 | Expr b = atan2_bypi(k, j); | |
148 |
9/18✓ Branch 1 taken 741 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 741 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 741 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 741 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 741 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 741 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 741 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 741 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 741 times.
✗ Branch 26 not taken.
|
1482 | Expr q = acos_bypi(SymEngine::expand(s * s + i * i - j * j - k * k)); | |
149 |
3/6✓ Branch 1 taken 741 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 741 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 741 times.
✗ Branch 8 not taken.
|
1482 | return std::tuple<Expr, Expr, Expr>(a - b, q, a + b); | |
150 | 741 | } | ||
151 | ||||
152 | 188902 | Rotation::Rotation(OpType optype, Expr a) | ||
153 |
4/8✓ Branch 2 taken 188902 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 188902 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 188902 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 188902 times.
✗ Branch 12 not taken.
|
188902 | : i_(0), j_(0), k_(0), optype_(optype), a_(a) { | |
154 |
3/4✓ Branch 1 taken 188902 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 81264 times.
✓ Branch 4 taken 107638 times.
|
2/2✓ Decision 'true' taken 81264 times.
✓ Decision 'false' taken 107638 times.
|
188902 | if (equiv_0(a, 4)) { |
155 | 81264 | rep_ = Rep::id; | ||
156 |
1/2✓ Branch 1 taken 81264 times.
✗ Branch 2 not taken.
|
81264 | s_ = 1; | |
157 |
3/6✓ Branch 1 taken 81264 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 81264 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 81264 times.
✗ Branch 9 not taken.
|
81264 | i_ = j_ = k_ = 0; | |
158 |
5/8✓ Branch 1 taken 107638 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 107638 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 107638 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 634 times.
✓ Branch 12 taken 107004 times.
|
2/2✓ Decision 'true' taken 634 times.
✓ Decision 'false' taken 107004 times.
|
107638 | } else if (equiv_0(a - 2, 4)) { |
159 | 634 | rep_ = Rep::minus_id; | ||
160 |
1/2✓ Branch 1 taken 634 times.
✗ Branch 2 not taken.
|
634 | s_ = -1; | |
161 |
3/6✓ Branch 1 taken 634 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 634 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 634 times.
✗ Branch 9 not taken.
|
634 | i_ = j_ = k_ = 0; | |
162 | } else { | |||
163 | 107004 | rep_ = Rep::orth_rot; | ||
164 |
1/2✓ Branch 1 taken 107004 times.
✗ Branch 2 not taken.
|
107004 | s_ = cos_halfpi_times(a); | |
165 |
1/2✓ Branch 1 taken 107004 times.
✗ Branch 2 not taken.
|
107004 | Expr t = sin_halfpi_times(a); | |
166 |
3/4✓ Branch 0 taken 13945 times.
✓ Branch 1 taken 23220 times.
✓ Branch 2 taken 69839 times.
✗ Branch 3 not taken.
|
107004 | switch (optype) { | |
167 |
1/1✓ Decision 'true' taken 13945 times.
|
13945 | case OpType::Rx: | |
168 |
1/2✓ Branch 1 taken 13945 times.
✗ Branch 2 not taken.
|
13945 | i_ = t; | |
169 | 13945 | break; | ||
170 |
1/1✓ Decision 'true' taken 23220 times.
|
23220 | case OpType::Ry: | |
171 |
1/2✓ Branch 1 taken 23220 times.
✗ Branch 2 not taken.
|
23220 | j_ = t; | |
172 | 23220 | break; | ||
173 |
1/1✓ Decision 'true' taken 69839 times.
|
69839 | case OpType::Rz: | |
174 |
1/2✓ Branch 1 taken 69839 times.
✗ Branch 2 not taken.
|
69839 | k_ = t; | |
175 | 69839 | break; | ||
176 |
0/1✗ Decision 'true' not taken.
|
✗ | default: | |
177 | ✗ | throw std::logic_error( | ||
178 | "Quaternions can only be constructed " | |||
179 | ✗ | "from Rx, Ry or Rz rotations"); | ||
180 | } | |||
181 | 107004 | } | ||
182 | 188902 | } | ||
183 | ||||
184 | 64404 | std::optional<Expr> Rotation::angle(OpType optype) const { | ||
185 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 64404 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 64404 times.
|
64404 | if (rep_ == Rep::id) { |
186 | ✗ | return Expr(0); | ||
187 |
2/2✓ Branch 0 taken 697 times.
✓ Branch 1 taken 63707 times.
|
2/2✓ Decision 'true' taken 697 times.
✓ Decision 'false' taken 63707 times.
|
64404 | } else if (rep_ == Rep::minus_id) { |
188 | 697 | return Expr(2); | ||
189 |
3/4✓ Branch 0 taken 63707 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48823 times.
✓ Branch 3 taken 14884 times.
|
2/2✓ Decision 'true' taken 48823 times.
✓ Decision 'false' taken 14884 times.
|
63707 | } else if (rep_ == Rep::orth_rot && optype_ == optype) { |
190 | 48823 | return a_; | ||
191 | } else { | |||
192 | 14884 | return std::nullopt; | ||
193 | } | |||
194 | } | |||
195 | ||||
196 | 37351 | std::tuple<Expr, Expr, Expr> Rotation::to_pqp(OpType p, OpType q) const { | ||
197 |
2/2✓ Branch 0 taken 9791 times.
✓ Branch 1 taken 27560 times.
|
2/2✓ Decision 'true' taken 9791 times.
✓ Decision 'false' taken 27560 times.
|
37351 | if (rep_ == Rep::id) { |
198 |
2/4✓ Branch 2 taken 9791 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 9791 times.
✗ Branch 6 not taken.
|
9791 | return {Expr(0), Expr(0), Expr(0)}; | |
199 |
2/2✓ Branch 0 taken 137 times.
✓ Branch 1 taken 27423 times.
|
2/2✓ Decision 'true' taken 137 times.
✓ Decision 'false' taken 27423 times.
|
27560 | } else if (rep_ == Rep::minus_id) { |
200 |
2/4✓ Branch 2 taken 137 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 137 times.
✗ Branch 6 not taken.
|
137 | return {Expr(2), Expr(0), Expr(0)}; | |
201 |
2/2✓ Branch 0 taken 24181 times.
✓ Branch 1 taken 3242 times.
|
2/2✓ Decision 'true' taken 24181 times.
✓ Decision 'false' taken 3242 times.
|
27423 | } else if (rep_ == Rep::orth_rot) { |
202 |
2/2✓ Branch 0 taken 370 times.
✓ Branch 1 taken 23811 times.
|
2/2✓ Decision 'true' taken 740 times.
✓ Decision 'false' taken 23441 times.
|
24181 | if (optype_ == p) { |
203 |
2/4✓ Branch 2 taken 370 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 370 times.
✗ Branch 6 not taken.
|
740 | return {a_, Expr(0), Expr(0)}; | |
204 |
2/2✓ Branch 0 taken 23453 times.
✓ Branch 1 taken 358 times.
|
0/1? Decision couldn't be analyzed.
|
23811 | } else if (optype_ == q) { |
205 |
2/4✓ Branch 2 taken 23453 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 23453 times.
✗ Branch 6 not taken.
|
46906 | return {Expr(0), a_, Expr(0)}; | |
206 | } | |||
207 | } | |||
208 |
3/4✓ Branch 0 taken 50 times.
✓ Branch 1 taken 3550 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 50 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 3600 times.
|
3600 | if (p == OpType::Rx && q == OpType::Ry) { |
209 | ✗ | return xyx_angles_from_coeffs(s_, i_, j_, k_); | ||
210 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3599 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 3600 times.
|
3600 | } else if (p == OpType::Ry && q == OpType::Rx) { |
211 | ✗ | return xyx_angles_from_coeffs(s_, j_, i_, -k_); | ||
212 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3599 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
2/2✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 3599 times.
|
3600 | } else if (p == OpType::Ry && q == OpType::Rz) { |
213 | 1 | return xyx_angles_from_coeffs(s_, j_, k_, i_); | ||
214 |
4/4✓ Branch 0 taken 3549 times.
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 3364 times.
✓ Branch 3 taken 185 times.
|
0/1? Decision couldn't be analyzed.
|
3599 | } else if (p == OpType::Rz && q == OpType::Ry) { |
215 |
1/2✓ Branch 2 taken 3364 times.
✗ Branch 3 not taken.
|
6728 | return xyx_angles_from_coeffs(s_, k_, j_, -i_); | |
216 |
3/4✓ Branch 0 taken 185 times.
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 185 times.
✗ Branch 3 not taken.
|
2/2✓ Decision 'true' taken 185 times.
✓ Decision 'false' taken 50 times.
|
235 | } else if (p == OpType::Rz && q == OpType::Rx) { |
217 | 185 | return xyx_angles_from_coeffs(s_, k_, i_, j_); | ||
218 |
2/4✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 50 times.
✗ Branch 3 not taken.
|
0/1? Decision couldn't be analyzed.
|
50 | } else if (p == OpType::Rx && q == OpType::Rz) { |
219 |
1/2✓ Branch 2 taken 50 times.
✗ Branch 3 not taken.
|
100 | return xyx_angles_from_coeffs(s_, i_, k_, -j_); | |
220 | } else { | |||
221 | ✗ | throw std::logic_error("Axes must be a pair of X, Y, Z."); | ||
222 | } | |||
223 | } | |||
224 | ||||
225 | // Table of compositions | |||
226 | static const std::map< | |||
227 | std::tuple<OpType, int, OpType, int>, std::pair<OpType, int>> | |||
228 | product = { | |||
229 | {{OpType::Rx, +1, OpType::Ry, +1}, {OpType::Rz, -1}}, | |||
230 | {{OpType::Rx, +1, OpType::Rz, +1}, {OpType::Ry, +1}}, | |||
231 | {{OpType::Rx, +1, OpType::Ry, -1}, {OpType::Rz, +1}}, | |||
232 | {{OpType::Rx, +1, OpType::Rz, -1}, {OpType::Ry, -1}}, | |||
233 | {{OpType::Rx, -1, OpType::Ry, +1}, {OpType::Rz, +1}}, | |||
234 | {{OpType::Rx, -1, OpType::Rz, +1}, {OpType::Ry, -1}}, | |||
235 | {{OpType::Rx, -1, OpType::Ry, -1}, {OpType::Rz, -1}}, | |||
236 | {{OpType::Rx, -1, OpType::Rz, -1}, {OpType::Ry, +1}}, | |||
237 | {{OpType::Ry, +1, OpType::Rz, +1}, {OpType::Rx, -1}}, | |||
238 | {{OpType::Ry, +1, OpType::Rx, +1}, {OpType::Rz, +1}}, | |||
239 | {{OpType::Ry, +1, OpType::Rz, -1}, {OpType::Rx, +1}}, | |||
240 | {{OpType::Ry, +1, OpType::Rx, -1}, {OpType::Rz, -1}}, | |||
241 | {{OpType::Ry, -1, OpType::Rz, +1}, {OpType::Rx, +1}}, | |||
242 | {{OpType::Ry, -1, OpType::Rx, +1}, {OpType::Rz, -1}}, | |||
243 | {{OpType::Ry, -1, OpType::Rz, -1}, {OpType::Rx, -1}}, | |||
244 | {{OpType::Ry, -1, OpType::Rx, -1}, {OpType::Rz, +1}}, | |||
245 | {{OpType::Rz, +1, OpType::Rx, +1}, {OpType::Ry, -1}}, | |||
246 | {{OpType::Rz, +1, OpType::Ry, +1}, {OpType::Rx, +1}}, | |||
247 | {{OpType::Rz, +1, OpType::Rx, -1}, {OpType::Ry, +1}}, | |||
248 | {{OpType::Rz, +1, OpType::Ry, -1}, {OpType::Rx, -1}}, | |||
249 | {{OpType::Rz, -1, OpType::Rx, +1}, {OpType::Ry, +1}}, | |||
250 | {{OpType::Rz, -1, OpType::Ry, +1}, {OpType::Rx, -1}}, | |||
251 | {{OpType::Rz, -1, OpType::Rx, -1}, {OpType::Ry, -1}}, | |||
252 | {{OpType::Rz, -1, OpType::Ry, -1}, {OpType::Rx, +1}}, | |||
253 | }; | |||
254 | ||||
255 | 55248 | void Rotation::apply(const Rotation &other) { | ||
256 |
2/2✓ Branch 0 taken 583 times.
✓ Branch 1 taken 54665 times.
|
2/2✓ Decision 'true' taken 54665 times.
✓ Decision 'false' taken 28551 times.
|
83216 | if (other.rep_ == Rep::id) return; |
257 | ||||
258 |
2/2✓ Branch 0 taken 27625 times.
✓ Branch 1 taken 27040 times.
|
2/2✓ Decision 'true' taken 27625 times.
✓ Decision 'false' taken 27040 times.
|
54665 | if (rep_ == Rep::id) { |
259 | 27625 | rep_ = other.rep_; | ||
260 |
1/2✓ Branch 1 taken 27625 times.
✗ Branch 2 not taken.
|
27625 | s_ = other.s_; | |
261 |
1/2✓ Branch 1 taken 27625 times.
✗ Branch 2 not taken.
|
27625 | i_ = other.i_; | |
262 |
1/2✓ Branch 1 taken 27625 times.
✗ Branch 2 not taken.
|
27625 | j_ = other.j_; | |
263 |
1/2✓ Branch 1 taken 27625 times.
✗ Branch 2 not taken.
|
27625 | k_ = other.k_; | |
264 | 27625 | optype_ = other.optype_; | ||
265 |
1/2✓ Branch 1 taken 27625 times.
✗ Branch 2 not taken.
|
27625 | a_ = other.a_; | |
266 | 27625 | return; | ||
267 | } | |||
268 | ||||
269 |
2/2✓ Branch 0 taken 343 times.
✓ Branch 1 taken 26697 times.
|
2/2✓ Decision 'true' taken 343 times.
✓ Decision 'false' taken 26697 times.
|
27040 | if (rep_ == Rep::minus_id) { |
270 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 338 times.
|
2/2✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 338 times.
|
343 | if (other.rep_ == Rep::minus_id) { |
271 | 5 | rep_ = Rep::id; | ||
272 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | s_ = 1; | |
273 |
3/6✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 5 times.
✗ Branch 9 not taken.
|
5 | i_ = j_ = k_ = 0; | |
274 |
1/2✓ Branch 0 taken 338 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 338 times.
✗ Decision 'false' not taken.
|
338 | } else if (other.rep_ == Rep::orth_rot) { |
275 | 338 | rep_ = Rep::orth_rot; | ||
276 | 338 | optype_ = other.optype_; | ||
277 |
2/4✓ Branch 1 taken 338 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 338 times.
✗ Branch 5 not taken.
|
338 | a_ = other.a_ + 2; | |
278 |
1/2✓ Branch 1 taken 338 times.
✗ Branch 2 not taken.
|
338 | s_ = -other.s_; | |
279 |
1/2✓ Branch 1 taken 338 times.
✗ Branch 2 not taken.
|
338 | i_ = -other.i_; | |
280 |
2/4✓ Branch 1 taken 338 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 338 times.
✗ Branch 6 not taken.
|
338 | j_ = -other.j_, k_ = -other.k_; | |
281 | } else { | |||
282 | ✗ | rep_ = Rep::quat; | ||
283 | ✗ | s_ = -other.s_; | ||
284 | ✗ | i_ = -other.i_; | ||
285 | ✗ | j_ = -other.j_, k_ = -other.k_; | ||
286 | } | |||
287 | 343 | return; | ||
288 | } | |||
289 | ||||
290 |
4/4✓ Branch 0 taken 19205 times.
✓ Branch 1 taken 7492 times.
✓ Branch 2 taken 19112 times.
✓ Branch 3 taken 93 times.
|
2/2✓ Decision 'true' taken 19112 times.
✓ Decision 'false' taken 7585 times.
|
26697 | if (rep_ == Rep::orth_rot && other.rep_ == Rep::orth_rot) { |
291 |
2/2✓ Branch 0 taken 14096 times.
✓ Branch 1 taken 5016 times.
|
2/2✓ Decision 'true' taken 14096 times.
✓ Decision 'false' taken 5016 times.
|
19112 | if (optype_ == other.optype_) { |
292 |
1/2✓ Branch 1 taken 14096 times.
✗ Branch 2 not taken.
|
14096 | a_ += other.a_; | |
293 |
3/4✓ Branch 1 taken 14096 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3513 times.
✓ Branch 4 taken 10583 times.
|
2/2✓ Decision 'true' taken 3513 times.
✓ Decision 'false' taken 10583 times.
|
14096 | if (equiv_0(a_, 4)) { |
294 | 3513 | rep_ = Rep::id; | ||
295 |
3/4✓ Branch 1 taken 10583 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 854 times.
✓ Branch 4 taken 9729 times.
|
2/2✓ Decision 'true' taken 854 times.
✓ Decision 'false' taken 9729 times.
|
10583 | } else if (equiv_0(a_, 2)) { |
296 | 854 | rep_ = Rep::minus_id; | ||
297 | } | |||
298 | 5016 | } else if ( | ||
299 |
8/10✓ Branch 1 taken 5016 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4811 times.
✓ Branch 4 taken 205 times.
✓ Branch 6 taken 4811 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 756 times.
✓ Branch 9 taken 4055 times.
✓ Branch 10 taken 199 times.
✓ Branch 11 taken 4817 times.
|
5977 | (equiv_val(a_, 1., 4) || equiv_val(a_, -1., 4)) && | |
300 |
6/8✓ Branch 1 taken 961 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 949 times.
✓ Branch 4 taken 12 times.
✓ Branch 6 taken 949 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 187 times.
✓ Branch 9 taken 762 times.
|
961 | (equiv_val(other.a_, 1., 4) || equiv_val(other.a_, -1., 4))) { | |
301 | // We are in a subgroup of order 8 | |||
302 |
3/4✓ Branch 1 taken 199 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 181 times.
|
199 | int m0 = equiv_val(a_, 1., 4) ? 1 : -1; | |
303 |
3/4✓ Branch 1 taken 199 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 187 times.
|
199 | int m1 = equiv_val(other.a_, 1., 4) ? 1 : -1; | |
304 |
2/4✓ Branch 2 taken 199 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 199 times.
✗ Branch 7 not taken.
|
199 | std::tie(optype_, a_) = product.at({optype_, m0, other.optype_, m1}); | |
305 | } else | |||
306 | 4817 | rep_ = Rep::quat; | ||
307 | 19112 | } else | ||
308 | 7585 | rep_ = Rep::quat; | ||
309 | ||||
310 |
7/14✓ Branch 1 taken 26697 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 26697 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 26697 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 26697 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 26697 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 26697 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 26697 times.
✗ Branch 20 not taken.
|
53394 | Expr s1 = other.s_ * s_ - other.i_ * i_ - other.j_ * j_ - other.k_ * k_; | |
311 |
7/14✓ Branch 1 taken 26697 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 26697 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 26697 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 26697 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 26697 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 26697 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 26697 times.
✗ Branch 20 not taken.
|
53394 | Expr i1 = other.s_ * i_ + other.i_ * s_ + other.j_ * k_ - other.k_ * j_; | |
312 |
7/14✓ Branch 1 taken 26697 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 26697 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 26697 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 26697 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 26697 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 26697 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 26697 times.
✗ Branch 20 not taken.
|
53394 | Expr j1 = other.s_ * j_ - other.i_ * k_ + other.j_ * s_ + other.k_ * i_; | |
313 |
7/14✓ Branch 1 taken 26697 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 26697 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 26697 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 26697 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 26697 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 26697 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 26697 times.
✗ Branch 20 not taken.
|
53394 | Expr k1 = other.s_ * k_ + other.i_ * j_ - other.j_ * i_ + other.k_ * s_; | |
314 |
1/2✓ Branch 1 taken 26697 times.
✗ Branch 2 not taken.
|
26697 | s_ = SymEngine::expand(s1); | |
315 |
1/2✓ Branch 1 taken 26697 times.
✗ Branch 2 not taken.
|
26697 | i_ = SymEngine::expand(i1); | |
316 |
1/2✓ Branch 1 taken 26697 times.
✗ Branch 2 not taken.
|
26697 | j_ = SymEngine::expand(j1); | |
317 |
1/2✓ Branch 1 taken 26697 times.
✗ Branch 2 not taken.
|
26697 | k_ = SymEngine::expand(k1); | |
318 | ||||
319 |
2/2✓ Branch 0 taken 12402 times.
✓ Branch 1 taken 14295 times.
|
2/2✓ Decision 'true' taken 12402 times.
✓ Decision 'false' taken 14295 times.
|
26697 | if (rep_ == Rep::quat) { |
320 | // See if we can simplify the representation. | |||
321 |
1/2✓ Branch 1 taken 12402 times.
✗ Branch 2 not taken.
|
12402 | bool i_zero = approx_0(i_); | |
322 |
1/2✓ Branch 1 taken 12402 times.
✗ Branch 2 not taken.
|
12402 | bool j_zero = approx_0(j_); | |
323 |
1/2✓ Branch 1 taken 12402 times.
✗ Branch 2 not taken.
|
12402 | bool k_zero = approx_0(k_); | |
324 |
5/6✓ Branch 0 taken 2347 times.
✓ Branch 1 taken 10055 times.
✓ Branch 2 taken 491 times.
✓ Branch 3 taken 1856 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 491 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 12402 times.
|
12402 | if (i_zero && j_zero && k_zero) { |
325 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if (approx_0(s_ - 1)) { | |
326 | ✗ | rep_ = Rep::id; | ||
327 | ✗ | s_ = 1; | ||
328 | ✗ | i_ = j_ = k_ = 0; | ||
329 | } else { | |||
330 | ✗ | rep_ = Rep::minus_id; | ||
331 | ✗ | s_ = -1; | ||
332 | ✗ | i_ = j_ = k_ = 0; | ||
333 | } | |||
334 |
4/4✓ Branch 0 taken 2282 times.
✓ Branch 1 taken 10120 times.
✓ Branch 2 taken 804 times.
✓ Branch 3 taken 1478 times.
|
2/2✓ Decision 'true' taken 804 times.
✓ Decision 'false' taken 11598 times.
|
12402 | } else if (j_zero && k_zero) { |
335 | 804 | rep_ = Rep::orth_rot; | ||
336 | 804 | optype_ = OpType::Rx; | ||
337 |
3/6✓ Branch 1 taken 804 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 804 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 804 times.
✗ Branch 8 not taken.
|
804 | a_ = 2 * atan2_bypi(i_, s_); | |
338 |
2/4✓ Branch 1 taken 804 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 804 times.
✗ Branch 6 not taken.
|
804 | j_ = k_ = 0; | |
339 |
4/4✓ Branch 0 taken 1462 times.
✓ Branch 1 taken 10136 times.
✓ Branch 2 taken 373 times.
✓ Branch 3 taken 1089 times.
|
2/2✓ Decision 'true' taken 373 times.
✓ Decision 'false' taken 11225 times.
|
11598 | } else if (k_zero && i_zero) { |
340 | 373 | rep_ = Rep::orth_rot; | ||
341 | 373 | optype_ = OpType::Ry; | ||
342 |
3/6✓ Branch 1 taken 373 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 373 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 373 times.
✗ Branch 8 not taken.
|
373 | a_ = 2 * atan2_bypi(j_, s_); | |
343 |
2/4✓ Branch 1 taken 373 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 373 times.
✗ Branch 6 not taken.
|
373 | k_ = i_ = 0; | |
344 |
4/4✓ Branch 0 taken 1974 times.
✓ Branch 1 taken 9251 times.
✓ Branch 2 taken 491 times.
✓ Branch 3 taken 1483 times.
|
2/2✓ Decision 'true' taken 491 times.
✓ Decision 'false' taken 10734 times.
|
11225 | } else if (i_zero && j_zero) { |
345 | 491 | rep_ = Rep::orth_rot; | ||
346 | 491 | optype_ = OpType::Rz; | ||
347 |
3/6✓ Branch 1 taken 491 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 491 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 491 times.
✗ Branch 8 not taken.
|
491 | a_ = 2 * atan2_bypi(k_, s_); | |
348 |
2/4✓ Branch 1 taken 491 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 491 times.
✗ Branch 6 not taken.
|
491 | i_ = j_ = 0; | |
349 | } | |||
350 | } | |||
351 | 26697 | } | ||
352 | ||||
353 | ✗ | std::ostream &operator<<(std::ostream &os, const Rotation &q) { | ||
354 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if (q.rep_ == Rotation::Rep::id) { | |
355 | ✗ | return os << "I"; | ||
356 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | } else if (q.rep_ == Rotation::Rep::minus_id) { | |
357 | ✗ | return os << "-I"; | ||
358 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | } else if (q.rep_ == Rotation::Rep::orth_rot) { | |
359 | ✗ | return os << OpDesc(q.optype_).name() << "(" << q.a_ << ")"; | ||
360 | } else { | |||
361 | ✗ | return os << q.s_ << " + " << q.i_ << " i + " << q.j_ << " j + " << q.k_ | ||
362 | ✗ | << " k"; | ||
363 | } | |||
364 | } | |||
365 | ||||
366 | 15751 | std::vector<double> tk1_angles_from_unitary(const Eigen::Matrix2cd &U) { | ||
367 | // clang-format off | |||
368 | // | |||
369 | // Assume U = e^{i pi p} TK1(a,b,c) | |||
370 | // = e^{i pi p} Rz(a) Rx(b) Rz(c) | |||
371 | // | e^{-i pi (a+c)/2} cos(pi b/2) -i e^{-i pi (a-c)/2} sin(pi b/2) | | |||
372 | // = e^{i pi p} | | | |||
373 | // | -i e^{ i pi (a-c)/2} sin(pi b/2) e^{ i pi (a+c)/2} cos(pi b/2) | | |||
374 | // | |||
375 | // clang-format on | |||
376 | ||||
377 | double a, b, c, p; // to be found satisfying the above equation | |||
378 | ||||
379 |
3/6✓ Branch 1 taken 15751 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15751 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 15751 times.
✗ Branch 8 not taken.
|
15751 | std::complex s = 0.5 * (U(0, 0) + U(1, 1)); | |
380 |
4/8✓ Branch 1 taken 15751 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15751 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 15751 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 15751 times.
✗ Branch 12 not taken.
|
15751 | std::complex x = 0.5 * i_ * (U(1, 0) + U(0, 1)); | |
381 |
3/6✓ Branch 1 taken 15751 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15751 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 15751 times.
✗ Branch 8 not taken.
|
15751 | std::complex y = 0.5 * (U(1, 0) - U(0, 1)); | |
382 |
4/8✓ Branch 1 taken 15751 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15751 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 15751 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 15751 times.
✗ Branch 12 not taken.
|
15751 | std::complex z = 0.5 * i_ * (U(0, 0) - U(1, 1)); | |
383 | ||||
384 | // s = e^{i pi p} cos(pi b/2) cos(pi (a+c)/2) | |||
385 | // x = e^{i pi p} sin(pi b/2) cos(pi (a-c)/2) | |||
386 | // y = e^{i pi p} sin(pi b/2) sin(pi (a-c)/2) | |||
387 | // z = e^{i pi p} cos(pi b/2) sin(pi (a+c)/2) | |||
388 | ||||
389 | // s, x, y and z all have phase e^{i pi p}. Extract it from the one with | |||
390 | // largest absolute value, to minimize numerical instability. Note that | |||
391 | // there are two possible values (p and p+1), but the choice is w.l.o.g. | |||
392 | // because (p,b) --> (p+1,b+2) does not change the value of the unitary. | |||
393 | ||||
394 | 15751 | std::complex w = s; | ||
395 |
2/2✓ Branch 2 taken 5854 times.
✓ Branch 3 taken 9897 times.
|
1/2✓ Decision 'true' taken 15751 times.
✗ Decision 'false' not taken.
|
15751 | if (std::abs(x) > std::abs(w)) w = x; |
396 |
2/2✓ Branch 2 taken 3779 times.
✓ Branch 3 taken 11972 times.
|
1/2✓ Decision 'true' taken 15751 times.
✗ Decision 'false' not taken.
|
15751 | if (std::abs(y) > std::abs(w)) w = y; |
397 |
2/2✓ Branch 2 taken 2737 times.
✓ Branch 3 taken 13014 times.
|
1/2✓ Decision 'true' taken 15751 times.
✗ Decision 'false' not taken.
|
15751 | if (std::abs(z) > std::abs(w)) w = z; |
398 | 15751 | std::complex eip = w / std::abs(w); | ||
399 | ||||
400 | // eip = e^{i pi p} | |||
401 | 15751 | p = std::arg(eip) / PI; | ||
402 | ||||
403 | // Now we've got the phase, factor it out. | |||
404 | ||||
405 | 15751 | std::complex emip = std::conj(eip); | ||
406 |
1/2✓ Branch 1 taken 15751 times.
✗ Branch 2 not taken.
|
15751 | double s0 = std::real(emip * s); | |
407 |
1/2✓ Branch 1 taken 15751 times.
✗ Branch 2 not taken.
|
15751 | double x0 = std::real(emip * x); | |
408 |
1/2✓ Branch 1 taken 15751 times.
✗ Branch 2 not taken.
|
15751 | double y0 = std::real(emip * y); | |
409 |
1/2✓ Branch 1 taken 15751 times.
✗ Branch 2 not taken.
|
15751 | double z0 = std::real(emip * z); | |
410 | ||||
411 | // s0 = cos(pi b/2) cos(pi (a+c)/2) | |||
412 | // x0 = sin(pi b/2) cos(pi (a-c)/2) | |||
413 | // y0 = sin(pi b/2) sin(pi (a-c)/2) | |||
414 | // z0 = cos(pi b/2) sin(pi (a+c)/2) | |||
415 | ||||
416 | 15751 | std::complex u = {s0, z0}, v = {x0, y0}; | ||
417 | ||||
418 | // u = cos(pi b/2) e^{i pi (a+c)/2} | |||
419 | // v = sin(pi b/2) e^{i pi (a-c)/2} | |||
420 | // |u|^2 + |v|^2 = 1 | |||
421 | ||||
422 | // Note that (a,b) --> (a+2, b+2) does not change the value of the unitary, so | |||
423 | // we are free to choose either solution. | |||
424 | // | |||
425 | // We treat the two special cases u=0 and v=0 separately, then the general | |||
426 | // case. | |||
427 | ||||
428 |
2/2✓ Branch 1 taken 484 times.
✓ Branch 2 taken 15267 times.
|
2/2✓ Decision 'true' taken 484 times.
✓ Decision 'false' taken 15267 times.
|
15751 | if (std::abs(u) < EPS) { // special case, b = 1 or 3 |
429 | // v = +/- e^{i pi (a-c)/2} | |||
430 | ||||
431 | // We may as well choose c = 0. | |||
432 | 484 | c = 0; | ||
433 | ||||
434 | // Assume b=1 and compute a. | |||
435 | // (b'=3, a'=a+2) is the other possibility but the unitary is the same. | |||
436 | 484 | b = 1; | ||
437 | 484 | a = 2 * std::arg(v) / PI; | ||
438 |
2/2✓ Branch 1 taken 1573 times.
✓ Branch 2 taken 13694 times.
|
2/2✓ Decision 'true' taken 1573 times.
✓ Decision 'false' taken 13694 times.
|
15267 | } else if (std::abs(v) < EPS) { // special case, b = 0 or 2 |
439 | // u = e^{i pi (a+c)/2} | |||
440 | ||||
441 | // We may as well choose c = 0. | |||
442 | 1573 | c = 0; | ||
443 | ||||
444 | // Assume b=0 and compute a. | |||
445 | // (b'=2, a'=a+2) is the other possibility but the unitary is the same. | |||
446 | 1573 | b = 0; | ||
447 | 1573 | a = 2 * std::arg(u) / PI; | ||
448 | } else { // general case | |||
449 | // s0^2 + z0^2 - x0^2 - y0^2 = cos(pi b) | |||
450 | 13694 | double t = s0 * s0 + z0 * z0 - x0 * x0 - y0 * y0; | ||
451 | // Rounding errors may mean t is outside the domain of acos. Fix this. | |||
452 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13694 times.
|
1/2✓ Decision 'true' taken 13694 times.
✗ Decision 'false' not taken.
|
13694 | if (t > +1.) t = +1.; |
453 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13694 times.
|
1/2✓ Decision 'true' taken 13694 times.
✗ Decision 'false' not taken.
|
13694 | if (t < -1.) t = -1.; |
454 | 13694 | b = std::acos(t) / PI; | ||
455 | ||||
456 | // w.l.o.g. b is in the range (-1,+1). | |||
457 | 13694 | double ac0 = std::arg(u), ac1 = std::arg(v); | ||
458 | 13694 | a = (ac0 + ac1) / PI; | ||
459 | 13694 | c = (ac0 - ac1) / PI; | ||
460 | } | |||
461 | ||||
462 |
1/2✓ Branch 2 taken 15751 times.
✗ Branch 3 not taken.
|
15751 | return {a, b, c, p}; | |
463 | } | |||
464 | ||||
465 | 49017 | Eigen::Matrix2cd get_matrix_from_tk1_angles(std::vector<Expr> params) { | ||
466 |
2/4✓ Branch 2 taken 49017 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 49017 times.
✗ Branch 6 not taken.
|
49017 | double alpha = eval_expr(params[0]).value(); | |
467 |
2/4✓ Branch 2 taken 49017 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 49017 times.
✗ Branch 6 not taken.
|
49017 | double beta = eval_expr(params[1]).value(); | |
468 |
2/4✓ Branch 2 taken 49017 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 49017 times.
✗ Branch 6 not taken.
|
49017 | double gamma = eval_expr(params[2]).value(); | |
469 |
2/4✓ Branch 2 taken 49017 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 49017 times.
✗ Branch 6 not taken.
|
49017 | double t = eval_expr(params[3]).value(); | |
470 |
1/2✓ Branch 1 taken 49017 times.
✗ Branch 2 not taken.
|
49017 | Eigen::Matrix2cd m; | |
471 | 49017 | alpha *= PI; | ||
472 | 49017 | beta *= PI; | ||
473 | 49017 | gamma *= PI; | ||
474 | 49017 | t *= PI; | ||
475 | 49017 | double c = cos(0.5 * beta); | ||
476 | 49017 | double s = sin(0.5 * beta); | ||
477 |
1/2✓ Branch 5 taken 49017 times.
✗ Branch 6 not taken.
|
49017 | m << exp(-0.5 * i_ * (alpha + gamma)) * c, | |
478 |
2/4✓ Branch 5 taken 49017 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 49017 times.
✗ Branch 10 not taken.
|
49017 | -i_ * exp(0.5 * i_ * (gamma - alpha)) * s, | |
479 |
2/4✓ Branch 5 taken 49017 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 49017 times.
✗ Branch 10 not taken.
|
49017 | -i_ * exp(0.5 * i_ * (alpha - gamma)) * s, | |
480 |
1/2✓ Branch 5 taken 49017 times.
✗ Branch 6 not taken.
|
49017 | exp(0.5 * i_ * (alpha + gamma)) * c; | |
481 |
2/4✓ Branch 3 taken 49017 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 49017 times.
✗ Branch 7 not taken.
|
98034 | return exp(i_ * t) * m; | |
482 | } | |||
483 | ||||
484 | } // namespace tket | |||
485 |