GCC Code Coverage Report


Directory: ./
File: Ops/include/Ops/ClassicalOps.hpp
Date: 2022-10-15 05:10:18
Exec Total Coverage
Lines: 12 34 35.3%
Functions: 9 27 33.3%
Branches: 3 14 21.4%
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 Classical operations
20 */
21
22 #include "Op.hpp"
23 #include "Utils/Json.hpp"
24
25 namespace tket {
26
27 /**
28 * A purely classical operation.
29 */
30 class ClassicalOp : public Op {
31 public:
32 /**
33 * Construct a ClassicalOp of specified shape
34 *
35 * this is a classical operation, only acting on the classical parts of the
36 * circuit
37 *
38 * @param type operation type
39 * @param n_i number of input-only bits
40 * @param n_io number of input/output bits
41 * @param n_o number of output-only bits
42 * @param name name of operation
43 */
44 ClassicalOp(
45 OpType type, unsigned n_i, unsigned n_io, unsigned n_o,
46 const std::string &name = "");
47
48 // Trivial overrides
49 Op_ptr symbol_substitution(
50 const SymEngine::map_basic_basic &) const override {
51 return Op_ptr();
52 }
53 SymSet free_symbols() const override { return {}; }
54 unsigned n_qubits() const override { return 0; }
55
56 op_signature_t get_signature() const override { return sig_; }
57
58 nlohmann::json serialize() const override;
59
60 static Op_ptr deserialize(const nlohmann::json &j);
61
62 std::string get_name(bool latex = false) const override;
63
64 /** Number of input-only bits. */
65 2 unsigned get_n_i() const { return n_i_; }
66
67 /** Number of input-output bits. */
68 3 unsigned get_n_io() const { return n_io_; }
69
70 /** Number of output-only bits. */
71 2 unsigned get_n_o() const { return n_o_; }
72
73 /**
74 * Equality check between two ClassicalEvalOp instances
75 */
76 bool is_equal(const Op &other) const override;
77
78 protected:
79 const unsigned n_i_;
80 const unsigned n_io_;
81 const unsigned n_o_;
82 const std::string name_;
83 std::vector<EdgeType> sig_;
84 };
85
86 class ClassicalEvalOp : public ClassicalOp {
87 public:
88 /**
89 * Construct a ClassicalEvalOp of specified shape
90 *
91 * this is a classical operation, only acting on the classical parts of the
92 * Circuit In addition to the ClassicalOp has the class the eval function in
93 * the signature, which allows a evaluation of this op
94 *
95 * @param type operation type
96 * @param n_i number of input-only bits
97 * @param n_io number of input/output bits
98 * @param n_o number of output-only bits
99 * @param name name of operation
100 */
101 ClassicalEvalOp(
102 OpType type, unsigned n_i, unsigned n_io, unsigned n_o,
103 const std::string &name = "");
104
105 /**
106 * Evaluation
107 *
108 * @param x vector of input bits
109 *
110 * @return vector of outbut bits
111 */
112 virtual std::vector<bool> eval(const std::vector<bool> &x) const = 0;
113
114 /**
115 * Equality check between two ClassicalEvalOp instances
116 */
117 bool is_equal(const Op &other) const override;
118 };
119
120 /**
121 * A general classical operation where all inputs are also outputs
122 */
123 class ClassicalTransformOp : public ClassicalEvalOp {
124 public:
125 /**
126 * Construct from a truth table.
127 *
128 * The truth table is represented by a vector of integers such that the j^th
129 * bit (in little-endian order) of the (sum_i a_i 2^i)^th term is the j^th
130 * output of the function applied to (a_i).
131 *
132 * @param n number of input/output bits
133 * @param values table of binary-encoded values
134 * @param name name of operation
135 *
136 * @pre n <= 32
137 */
138 ClassicalTransformOp(
139 unsigned n, const std::vector<uint32_t> &values,
140 const std::string &name = "ClassicalTransform");
141
142 std::vector<bool> eval(const std::vector<bool> &x) const override;
143
144 std::vector<uint32_t> get_values() const { return values_; }
145
146 private:
147 const std::vector<uint32_t> values_;
148 };
149
150 /**
151 * Op containing a classical wasm function call
152 */
153 class WASMOp : public ClassicalOp {
154 public:
155 /**
156 * contains a wasm op that could be added to a circuit.
157 * This op stores in its signatures which bits are interacting as input and
158 * output with the call to which function of the wasm file
159 *
160 * @param _n total number bits it is interacting with
161 * @param _ni_vec vector of bits for each input i32
162 * @param _no_vec vector of bits for each output i32
163 * @param _func_name name of the function
164 * @param _wasm_uid uid of the wasm file to be called
165 */
166 WASMOp(
167 unsigned _n, std::vector<unsigned> _ni_vec, std::vector<unsigned> _no_vec,
168 const std::string &_func_name, const std::string &_wasm_uid);
169
170 /**
171 * return if the op is external
172 */
173 1 bool is_extern() const override { return true; }
174
175 /**
176 * serialize wasmop to json
177 */
178 nlohmann::json serialize() const override;
179
180 /**
181 * deserialize json to wasmop
182 */
183 static Op_ptr deserialize(const nlohmann::json &j);
184
185 /**
186 * Equality check between two WASMOp instances
187 */
188 bool is_equal(const Op &other) const override;
189
190 /**
191 * returns the number of classical bits the wasm op is acting on
192 */
193 7 unsigned get_n() const { return n_; }
194
195 /**
196 * returns the number of i32 the function is acting on
197 */
198 unsigned get_n_i32() const { return n_i32_; }
199
200 /**
201 * returns the vector of number of bit used for each of the input i32
202 * variables
203 */
204 5 std::vector<unsigned> get_ni_vec() const { return ni_vec_; }
205
206 /**
207 * returns the vector of number of bit used for each of the output i32
208 * variables
209 */
210 5 std::vector<unsigned> get_no_vec() const { return no_vec_; }
211
212 /**
213 * returns the name of the function the wasm op is using
214 */
215 std::string get_func_name() const { return func_name_; }
216
217 /**
218 * returns the uid of the wasm file the op is using, the file is stored on the
219 * python layer
220 */
221 std::string get_wasm_uid() const { return wasm_uid_; }
222
223 private:
224 /**
225 * total number of classical bits the op is interacting with
226 */
227 const unsigned n_;
228
229 /**
230 * total number of i32 inut and output variables
231 */
232 const unsigned n_i32_;
233
234 /**
235 * vector of bits for each input i32
236 */
237 const std::vector<unsigned> ni_vec_;
238
239 /**
240 * vector of bits for each output i32
241 */
242 const std::vector<unsigned> no_vec_;
243
244 /**
245 * name of the called function
246 */
247 const std::string func_name_;
248
249 /**
250 * uid of the wasm file the op is using
251 */
252 const std::string wasm_uid_;
253 };
254
255 /**
256 * An operation to set some bits to specified values
257 */
258 class SetBitsOp : public ClassicalEvalOp {
259 public:
260 /**
261 * Construct from values.
262 *
263 * @param values values to set
264 */
265 3 explicit SetBitsOp(const std::vector<bool> &values)
266 3 : ClassicalEvalOp(OpType::SetBits, 0, 0, values.size(), "SetBits"),
267
3/6
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
6 values_(values) {}
268
269 std::string get_name(bool latex) const override;
270
271 std::vector<bool> get_values() const { return values_; }
272
273 std::vector<bool> eval(const std::vector<bool> &x) const override;
274
275 private:
276 std::vector<bool> values_;
277 };
278
279 /**
280 * An operation to copy some bit values
281 *
282 * @param n number of bits copied
283 */
284 class CopyBitsOp : public ClassicalEvalOp {
285 public:
286 explicit CopyBitsOp(unsigned n)
287 : ClassicalEvalOp(OpType::CopyBits, n, 0, n, "CopyBits") {}
288
289 std::vector<bool> eval(const std::vector<bool> &x) const override;
290 };
291
292 /**
293 * A classical operation with single output bit.
294 *
295 * There may be any number of input bits. The output bit is distinct from these.
296 */
297 class PredicateOp : public ClassicalEvalOp {
298 public:
299 /**
300 * Construct a PredicateOp of specified arity
301 *
302 * @param type type of classical operation
303 * @param n number of input bits
304 * @param name name of operation
305 */
306 PredicateOp(OpType type, unsigned n, const std::string &name = "")
307 : ClassicalEvalOp(type, n, 0, 1, name) {}
308 };
309
310 /**
311 * A predicate defined by a range of values in binary encoding
312 */
313 class RangePredicateOp : public PredicateOp {
314 public:
315 /**
316 * Construct from a lower and upper bound
317 *
318 * The lower and upper bounds are both inclusive. The output is set to 1 if
319 * and only the encoded number is in the specified range.
320 *
321 * @param n number of inputs to predicate
322 * @param a lower bound in little-endian encoding
323 * @param b upper bound in little-endian encoding
324 */
325 RangePredicateOp(
326 unsigned n, uint32_t a = 0,
327 uint32_t b = std::numeric_limits<uint32_t>::max())
328 : PredicateOp(OpType::RangePredicate, n, "RangePredicate"), a(a), b(b) {}
329
330 std::string get_name(bool latex) const override;
331
332 uint32_t upper() const { return b; }
333
334 uint32_t lower() const { return a; }
335
336 std::vector<bool> eval(const std::vector<bool> &x) const override;
337
338 /**
339 * Equality check between two RangePredicateOp instances
340 */
341 bool is_equal(const Op &other) const override;
342
343 private:
344 uint32_t a;
345 uint32_t b;
346 };
347
348 /**
349 * A predicate defined explicitly by a truth table
350 */
351 class ExplicitPredicateOp : public PredicateOp {
352 public:
353 /**
354 * @brief Construct from a table of values
355 *
356 * The truth table is represented by a vector of bool whose
357 * (sum_i a_i 2^i)^th term is the predicate applied to (a_i).
358 *
359 * @param n number of inputs to predicate
360 * @param values table of values
361 * @param name name of operation
362 *
363 * @pre n <= 32
364 */
365 ExplicitPredicateOp(
366 unsigned n, const std::vector<bool> &values,
367 const std::string &name = "ExplicitPredicate");
368
369 std::vector<bool> eval(const std::vector<bool> &x) const override;
370
371 std::vector<bool> get_values() const { return values_; }
372
373 private:
374 const std::vector<bool> values_;
375 };
376
377 /**
378 * A classical operation with one output bit which is also an input bit
379 */
380 class ModifyingOp : public ClassicalEvalOp {
381 public:
382 /**
383 * Construct a ModifyingOp of specified arity
384 *
385 * @param type type of classical operation
386 * @param n number of input bits in addition to the modified bit
387 * @param name name of operation
388 */
389 2 ModifyingOp(OpType type, unsigned n, const std::string &name)
390 2 : ClassicalEvalOp(type, n, 1, 0, name) {}
391 };
392
393 /**
394 * A modifying operation defined explicitly by a truth table
395 */
396 class ExplicitModifierOp : public ModifyingOp {
397 public:
398 /**
399 * @brief Construct from a table of values
400 *
401 * The truth table is represented by a vector of bool whose
402 * (sum_i a_i 2^i)^th term is the predicate applied to (a_i), where a_m is
403 * the initial value of the modified bit.
404 *
405 * @param n number of inputs to predicate in addition to the modified bit
406 * @param values table of values
407 * @param name name of operation
408 *
409 * @pre n <= 31
410 */
411 ExplicitModifierOp(
412 unsigned n, const std::vector<bool> &values,
413 const std::string &name = "ExplicitModifier");
414
415 std::vector<bool> eval(const std::vector<bool> &x) const override;
416
417 std::vector<bool> get_values() const { return values_; }
418
419 private:
420 const std::vector<bool> values_;
421 };
422
423 /**
424 * A classical operation applied simultaneously to multiple bits.
425 *
426 * The order of arguments is: all arguments to first operation, then all
427 * arguments to second operation, and so on.
428 */
429 class MultiBitOp : public ClassicalEvalOp {
430 public:
431 MultiBitOp(std::shared_ptr<const ClassicalEvalOp> op, unsigned n);
432
433 std::string get_name(bool latex) const override;
434
435 std::shared_ptr<const ClassicalEvalOp> get_op() const { return op_; }
436
437 unsigned get_n() const { return n_; }
438
439 std::vector<bool> eval(const std::vector<bool> &x) const override;
440
441 /**
442 * Equality check between two MultiBitOp instances
443 */
444 bool is_equal(const Op &other) const override;
445
446 private:
447 std::shared_ptr<const ClassicalEvalOp> op_;
448 unsigned n_;
449 };
450
451 /**
452 * Classical NOT transform
453 */
454 std::shared_ptr<ClassicalTransformOp> ClassicalX();
455
456 /**
457 * Classical CNOT transform
458 */
459 std::shared_ptr<ClassicalTransformOp> ClassicalCX();
460
461 /**
462 * Unary NOT operator
463 */
464 std::shared_ptr<ExplicitPredicateOp> NotOp();
465
466 /**
467 * Binary AND operator
468 */
469 std::shared_ptr<ExplicitPredicateOp> AndOp();
470
471 /**
472 * Binary OR operator
473 */
474 std::shared_ptr<ExplicitPredicateOp> OrOp();
475
476 /**
477 * Binary XOR operator
478 */
479 std::shared_ptr<ExplicitPredicateOp> XorOp();
480
481 /**
482 * In-place AND with another input
483 */
484 std::shared_ptr<ExplicitModifierOp> AndWithOp();
485
486 /**
487 * In-place OR with another input
488 */
489 std::shared_ptr<ExplicitModifierOp> OrWithOp();
490
491 /**
492 * In-place XOR with another input
493 */
494 std::shared_ptr<ExplicitModifierOp> XorWithOp();
495
496 } // namespace tket
497