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 | #pragma once | |||
16 | ||||
17 | /** | |||
18 | * @file | |||
19 | * @brief Functions related to (possibly symbolic) phase values | |||
20 | */ | |||
21 | ||||
22 | #include <map> | |||
23 | #include <optional> | |||
24 | #include <set> | |||
25 | #include <vector> | |||
26 | ||||
27 | #include "Constants.hpp" | |||
28 | #include "Json.hpp" | |||
29 | #include "Symbols.hpp" | |||
30 | ||||
31 | namespace tket { | |||
32 | ||||
33 | /** Representation of a phase as a multiple of \f$ \pi \f$ */ | |||
34 | typedef SymEngine::Expression Expr; | |||
35 | ||||
36 | JSON_DECL(Expr) | |||
37 | ||||
38 | /** Shared pointer to an \p Expr */ | |||
39 | typedef SymEngine::RCP<const SymEngine::Basic> ExprPtr; | |||
40 | ||||
41 | /** Shared pointer to a free symbol */ | |||
42 | typedef SymEngine::RCP<const SymEngine::Symbol> Sym; | |||
43 | ||||
44 | } // namespace tket | |||
45 | ||||
46 | namespace nlohmann { | |||
47 | ||||
48 | template <> | |||
49 | struct adl_serializer<tket::Expr> { | |||
50 | ✗ | static void to_json(json& j, const tket::Expr& exp) { | ||
51 | ✗ | tket::ExprPtr e_ = exp; | ||
52 | ✗ | j = e_->__str__(); | ||
53 | } | |||
54 | ||||
55 | ✗ | static void from_json(const json& j, tket::Expr& exp) { | ||
56 | ✗ | exp = j.get<std::string>(); | ||
57 | } | |||
58 | }; | |||
59 | ||||
60 | template <> | |||
61 | struct adl_serializer<tket::Sym> { | |||
62 | 2 | static void to_json(json& j, const tket::Sym& exp) { | ||
63 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | tket::ExprPtr e_ = exp; | |
64 |
3/6✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
|
2 | j = e_->__str__(); | |
65 | 2 | } | ||
66 | ||||
67 | 2 | static void from_json(const json& j, tket::Sym& exp) { | ||
68 |
2/4✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
|
2 | exp = SymEngine::symbol(j.get<std::string>()); | |
69 | 2 | } | ||
70 | }; | |||
71 | ||||
72 | } // namespace nlohmann | |||
73 | ||||
74 | namespace tket { | |||
75 | ||||
76 | struct SymCompareLess { | |||
77 | ✗ | bool operator()(const Sym& a, const Sym& b) const { | ||
78 | ✗ | return a->compare(*b) < 0; | ||
79 | } | |||
80 | }; | |||
81 | ||||
82 | typedef std::set<Sym, SymCompareLess> SymSet; | |||
83 | ||||
84 | /** Map from symbols to expressions */ | |||
85 | typedef std::map<Sym, Expr, SymEngine::RCPBasicKeyLess> symbol_map_t; | |||
86 | ||||
87 | /** Set of all free symbols contained in the expression */ | |||
88 | SymSet expr_free_symbols(const Expr& e); | |||
89 | ||||
90 | /** Set of all free symbols contained in the expressions in the vector */ | |||
91 | SymSet expr_free_symbols(const std::vector<Expr>& es); | |||
92 | ||||
93 | std::optional<double> eval_expr(const Expr& e); | |||
94 | ||||
95 | std::optional<Complex> eval_expr_c(const Expr& e); | |||
96 | ||||
97 | /** | |||
98 | * Evaluate an expression modulo n | |||
99 | * | |||
100 | * The result will be in the half-interval [0,n). If it is within EPS of a | |||
101 | * multiple of 0.25 the result is clamped to an exact multiple. | |||
102 | * | |||
103 | * @param e expression to evaluate | |||
104 | * @param n modulus | |||
105 | * @return value of expression modulo n, iff it has no free symbols | |||
106 | */ | |||
107 | std::optional<double> eval_expr_mod(const Expr& e, unsigned n = 2); | |||
108 | ||||
109 | /** | |||
110 | * Return cos(e*pi/2) | |||
111 | * | |||
112 | * If e is within @p EPS of an integer then it is rounded so that the result can | |||
113 | * be evaluated. | |||
114 | */ | |||
115 | Expr cos_halfpi_times(const Expr& e); | |||
116 | ||||
117 | /** | |||
118 | * Return sin(e*pi/2) | |||
119 | * | |||
120 | * If e is within @p EPS of an integer then it is rounded so that the result can | |||
121 | * be evaluated. | |||
122 | */ | |||
123 | Expr sin_halfpi_times(const Expr& e); | |||
124 | ||||
125 | /** | |||
126 | * Return -e | |||
127 | * | |||
128 | * Expanding e after multiplying by -1 may reduce its size, especially when | |||
129 | * `minus_times` is applied repeatedly and should cancel out. | |||
130 | * | |||
131 | * @param e expression | |||
132 | * @return Expr -e | |||
133 | */ | |||
134 | Expr minus_times(const Expr& e); | |||
135 | ||||
136 | /** | |||
137 | * Test if an expression is approximately zero | |||
138 | * | |||
139 | * @param e expression | |||
140 | * @param tol tolerance | |||
141 | * | |||
142 | * @return whether \p e is within \p tol of zero | |||
143 | */ | |||
144 | bool approx_0(const Expr& e, double tol = EPS); | |||
145 | ||||
146 | /** | |||
147 | * Evaluate modulo n in the range [0,n) | |||
148 | * | |||
149 | * @param x value to be reduced | |||
150 | * @param n modulus | |||
151 | * | |||
152 | * @return y s.t. y == x (mod n) and 0 <= y < n | |||
153 | */ | |||
154 | double fmodn(double x, unsigned n); | |||
155 | ||||
156 | /** | |||
157 | * Test approximate equality of two values modulo n | |||
158 | * | |||
159 | * @param x first value | |||
160 | * @param y second value | |||
161 | * @param mod modulus | |||
162 | * @param tol tolerance | |||
163 | * | |||
164 | * @return whether \p x is within \p tol of \p y modulo \p mod | |||
165 | */ | |||
166 | bool approx_eq(double x, double y, unsigned mod = 2, double tol = EPS); | |||
167 | ||||
168 | /** | |||
169 | * Test approximate equality of expressions modulo n | |||
170 | * | |||
171 | * @param e0 expression | |||
172 | * @param e1 expression | |||
173 | * @param n modulus | |||
174 | * @param tol tolerance | |||
175 | * | |||
176 | * @retval true \p e0 and \p e1 are within \p tol of each other modulo n | |||
177 | * @retval false expressions are not within tolerance or could not ve evaluated | |||
178 | */ | |||
179 | bool equiv_expr( | |||
180 | const Expr& e0, const Expr& e1, unsigned n = 2, double tol = EPS); | |||
181 | ||||
182 | /** | |||
183 | * Test approximate value of an expression modulo n | |||
184 | * | |||
185 | * @param e expression | |||
186 | * @param x test value | |||
187 | * @param n modulus | |||
188 | * @param tol tolerance | |||
189 | * | |||
190 | * @retval true \p e is within \p tol of \p x modulo n | |||
191 | * @retval false expression is not within tolerance or could not be evaluated | |||
192 | */ | |||
193 | bool equiv_val(const Expr& e, double x, unsigned n = 2, double tol = EPS); | |||
194 | ||||
195 | /** | |||
196 | * Test whether a expression is approximately 0 modulo n | |||
197 | * | |||
198 | * @param e expression | |||
199 | * @param n modulus | |||
200 | * @param tol tolerance | |||
201 | * | |||
202 | * @retval true \p e is within \p tol of 0 modulo n | |||
203 | * @retval false expression is not within tolerance or could not be evaluated | |||
204 | */ | |||
205 | bool equiv_0(const Expr& e, unsigned n = 2, double tol = EPS); | |||
206 | ||||
207 | /** | |||
208 | * Test whether an expression is approximately a Clifford angle (some multiple | |||
209 | * of 0.5 modulo n) | |||
210 | * | |||
211 | * @param e expression | |||
212 | * @param n modulus | |||
213 | * @param tol tolerance | |||
214 | * | |||
215 | * @retval nullopt expression is not within tolerance or could not be evaluated | |||
216 | * @retval u \f$ e \approx \frac12 u \pmod n \f$ where \f$ 0 \leq u < 2n \} \f$. | |||
217 | */ | |||
218 | std::optional<unsigned> equiv_Clifford( | |||
219 | const Expr& e, unsigned n = 2, double tol = EPS); | |||
220 | ||||
221 | /** | |||
222 | * Exception indicating that symbolic values are not supported. | |||
223 | */ | |||
224 | class SymbolsNotSupported : public std::logic_error { | |||
225 | public: | |||
226 | ✗ | explicit SymbolsNotSupported(const std::string& message) | ||
227 | ✗ | : std::logic_error(message) {} | ||
228 | ✗ | SymbolsNotSupported() | ||
229 | ✗ | : SymbolsNotSupported("Symbolic values not supported") {} | ||
230 | }; | |||
231 | ||||
232 | } // namespace tket | |||
233 |