Maestro 0.1.0
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
SyntaxTree.h
Go to the documentation of this file.
1
11
12#pragma once
13
14#ifndef _SYNTAXTREE_H_
15#define _SYNTAXTREE_H_
16
17#include "../Circuit/Factory.h"
18#include "SimpleOps.h"
19
20namespace qasm {
22 struct result {
24 };
25
27 const UopType &uop,
28 const std::unordered_map<std::string, IndexedId> &qreg_map,
29 const std::unordered_map<std::string, StatementType> &opaqueGates,
30 const std::unordered_map<std::string, StatementType> &definedGates,
31 const std::unordered_map<std::string, double> &variables = {}) const {
32 StatementType stmt;
34
35 if (std::holds_alternative<UGateCallType>(uop)) {
36 const auto &gate = std::get<UGateCallType>(uop);
37 const std::vector<Expression> &params = boost::fusion::at_c<0>(gate);
38 const ArgumentType &arg = boost::fusion::at_c<1>(gate);
39
41
42 for (const auto &p : params)
43 stmt.parameters.push_back(p.Eval(variables));
44
45 stmt.qubits = ParseQubits(arg, qreg_map);
46 } else if (std::holds_alternative<CXGateCallType>(uop)) {
47 const auto &gate = std::get<CXGateCallType>(uop);
48
50
51 // two arguments
52 const ArgumentType &arg1 = boost::fusion::at_c<0>(gate);
53 const ArgumentType &arg2 = boost::fusion::at_c<1>(gate);
54
55 const std::vector<int> qubits1 = ParseQubits(arg1, qreg_map);
56 const std::vector<int> qubits2 = ParseQubits(arg2, qreg_map);
57
58 // four cases
59 if (qubits1.size() == 1 && qubits2.size() == 1) {
60 // cx q1[i], q2[j]
61 stmt.qubits.push_back(qubits1[0]);
62 stmt.qubits.push_back(qubits2[0]);
63 } else if (qubits1.size() == 1 && qubits2.size() > 1) {
64 // cx q1[i], q2
65 for (const auto &q2 : qubits2) {
66 if (q2 == qubits1[0])
67 throw std::invalid_argument(
68 "Control and target qubits cannot be the same for CX gate");
69 stmt.qubits.push_back(qubits1[0]);
70 stmt.qubits.push_back(q2);
71 }
72 } else if (qubits1.size() > 1 && qubits2.size() == 1) {
73 // cx q[], q[j]
74 for (const auto &q1 : qubits1) {
75 if (q1 == qubits2[0])
76 throw std::invalid_argument(
77 "Control and target qubits cannot be the same for CX gate");
78 stmt.qubits.push_back(q1);
79 stmt.qubits.push_back(qubits2[0]);
80 }
81 } else if (qubits1.size() == qubits2.size()) {
82 // cx q1, q2
83 for (size_t i = 0; i < qubits1.size(); ++i) {
84 if (qubits1[i] == qubits2[i])
85 throw std::invalid_argument(
86 "Control and target qubits cannot be the same for CX gate");
87 stmt.qubits.push_back(qubits1[i]);
88 stmt.qubits.push_back(qubits2[i]);
89 }
90 } else
91 throw std::invalid_argument(
92 "Mismatched qubits sizes for CX gate arguments");
93 } else if (std::holds_alternative<GatecallType>(uop)) {
94 const auto &gateCall = std::get<GatecallType>(uop);
95 // can be either simple or with expressions
96 if (std::holds_alternative<SimpleGatecallType>(gateCall)) {
97 // gate without parameters
98 const auto &gate = std::get<SimpleGatecallType>(gateCall);
99 const std::string &gateName = boost::fusion::at_c<0>(gate);
100 std::string gateNameLower = gateName;
101 std::transform(gateNameLower.begin(), gateNameLower.end(),
102 gateNameLower.begin(), ::tolower);
103
104 const MixedListType &args = boost::fusion::at_c<1>(gate);
105
106 const auto it = definedGates.find(gateName);
107 if (it == definedGates.end()) {
108 if (!IsSuppportedGate(gateNameLower))
109 throw std::invalid_argument(
110 "Unsupported gate without parameters: " + gateName);
111
112 stmt.gateType = GetGateType(gateNameLower);
113 const int expectedNrQubits = GateNrQubits(stmt.gateType);
114 if (args.size() != expectedNrQubits)
115 throw std::invalid_argument(
116 "Gate " + gateName + " requires exactly " +
117 std::to_string(expectedNrQubits) + " qubits");
118 } else {
119 // defined gate, check if the number of qubits match
120 const StatementType &definedGateStmt = it->second;
121 const int expectedNrQubits =
122 static_cast<int>(definedGateStmt.qubitsDecl.size());
123 if (args.size() != expectedNrQubits)
124 throw std::invalid_argument(
125 "Defined gate " + gateName + " requires exactly " +
126 std::to_string(expectedNrQubits) + " qubits");
127 if (definedGateStmt.parameters.size() != 0)
128 throw std::invalid_argument(
129 "Defined gate " + gateName +
130 " requires parameters, but none were provided");
131
132 stmt.comment = gateName;
133
134 // copy the gate definition here, as it might be redefined later
135 // (actually not yet supported)
136 stmt.qubitsDecl = definedGateStmt.qubitsDecl;
137 stmt.declOps = definedGateStmt.declOps;
138 }
139
140 // first, check the qubits
141 int qubitsCounter = 1;
142
143 std::vector<std::vector<int>> allQubits(args.size());
144 for (int i = 0; i < static_cast<int>(args.size()); ++i) {
145 const ArgumentType &arg = args[i];
146 std::vector<int> qubits = ParseQubits(arg, qreg_map);
147
148 if (qubits.size() != 1) {
149 if (qubitsCounter == 1)
150 qubitsCounter = static_cast<int>(qubits.size());
151 else if (qubitsCounter != static_cast<int>(qubits.size()))
152 throw std::invalid_argument(
153 "Mismatched qubits sizes for gate arguments");
154 }
155
156 allQubits[i] = std::move(qubits);
157 }
158
159 // now set them
160 for (int i = 0; i < qubitsCounter; ++i) {
161 for (const auto &qlist : allQubits) {
162 if (qlist.size() == 1)
163 stmt.qubits.push_back(qlist[0]);
164 else
165 stmt.qubits.push_back(qlist[i]);
166 }
167 }
168 } else if (std::holds_alternative<ExpGatecallType>(gateCall)) {
169 // gate with parameters
170 const auto &gate = std::get<ExpGatecallType>(gateCall);
171 const std::string &gateName = boost::fusion::at_c<0>(gate);
172 std::string gateNameLower = gateName;
173 std::transform(gateNameLower.begin(), gateNameLower.end(),
174 gateNameLower.begin(), ::tolower);
175
176 const std::vector<Expression> &params = boost::fusion::at_c<1>(gate);
177 const MixedListType &args = boost::fusion::at_c<2>(gate);
178
179 for (const auto &p : params)
180 stmt.parameters.push_back(p.Eval(variables));
181
182 const auto it = definedGates.find(gateName);
183 if (it == definedGates.end()) {
184 if (IsSuppportedGate(gateNameLower)) {
185 if (params.empty())
186 throw std::invalid_argument("Gate " + gateName +
187 " requires parameters");
188 else if (params.size() == 1) {
189 if (!IsSuppportedOneParamGate(gateNameLower))
190 throw std::invalid_argument(
191 "This gate does not allow one parameter: " + gateName);
192 } else if (params.size() > 1) {
193 if (!IsSuppportedMultipleParamsGate(gateNameLower))
194 throw std::invalid_argument(
195 "This gate does not allow multiple parameters: " +
196 gateName);
197
198 if (params.size() > 4)
199 throw std::invalid_argument("Too many parameters for gate: " +
200 gateName);
201 }
202
203 stmt.gateType = GetGateType(gateNameLower);
204 const int expectedNrQubits = GateNrQubits(stmt.gateType);
205 if (args.size() != expectedNrQubits)
206 throw std::invalid_argument(
207 "Gate " + gateName + " requires exactly " +
208 std::to_string(expectedNrQubits) + " qubits");
209
210 if (gateNameLower == "u1") {
211 const double lambda = stmt.parameters[0];
212 stmt.parameters[0] = 0.0; // theta
213 stmt.parameters.push_back(0.);
214 stmt.parameters.push_back(lambda);
215 } else if (gateNameLower == "u2") {
216 const double phi = stmt.parameters[0];
217 const double lambda = stmt.parameters[1];
218
219 stmt.parameters[0] = M_PI / 2.0; // theta
220 stmt.parameters[1] = phi;
221 stmt.parameters.push_back(lambda);
222 } else if (gateNameLower == "cu1") {
223 const double lambda = stmt.parameters[0];
224 stmt.parameters[0] = 0.0; // theta
225 stmt.parameters.push_back(0.);
226 stmt.parameters.push_back(lambda);
227 } else if (gateNameLower == "cu2") {
228 const double phi = stmt.parameters[0];
229 const double lambda = stmt.parameters[1];
230
231 stmt.parameters[0] = M_PI / 2.0; // theta
232 stmt.parameters[1] = phi;
233 stmt.parameters.push_back(lambda);
234 }
235 } else if (gateNameLower == "u1") {
237
238 if (stmt.parameters.size() != 1)
239 throw std::invalid_argument(
240 "Gate u1 requires exactly one parameter");
241
242 const double lambda = stmt.parameters[0];
243 stmt.parameters[0] = 0.0; // theta
244 stmt.parameters.push_back(0.);
245 stmt.parameters.push_back(lambda);
246
247 if (args.size() != 1)
248 throw std::invalid_argument("Gate " + gateName +
249 " requires exactly 1 qubit");
250 } else if (gateNameLower == "u2") {
252
253 if (stmt.parameters.size() != 2)
254 throw std::invalid_argument("Gate u2 requires two parameters");
255
256 const double phi = stmt.parameters[0];
257 const double lambda = stmt.parameters[1];
258
259 stmt.parameters[0] = M_PI / 2.0; // theta
260 stmt.parameters[1] = phi;
261 stmt.parameters.push_back(lambda);
262
263 if (args.size() != 1)
264 throw std::invalid_argument("Gate " + gateName +
265 " requires exactly 1 qubit");
266 } else if (gateNameLower == "u3") {
268
269 if (stmt.parameters.size() != 3)
270 throw std::invalid_argument("Gate u3 requires three parameters");
271 // nothing to do, u3 already has the correct parameters
272
273 if (args.size() != 1)
274 throw std::invalid_argument("Gate " + gateName +
275 " requires exactly 1 qubit");
276 } else if (gateNameLower == "cu1") {
278
279 if (stmt.parameters.size() != 1)
280 throw std::invalid_argument(
281 "Gate cu1 requires exactly one parameter");
282
283 const double lambda = stmt.parameters[0];
284 stmt.parameters[0] = 0.0; // theta
285 stmt.parameters.push_back(0.);
286 stmt.parameters.push_back(lambda);
287
288 if (args.size() != 2)
289 throw std::invalid_argument("Gate " + gateName +
290 " requires exactly 2 qubits");
291 } else if (gateNameLower == "cu2") {
293
294 if (stmt.parameters.size() != 2)
295 throw std::invalid_argument("Gate cu2 requires two parameters");
296
297 const double phi = stmt.parameters[0];
298 const double lambda = stmt.parameters[1];
299
300 stmt.parameters[0] = M_PI / 2.0; // theta
301 stmt.parameters[1] = phi;
302 stmt.parameters.push_back(lambda);
303
304 if (args.size() != 2)
305 throw std::invalid_argument("Gate " + gateName +
306 " requires exactly 2 qubits");
307 } else if (gateNameLower == "cu3") {
309
310 if (stmt.parameters.size() != 3)
311 throw std::invalid_argument("Gate cu3 requires three parameters");
312 // nothing to do, cu3 already has the correct parameters
313
314 if (args.size() != 2)
315 throw std::invalid_argument("Gate " + gateName +
316 " requires exactly 2 qubits");
317 }
318 } else {
319 // defined gate, check if the number of parameters and qubits match
320 const StatementType &definedGateStmt = it->second;
321 const int expectedNrQubits =
322 static_cast<int>(definedGateStmt.qubitsDecl.size());
323 if (args.size() != expectedNrQubits)
324 throw std::invalid_argument(
325 "Defined gate " + gateName + " requires exactly " +
326 std::to_string(expectedNrQubits) + " qubits");
327
328 if (definedGateStmt.paramsDecl.size() != stmt.parameters.size())
329 throw std::invalid_argument(
330 "Defined gate " + gateName + " requires a different number (" +
331 std::to_string(definedGateStmt.paramsDecl.size()) +
332 ") of parameters than " +
333 std::to_string(stmt.parameters.size()));
334
335 stmt.comment = gateName;
336
337 // copy the gate definition here, as it might be redefined later
338 stmt.paramsDecl = definedGateStmt.paramsDecl;
339 stmt.qubitsDecl = definedGateStmt.qubitsDecl;
340 stmt.declOps = definedGateStmt.declOps;
341 }
342
343 // first, check the qubits
344 int qubitsCounter = 1;
345
346 std::vector<std::vector<int>> allQubits(args.size());
347 for (int i = 0; i < static_cast<int>(args.size()); ++i) {
348 const ArgumentType &arg = args[i];
349 std::vector<int> qubits = ParseQubits(arg, qreg_map);
350
351 if (qubits.size() != 1) {
352 if (qubitsCounter == 1)
353 qubitsCounter = static_cast<int>(qubits.size());
354 else if (qubitsCounter != static_cast<int>(qubits.size()))
355 throw std::invalid_argument(
356 "Mismatched qubits sizes for gate arguments");
357 }
358
359 allQubits[i] = std::move(qubits);
360 }
361
362 // now set them
363 for (int i = 0; i < qubitsCounter; ++i) {
364 for (const auto &qlist : allQubits) {
365 if (qlist.size() == 1)
366 stmt.qubits.push_back(qlist[0]);
367 else
368 stmt.qubits.push_back(qlist[i]);
369 }
370 }
371 }
372 }
373
374 return stmt;
375 }
376
377 static std::vector<int>
379 const std::unordered_map<std::string, IndexedId> &qreg_map) {
380 std::vector<int> qubits;
381 // there are two possibilities here, either it's an indexed id or a simple
382 // id
383 if (std::holds_alternative<IndexedId>(arg)) {
384 const IndexedId &indexedId = std::get<IndexedId>(arg);
385 auto it = qreg_map.find(indexedId.id);
386 if (it != qreg_map.end()) {
387 int base = it->second.base;
388 qubits.push_back(base + indexedId.index);
389 }
390 } else if (std::holds_alternative<std::string>(arg)) {
391 const std::string &id = std::get<std::string>(arg);
392 auto it = qreg_map.find(id);
393 if (it != qreg_map.end()) {
394 int base = it->second.base;
395 int size = static_cast<int>(std::round(it->second.Eval()));
396 for (int i = 0; i < size; ++i)
397 qubits.push_back(base + i);
398 }
399 }
400
401 return qubits;
402 }
403
404 static bool IsSuppportedNoParamGate(const std::string &gateName) {
405 return allowedNoParamGates.find(gateName) != allowedNoParamGates.end();
406 }
407
408 static bool IsSuppportedOneParamGate(const std::string &gateName) {
409 return allowedOneParamGates.find(gateName) != allowedOneParamGates.end();
410 }
411
412 static bool IsSuppportedMultipleParamsGate(const std::string &gateName) {
413 return allowedMultipleParamsGates.find(gateName) !=
414 allowedMultipleParamsGates.end();
415 }
416
417 static bool IsSuppportedGate(const std::string &gateName) {
418 return allowedNoParamGates.find(gateName) != allowedNoParamGates.end() ||
419 allowedOneParamGates.find(gateName) != allowedOneParamGates.end() ||
420 allowedMultipleParamsGates.find(gateName) !=
421 allowedMultipleParamsGates.end();
422 }
423
424 Circuits::QuantumGateType GetGateType(const std::string &gateN) const {
425 std::string gateName = gateN;
426 std::transform(gateName.begin(), gateName.end(), gateName.begin(),
427 ::tolower);
428
429 if (gateName == "x")
431 else if (gateName == "y")
433 else if (gateName == "z")
435 else if (gateName == "h")
437 else if (gateName == "s")
439 else if (gateName == "sdg" || gateName == "sxdag")
441 else if (gateName == "t")
443 else if (gateName == "tdg" || gateName == "tdag")
445 else if (gateName == "sx")
447 else if (gateName == "sxdg" || gateName == "sxdag")
449 else if (gateName == "k")
451 else if (gateName == "swap")
453 else if (gateName == "cx")
455 else if (gateName == "cy")
457 else if (gateName == "cz")
459 else if (gateName == "ch")
461 else if (gateName == "csx")
463 else if (gateName == "csxdg" || gateName == "csxdag")
465 else if (gateName == "cswap")
467 else if (gateName == "ccx")
469 else if (gateName == "p")
471 else if (gateName == "rx")
473 else if (gateName == "ry")
475 else if (gateName == "rz")
477 else if (gateName == "cp")
479 else if (gateName == "crx")
481 else if (gateName == "cry")
483 else if (gateName == "crz")
485 else if (gateName == "u" || gateName == "u3" || gateName == "u1")
487 else if (gateName == "cu" || gateName == "cu3" || gateName == "cu1")
489
490 return Circuits::QuantumGateType::kNone; // this will be returnd also for
491 // 'id'
492 }
493
495 const int gateT = static_cast<int>(gateType);
496
497 if (gateT < static_cast<int>(Circuits::QuantumGateType::kSwapGateType))
498 return 1;
499 else if (gateT <
501 return 2;
502 else if (gateT <= static_cast<int>(Circuits::QuantumGateType::kCCXGateType))
503 return 3;
504
505 return 0;
506 }
507
508private:
509 static inline std::unordered_set<std::string> allowedNoParamGates = {
510 "x", "y", "z", "h", "s", "sdg", "sdag", "t", "tdg",
511 "tdag", "sx", "sxdg", "sxdag", "k", "swap", "cx", "cy", "cz",
512 "ch", "csx", "csxdg", "csxdag", "cswap", "ccx", "id"};
513 static inline std::unordered_set<std::string> allowedOneParamGates = {
514 "p", "rx", "ry", "rz", "cp", "crx", "cry", "crz", "u1", "cu1"};
515 static inline std::unordered_set<std::string> allowedMultipleParamsGates = {
516 "u", "u3", "cu1", "cu3"}; // max 4
517};
518
519phx::function<AddGateExpr> AddGate;
520
522 struct result {
524 };
525
528 const std::unordered_map<std::string, IndexedId> &qreg_map,
529 const std::unordered_map<std::string, IndexedId> &creg_map,
530 const std::unordered_map<std::string, StatementType> &opaqueGates,
531 const std::unordered_map<std::string, StatementType> &definedGates)
532 const {
533 StatementType stmt;
534
535 const std::string &condId = boost::fusion::at_c<0>(condOp);
536 int condVal = boost::fusion::at_c<1>(condOp);
537 const QoperationStatement &op = boost::fusion::at_c<2>(condOp);
538
539 stmt = op;
540
542 stmt.condValue = condVal;
543
544 if (creg_map.find(condId) == creg_map.end())
545 throw std::invalid_argument("Condition register not found: " + condId);
546 else {
547 const IndexedId &condCreg = creg_map.at(condId);
548
549 for (int c = 0; c < condCreg.Eval(); ++c)
550 stmt.cbits.push_back(condCreg.base + c);
551 }
552
553 return stmt;
554 }
555};
556
557phx::function<AddCondQopExpr> AddCondQop;
558
559struct Program {
560 double version = 2.0;
561 std::vector<StatementType> statements;
562 std::vector<std::string> comments;
563 std::vector<std::string> includes;
564
565 Program(const ProgramType &program = {}) {
566 comments = boost::fusion::at_c<0>(program);
567 version = boost::fusion::at_c<1>(program);
568 includes = boost::fusion::at_c<2>(program);
569 statements = boost::fusion::at_c<3>(program);
570 }
571
572 void clear() {
573 comments.clear();
574 includes.clear();
575 statements.clear();
576 version = 2.0;
577 }
578
579 template <typename Time = Types::time_type>
580 std::shared_ptr<Circuits::Circuit<Time>> ToCircuit(
581 std::unordered_map<std::string, StatementType> &opaqueGates,
582 std::unordered_map<std::string, StatementType> &definedGates) const {
583 auto circuit = std::make_shared<Circuits::Circuit<Time>>();
584
585 for (const auto &stmt : statements)
586 AddToCircuit(circuit, stmt, opaqueGates, definedGates);
587
588 return circuit;
589 }
590
591 template <typename Time = Types::time_type>
592 static void
593 AddToCircuit(const std::shared_ptr<Circuits::Circuit<Time>> &circuit,
594 const StatementType &stmt,
595 std::unordered_map<std::string, StatementType> &opaqueGates,
596 std::unordered_map<std::string, StatementType> &definedGates) {
597 switch (stmt.opType) {
599 if (stmt.qubits.size() != stmt.cbits.size())
600 throw std::invalid_argument("Measurement operation: number of qubits "
601 "and classical bits do not match.");
602
603 std::vector<std::pair<Types::qubit_t, size_t>> qs;
604 for (size_t i = 0; i < stmt.qubits.size(); ++i)
605 qs.push_back({static_cast<Types::qubit_t>(stmt.qubits[i]),
606 static_cast<size_t>(stmt.cbits[i])});
607
609 circuit->AddOperation(measureOp);
610 } break;
612 Types::qubits_vector qubits(stmt.qubits.begin(), stmt.qubits.end());
613 auto resetOp = Circuits::CircuitFactory<Time>::CreateReset(qubits);
614 circuit->AddOperation(resetOp);
615 } break;
616
619 // can add more than one gate here depending on what's in qubits
620 double param1 = stmt.parameters.size() > 0 ? stmt.parameters[0] : 0;
621 double param2 = stmt.parameters.size() > 1 ? stmt.parameters[1] : 0;
622 double param3 = stmt.parameters.size() > 2 ? stmt.parameters[2] : 0;
623 double param4 = stmt.parameters.size() > 3 ? stmt.parameters[3] : 0;
624
625 int nrQubits = AddGateExpr::GateNrQubits(stmt.gateType);
626 if (stmt.qubits.size() % nrQubits != 0)
627 throw std::invalid_argument("Uop operation: number of qubits does "
628 "not match the gate requirements.");
629
630 for (int pos = 0; pos < static_cast<int>(stmt.qubits.size());
631 pos += nrQubits) {
632 Types::qubits_vector gateQubits;
633 for (int q = 0; q < nrQubits; ++q)
634 gateQubits.push_back(
635 static_cast<Types::qubit_t>(stmt.qubits[pos + q]));
636
638 stmt.gateType, gateQubits[0], nrQubits > 1 ? gateQubits[1] : 0,
639 nrQubits > 2 ? gateQubits[2] : 0, param1, param2, param3, param4);
640
641 circuit->AddOperation(gateOp);
642 }
643 } else {
644 // it's a defined gate, check further and implement
645 // will add several gates to the circuit
646 if (stmt.paramsDecl.size() != stmt.parameters.size())
647 throw std::invalid_argument("Uop operation: number of parameters do "
648 "not match the declaration.");
649
650 std::unordered_map<std::string, double> variables;
651
652 for (size_t i = 0; i < stmt.paramsDecl.size(); ++i)
653 variables[stmt.paramsDecl[i]] = stmt.parameters[i];
654
655 int nrQubits = static_cast<int>(stmt.qubitsDecl.size());
656 if (stmt.qubits.size() % nrQubits != 0)
657 throw std::invalid_argument("Defined Uop operation: number of qubits "
658 "does not match the gate requirements.");
659
660 for (int pos = 0; pos < static_cast<int>(stmt.qubits.size());
661 pos += nrQubits) {
662 std::unordered_map<std::string, IndexedId> qubitMap;
663 for (int q = 0; q < nrQubits; ++q) {
664 IndexedId id;
665 id.id = stmt.qubitsDecl[q];
666 id.base = stmt.qubits[pos + q];
667 id.index = 1;
668 qubitMap[id.id] = id;
669 }
670
671 // now walk over all gates in declOps and add them to the circuit
672 AddGateExpr addGate;
673 for (const auto &op : stmt.declOps) {
674 StatementType gateStmt =
675 addGate(op, qubitMap, opaqueGates, definedGates, variables);
676
677 AddToCircuit(circuit, gateStmt, opaqueGates, definedGates);
678 }
679 }
680 }
681 } break;
683 unsigned long long int condValue =
684 static_cast<unsigned long long int>(stmt.condValue);
685
687 // can add more than one gate here depending on what's in qubits
688 double param1 = stmt.parameters.size() > 0 ? stmt.parameters[0] : 0;
689 double param2 = stmt.parameters.size() > 1 ? stmt.parameters[1] : 0;
690 double param3 = stmt.parameters.size() > 2 ? stmt.parameters[2] : 0;
691 double param4 = stmt.parameters.size() > 3 ? stmt.parameters[3] : 0;
692
693 int nrQubits = AddGateExpr::GateNrQubits(stmt.gateType);
694 if (stmt.qubits.size() % nrQubits != 0)
695 throw std::invalid_argument("Uop operation: number of qubits does "
696 "not match the gate requirements.");
697
698 std::vector<size_t> ind;
699 std::vector<bool> condBits;
700
701 for (size_t i = 0; i < stmt.cbits.size(); ++i) {
702 ind.push_back(static_cast<size_t>(stmt.cbits[i]));
703 condBits.push_back((condValue & 1) == 1);
704 condValue >>= 1;
705 }
706
707 const auto condition =
709
710 for (int pos = 0; pos < static_cast<int>(stmt.qubits.size());
711 pos += nrQubits) {
712 Types::qubits_vector gateQubits;
713 for (int q = 0; q < nrQubits; ++q)
714 gateQubits.push_back(
715 static_cast<Types::qubit_t>(stmt.qubits[pos + q]));
716
718 stmt.gateType, gateQubits[0], nrQubits > 1 ? gateQubits[1] : 0,
719 nrQubits > 2 ? gateQubits[2] : 0, param1, param2, param3, param4);
720
722 gateOp, condition);
723 circuit->AddOperation(condOp);
724 }
725 } else {
726 // it's a defined gate, check further and implement
727 // will add several gates to the circuit
728 if (stmt.paramsDecl.size() != stmt.parameters.size())
729 throw std::invalid_argument("Uop operation: number of parameters do "
730 "not match the declaration.");
731
732 std::unordered_map<std::string, double> variables;
733
734 for (size_t i = 0; i < stmt.paramsDecl.size(); ++i)
735 variables[stmt.paramsDecl[i]] = stmt.parameters[i];
736
737 int nrQubits = static_cast<int>(stmt.qubitsDecl.size());
738 if (stmt.qubits.size() % nrQubits != 0)
739 throw std::invalid_argument("Defined Uop operation: number of qubits "
740 "does not match the gate requirements.");
741
742 for (int pos = 0; pos < static_cast<int>(stmt.qubits.size());
743 pos += nrQubits) {
744 std::unordered_map<std::string, IndexedId> qubitMap;
745 for (int q = 0; q < nrQubits; ++q) {
746 IndexedId id;
747 id.id = stmt.qubitsDecl[q];
748 id.base = stmt.qubits[pos + q];
749 id.index = 1;
750 qubitMap[id.id] = id;
751 }
752
753 // now walk over all gates in declOps and add them to the circuit
754 AddGateExpr addGate;
755 for (const auto &op : stmt.declOps) {
756 StatementType gateStmt =
757 addGate(op, qubitMap, opaqueGates, definedGates, variables);
758
759 // make each of them conditioned on the original condition
761 gateStmt.condValue = static_cast<int>(condValue);
762 gateStmt.cbits = stmt.cbits;
763
764 AddToCircuit(circuit, gateStmt, opaqueGates, definedGates);
765 }
766 }
767 }
768 } break;
773 case QoperationStatement::OperationType::
774 GateDecl: // do not generate anything here, it's already handled when
775 // the gate is called
776 default:
777 // those are ignored
778 break;
779 }
780 }
781};
782
783} // namespace qasm
784
785#endif // !_SYNTAXTREE_H_
static const std::shared_ptr< IQuantumGate< Time > > CreateGate(QuantumGateType type, size_t q1, size_t q2=0, size_t q3=0, double param1=0, double param2=0, double param3=0, double param4=0)
Construct a quantum gate.
static std::shared_ptr< IOperation< Time > > CreateConditionalGate(const std::shared_ptr< IGateOperation< Time > > &operation, const std::shared_ptr< ICondition > &condition)
Construct a conditional gate.
static std::shared_ptr< IOperation< Time > > CreateReset(const Types::qubits_vector &qubits={}, const std::vector< bool > &resetTgts={})
Construct a reset operation.
static const std::shared_ptr< IOperation< Time > > CreateMeasurement(const std::vector< std::pair< Types::qubit_t, size_t > > &qs={})
Construct a measurement operation.
static std::shared_ptr< ICondition > CreateEqualCondition(const std::vector< size_t > &ind, const std::vector< bool > &b)
Construct an equality condition.
Circuit class for holding the sequence of operations.
Definition Circuit.h:45
double Eval() const
Definition SimpleOps.h:29
std::string id
Definition SimpleOps.h:35
QuantumGateType
The type of quantum gates.
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
Definition Types.h:21
uint_fast64_t qubit_t
The type of a qubit.
Definition Types.h:20
phx::function< AddCondQopExpr > AddCondQop
Definition SyntaxTree.h:557
std::variant< UGateCallType, CXGateCallType, GatecallType > UopType
Definition SimpleOps.h:68
std::vector< ArgumentType > MixedListType
Definition SimpleOps.h:57
boost::fusion::vector< std::vector< std::string >, double, std::vector< std::string >, std::vector< StatementType > > ProgramType
Definition SimpleOps.h:104
boost::fusion::vector< std::string, int, QopType > CondOpType
Definition SimpleOps.h:113
phx::function< AddGateExpr > AddGate
Definition SyntaxTree.h:519
std::variant< std::string, IndexedId > ArgumentType
Definition SimpleOps.h:56
QoperationStatement StatementType
Definition SimpleOps.h:102
QoperationStatement type
Definition SyntaxTree.h:523
QoperationStatement operator()(CondOpType &condOp, const std::unordered_map< std::string, IndexedId > &qreg_map, const std::unordered_map< std::string, IndexedId > &creg_map, const std::unordered_map< std::string, StatementType > &opaqueGates, const std::unordered_map< std::string, StatementType > &definedGates) const
Definition SyntaxTree.h:527
QoperationStatement type
Definition SyntaxTree.h:23
static bool IsSuppportedGate(const std::string &gateName)
Definition SyntaxTree.h:417
static int GateNrQubits(Circuits::QuantumGateType gateType)
Definition SyntaxTree.h:494
static std::vector< int > ParseQubits(const ArgumentType &arg, const std::unordered_map< std::string, IndexedId > &qreg_map)
Definition SyntaxTree.h:378
static bool IsSuppportedOneParamGate(const std::string &gateName)
Definition SyntaxTree.h:408
static bool IsSuppportedMultipleParamsGate(const std::string &gateName)
Definition SyntaxTree.h:412
static bool IsSuppportedNoParamGate(const std::string &gateName)
Definition SyntaxTree.h:404
QoperationStatement operator()(const UopType &uop, const std::unordered_map< std::string, IndexedId > &qreg_map, const std::unordered_map< std::string, StatementType > &opaqueGates, const std::unordered_map< std::string, StatementType > &definedGates, const std::unordered_map< std::string, double > &variables={}) const
Definition SyntaxTree.h:26
Circuits::QuantumGateType GetGateType(const std::string &gateN) const
Definition SyntaxTree.h:424
std::shared_ptr< Circuits::Circuit< Time > > ToCircuit(std::unordered_map< std::string, StatementType > &opaqueGates, std::unordered_map< std::string, StatementType > &definedGates) const
Definition SyntaxTree.h:580
std::vector< StatementType > statements
Definition SyntaxTree.h:561
static void AddToCircuit(const std::shared_ptr< Circuits::Circuit< Time > > &circuit, const StatementType &stmt, std::unordered_map< std::string, StatementType > &opaqueGates, std::unordered_map< std::string, StatementType > &definedGates)
Definition SyntaxTree.h:593
std::vector< std::string > comments
Definition SyntaxTree.h:562
Program(const ProgramType &program={})
Definition SyntaxTree.h:565
std::vector< std::string > includes
Definition SyntaxTree.h:563
std::vector< UopType > declOps
Definition SimpleOps.h:99
std::vector< std::string > qubitsDecl
Definition SimpleOps.h:96
std::vector< double > parameters
Definition SimpleOps.h:93
std::vector< int > cbits
Definition SimpleOps.h:91
std::vector< std::string > paramsDecl
Definition SimpleOps.h:95
std::vector< int > qubits
Definition SimpleOps.h:90
Circuits::QuantumGateType gateType
Definition SimpleOps.h:84