GCC Code Coverage Report


Directory: ./
File: Utils/include/Utils/Expression.hpp
Date: 2022-10-15 05:10:18
Exec Total Coverage
Lines: 7 18 38.9%
Functions: 2 7 28.6%
Branches: 6 26 23.1%
Decisions: 0 0 -%

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