Maestro 0.2.5
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
SyntaxTree.h
Go to the documentation of this file.
1
13#pragma once
14
15#ifndef _SYNTAXTREE_H_
16#define _SYNTAXTREE_H_
17
18#include "../Circuit/Factory.h"
19#include "SimpleOps.h"
20
21namespace qasm {
23 struct result {
25 };
26
28 const UopType &uop,
29 const std::unordered_map<std::string, IndexedId> &qreg_map,
30 const std::unordered_map<std::string, StatementType> &opaqueGates,
31 const std::unordered_map<std::string, StatementType> &definedGates,
32 const std::unordered_map<std::string, double> &variables = {}) const {
33 StatementType stmt;
35
36 if (std::holds_alternative<UGateCallType>(uop)) {
37 const auto &gate = std::get<UGateCallType>(uop);
38 const std::vector<Expression> &params = boost::fusion::at_c<0>(gate);
39 const ArgumentType &arg = boost::fusion::at_c<1>(gate);
40
42
43 for (const auto &p : params) 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 (static_cast<int>(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 (static_cast<int>(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 (static_cast<int>(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 (static_cast<int>(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> ParseQubits(
378 const ArgumentType &arg,
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) qubits.push_back(base + i);
397 }
398 }
399
400 return qubits;
401 }
402
403 static bool IsSuppportedNoParamGate(const std::string &gateName) {
404 return allowedNoParamGates.find(gateName) != allowedNoParamGates.end();
405 }
406
407 static bool IsSuppportedOneParamGate(const std::string &gateName) {
408 return allowedOneParamGates.find(gateName) != allowedOneParamGates.end();
409 }
410
411 static bool IsSuppportedMultipleParamsGate(const std::string &gateName) {
412 return allowedMultipleParamsGates.find(gateName) !=
413 allowedMultipleParamsGates.end();
414 }
415
416 static bool IsSuppportedGate(const std::string &gateName) {
417 return allowedNoParamGates.find(gateName) != allowedNoParamGates.end() ||
418 allowedOneParamGates.find(gateName) != allowedOneParamGates.end() ||
419 allowedMultipleParamsGates.find(gateName) !=
420 allowedMultipleParamsGates.end();
421 }
422
423 Circuits::QuantumGateType GetGateType(const std::string &gateN) const {
424 std::string gateName = gateN;
425 std::transform(gateName.begin(), gateName.end(), gateName.begin(),
426 ::tolower);
427
428 if (gateName == "x")
430 else if (gateName == "y")
432 else if (gateName == "z")
434 else if (gateName == "h")
436 else if (gateName == "s")
438 else if (gateName == "sdg" || gateName == "sxdag")
440 else if (gateName == "t")
442 else if (gateName == "tdg" || gateName == "tdag")
444 else if (gateName == "sx")
446 else if (gateName == "sxdg" || gateName == "sxdag")
448 else if (gateName == "k")
450 else if (gateName == "swap")
452 else if (gateName == "cx")
454 else if (gateName == "cy")
456 else if (gateName == "cz")
458 else if (gateName == "ch")
460 else if (gateName == "csx")
462 else if (gateName == "csxdg" || gateName == "csxdag")
464 else if (gateName == "cswap")
466 else if (gateName == "ccx")
468 else if (gateName == "p")
470 else if (gateName == "rx")
472 else if (gateName == "ry")
474 else if (gateName == "rz")
476 else if (gateName == "cp")
478 else if (gateName == "crx")
480 else if (gateName == "cry")
482 else if (gateName == "crz")
484 else if (gateName == "u" || gateName == "u3" || gateName == "u1")
486 else if (gateName == "cu" || gateName == "cu3" || gateName == "cu1")
488
489 return Circuits::QuantumGateType::kNone; // this will be returnd also for
490 // 'id'
491 }
492
494 const int gateT = static_cast<int>(gateType);
495
496 if (gateT < static_cast<int>(Circuits::QuantumGateType::kSwapGateType))
497 return 1;
498 else if (gateT <
500 return 2;
501 else if (gateT <= static_cast<int>(Circuits::QuantumGateType::kCCXGateType))
502 return 3;
503
504 return 0;
505 }
506
507 private:
508 static inline std::unordered_set<std::string> allowedNoParamGates = {
509 "x", "y", "z", "h", "s", "sdg", "sdag", "t", "tdg",
510 "tdag", "sx", "sxdg", "sxdag", "k", "swap", "cx", "cy", "cz",
511 "ch", "csx", "csxdg", "csxdag", "cswap", "ccx", "id"};
512 static inline std::unordered_set<std::string> allowedOneParamGates = {
513 "p", "rx", "ry", "rz", "cp", "crx", "cry", "crz", "u1", "cu1"};
514 static inline std::unordered_set<std::string> allowedMultipleParamsGates = {
515 "u", "u3", "cu1", "cu3"}; // max 4
516};
517
518phx::function<AddGateExpr> AddGate;
519
521 struct result {
523 };
524
526 CondOpType &condOp,
527 const std::unordered_map<std::string, IndexedId> &qreg_map,
528 const std::unordered_map<std::string, IndexedId> &creg_map,
529 const std::unordered_map<std::string, StatementType> &opaqueGates,
530 const std::unordered_map<std::string, StatementType> &definedGates)
531 const {
532 StatementType stmt;
533
534 const std::string &condId = boost::fusion::at_c<0>(condOp);
535 int condVal = boost::fusion::at_c<1>(condOp);
536 const QoperationStatement &op = boost::fusion::at_c<2>(condOp);
537
538 stmt = op;
539
541 stmt.condValue = condVal;
542
543 if (creg_map.find(condId) == creg_map.end())
544 throw std::invalid_argument("Condition register not found: " + condId);
545 else {
546 const IndexedId &condCreg = creg_map.at(condId);
547
548 for (int c = 0; c < condCreg.Eval(); ++c)
549 stmt.cbits.push_back(condCreg.base + c);
550 }
551
552 return stmt;
553 }
554};
555
556phx::function<AddCondQopExpr> AddCondQop;
557
558struct Program {
559 double version = 2.0;
560 std::vector<StatementType> statements;
561 std::vector<std::string> comments;
562 std::vector<std::string> includes;
563
564 Program(const ProgramType &program = {}) {
565 comments = boost::fusion::at_c<0>(program);
566 version = boost::fusion::at_c<1>(program);
567 includes = boost::fusion::at_c<2>(program);
568 statements = boost::fusion::at_c<3>(program);
569 }
570
571 void clear() {
572 comments.clear();
573 includes.clear();
574 statements.clear();
575 version = 2.0;
576 }
577
578 template <typename Time = Types::time_type>
579 std::shared_ptr<Circuits::Circuit<Time>> ToCircuit(
580 std::unordered_map<std::string, StatementType> &opaqueGates,
581 std::unordered_map<std::string, StatementType> &definedGates) const {
582 auto circuit = std::make_shared<Circuits::Circuit<Time>>();
583
584 for (const auto &stmt : statements)
585 AddToCircuit(circuit, stmt, opaqueGates, definedGates);
586
587 return circuit;
588 }
589
590 template <typename Time = Types::time_type>
591 static void AddToCircuit(
592 const std::shared_ptr<Circuits::Circuit<Time>> &circuit,
593 const StatementType &stmt,
594 std::unordered_map<std::string, StatementType> &opaqueGates,
595 std::unordered_map<std::string, StatementType> &definedGates) {
596 switch (stmt.opType) {
598 if (stmt.qubits.size() != stmt.cbits.size())
599 throw std::invalid_argument(
600 "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(
628 "Uop operation: number of qubits does "
629 "not match the gate requirements.");
630
631 for (int pos = 0; pos < static_cast<int>(stmt.qubits.size());
632 pos += nrQubits) {
633 Types::qubits_vector gateQubits;
634 for (int q = 0; q < nrQubits; ++q)
635 gateQubits.push_back(
636 static_cast<Types::qubit_t>(stmt.qubits[pos + q]));
637
639 stmt.gateType, gateQubits[0], nrQubits > 1 ? gateQubits[1] : 0,
640 nrQubits > 2 ? gateQubits[2] : 0, param1, param2, param3,
641 param4);
642
643 circuit->AddOperation(gateOp);
644 }
645 } else {
646 // it's a defined gate, check further and implement
647 // will add several gates to the circuit
648 if (stmt.paramsDecl.size() != stmt.parameters.size())
649 throw std::invalid_argument(
650 "Uop operation: number of parameters do "
651 "not match the declaration.");
652
653 std::unordered_map<std::string, double> variables;
654
655 for (size_t i = 0; i < stmt.paramsDecl.size(); ++i)
656 variables[stmt.paramsDecl[i]] = stmt.parameters[i];
657
658 int nrQubits = static_cast<int>(stmt.qubitsDecl.size());
659 if (stmt.qubits.size() % nrQubits != 0)
660 throw std::invalid_argument(
661 "Defined Uop operation: number of qubits "
662 "does not match the gate requirements.");
663
664 for (int pos = 0; pos < static_cast<int>(stmt.qubits.size());
665 pos += nrQubits) {
666 std::unordered_map<std::string, IndexedId> qubitMap;
667 for (int q = 0; q < nrQubits; ++q) {
668 IndexedId id;
669 id.id = stmt.qubitsDecl[q];
670 id.base = stmt.qubits[pos + q];
671 id.index = 1;
672 qubitMap[id.id] = id;
673 }
674
675 // now walk over all gates in declOps and add them to the circuit
676 AddGateExpr addGate;
677 for (const auto &op : stmt.declOps) {
678 StatementType gateStmt =
679 addGate(op, qubitMap, opaqueGates, definedGates, variables);
680
681 AddToCircuit(circuit, gateStmt, opaqueGates, definedGates);
682 }
683 }
684 }
685 } break;
687 unsigned long long int condValue =
688 static_cast<unsigned long long int>(stmt.condValue);
689
691 // can add more than one gate here depending on what's in qubits
692 double param1 = stmt.parameters.size() > 0 ? stmt.parameters[0] : 0;
693 double param2 = stmt.parameters.size() > 1 ? stmt.parameters[1] : 0;
694 double param3 = stmt.parameters.size() > 2 ? stmt.parameters[2] : 0;
695 double param4 = stmt.parameters.size() > 3 ? stmt.parameters[3] : 0;
696
697 int nrQubits = AddGateExpr::GateNrQubits(stmt.gateType);
698 if (stmt.qubits.size() % nrQubits != 0)
699 throw std::invalid_argument(
700 "Uop operation: number of qubits does "
701 "not match the gate requirements.");
702
703 std::vector<size_t> ind;
704 std::vector<bool> condBits;
705
706 for (size_t i = 0; i < stmt.cbits.size(); ++i) {
707 ind.push_back(static_cast<size_t>(stmt.cbits[i]));
708 condBits.push_back((condValue & 1) == 1);
709 condValue >>= 1;
710 }
711
712 const auto condition =
714 condBits);
715
716 for (int pos = 0; pos < static_cast<int>(stmt.qubits.size());
717 pos += nrQubits) {
718 Types::qubits_vector gateQubits;
719 for (int q = 0; q < nrQubits; ++q)
720 gateQubits.push_back(
721 static_cast<Types::qubit_t>(stmt.qubits[pos + q]));
722
724 stmt.gateType, gateQubits[0], nrQubits > 1 ? gateQubits[1] : 0,
725 nrQubits > 2 ? gateQubits[2] : 0, param1, param2, param3,
726 param4);
727
729 gateOp, condition);
730 circuit->AddOperation(condOp);
731 }
732 } else {
733 // it's a defined gate, check further and implement
734 // will add several gates to the circuit
735 if (stmt.paramsDecl.size() != stmt.parameters.size())
736 throw std::invalid_argument(
737 "Uop operation: number of parameters do "
738 "not match the declaration.");
739
740 std::unordered_map<std::string, double> variables;
741
742 for (size_t i = 0; i < stmt.paramsDecl.size(); ++i)
743 variables[stmt.paramsDecl[i]] = stmt.parameters[i];
744
745 int nrQubits = static_cast<int>(stmt.qubitsDecl.size());
746 if (stmt.qubits.size() % nrQubits != 0)
747 throw std::invalid_argument(
748 "Defined Uop operation: number of qubits "
749 "does not match the gate requirements.");
750
751 for (int pos = 0; pos < static_cast<int>(stmt.qubits.size());
752 pos += nrQubits) {
753 std::unordered_map<std::string, IndexedId> qubitMap;
754 for (int q = 0; q < nrQubits; ++q) {
755 IndexedId id;
756 id.id = stmt.qubitsDecl[q];
757 id.base = stmt.qubits[pos + q];
758 id.index = 1;
759 qubitMap[id.id] = id;
760 }
761
762 // now walk over all gates in declOps and add them to the circuit
763 AddGateExpr addGate;
764 for (const auto &op : stmt.declOps) {
765 StatementType gateStmt =
766 addGate(op, qubitMap, opaqueGates, definedGates, variables);
767
768 // make each of them conditioned on the original condition
770 gateStmt.condValue = static_cast<int>(condValue);
771 gateStmt.cbits = stmt.cbits;
772
773 AddToCircuit(circuit, gateStmt, opaqueGates, definedGates);
774 }
775 }
776 }
777 } break;
783 GateDecl: // do not generate anything here, it's already handled when
784 // the gate is called
785 default:
786 // those are ignored
787 break;
788 }
789 }
790};
791
792} // namespace qasm
793
794#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:46
virtual double Eval() const
Definition Expr.h:44
double Eval() const
Definition SimpleOps.h:30
std::string id
Definition SimpleOps.h:36
QuantumGateType
The type of quantum gates.
uint_fast64_t qubit_t
The type of a qubit.
Definition Types.h:21
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
Definition Types.h:23
phx::function< AddCondQopExpr > AddCondQop
Definition SyntaxTree.h:556
std::variant< std::string, IndexedId > ArgumentType
Definition SimpleOps.h:58
QoperationStatement StatementType
Definition SimpleOps.h:104
std::variant< UGateCallType, CXGateCallType, GatecallType > UopType
Definition SimpleOps.h:70
boost::fusion::vector< std::string, int, QopType > CondOpType
Definition SimpleOps.h:115
phx::function< AddGateExpr > AddGate
Definition SyntaxTree.h:518
boost::fusion::vector< std::vector< std::string >, double, std::vector< std::string >, std::vector< StatementType > > ProgramType
Definition SimpleOps.h:108
std::vector< ArgumentType > MixedListType
Definition SimpleOps.h:59
QoperationStatement type
Definition SyntaxTree.h:522
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:525
static bool IsSuppportedGate(const std::string &gateName)
Definition SyntaxTree.h:416
static int GateNrQubits(Circuits::QuantumGateType gateType)
Definition SyntaxTree.h:493
static std::vector< int > ParseQubits(const ArgumentType &arg, const std::unordered_map< std::string, IndexedId > &qreg_map)
Definition SyntaxTree.h:377
QoperationStatement type
Definition SyntaxTree.h:24
static bool IsSuppportedOneParamGate(const std::string &gateName)
Definition SyntaxTree.h:407
static bool IsSuppportedMultipleParamsGate(const std::string &gateName)
Definition SyntaxTree.h:411
static bool IsSuppportedNoParamGate(const std::string &gateName)
Definition SyntaxTree.h:403
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:27
Circuits::QuantumGateType GetGateType(const std::string &gateN) const
Definition SyntaxTree.h:423
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:579
std::vector< StatementType > statements
Definition SyntaxTree.h:560
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:591
std::vector< std::string > comments
Definition SyntaxTree.h:561
Program(const ProgramType &program={})
Definition SyntaxTree.h:564
std::vector< std::string > includes
Definition SyntaxTree.h:562
std::vector< UopType > declOps
Definition SimpleOps.h:101
std::vector< std::string > qubitsDecl
Definition SimpleOps.h:98
std::vector< double > parameters
Definition SimpleOps.h:95
std::vector< int > cbits
Definition SimpleOps.h:93
std::vector< std::string > paramsDecl
Definition SimpleOps.h:97
std::vector< int > qubits
Definition SimpleOps.h:92
Circuits::QuantumGateType gateType
Definition SimpleOps.h:86