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 {
35 if (std::holds_alternative<UGateCallType>(uop)) {
36 const auto &gate = std::get<UGateCallType>(uop);
37 const std::vector<Expression> ¶ms = boost::fusion::at_c<0>(gate);
42 for (
const auto &p : params)
46 }
else if (std::holds_alternative<CXGateCallType>(uop)) {
47 const auto &gate = std::get<CXGateCallType>(uop);
55 const std::vector<int> qubits1 =
ParseQubits(arg1, qreg_map);
56 const std::vector<int> qubits2 =
ParseQubits(arg2, qreg_map);
59 if (qubits1.size() == 1 && qubits2.size() == 1) {
61 stmt.
qubits.push_back(qubits1[0]);
62 stmt.
qubits.push_back(qubits2[0]);
63 }
else if (qubits1.size() == 1 && qubits2.size() > 1) {
65 for (
const auto &q2 : qubits2) {
67 throw std::invalid_argument(
68 "Control and target qubits cannot be the same for CX gate");
69 stmt.
qubits.push_back(qubits1[0]);
72 }
else if (qubits1.size() > 1 && qubits2.size() == 1) {
74 for (
const auto &q1 : qubits1) {
76 throw std::invalid_argument(
77 "Control and target qubits cannot be the same for CX gate");
79 stmt.
qubits.push_back(qubits2[0]);
81 }
else if (qubits1.size() == qubits2.size()) {
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]);
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);
96 if (std::holds_alternative<SimpleGatecallType>(gateCall)) {
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);
106 const auto it = definedGates.find(gateName);
107 if (it == definedGates.end()) {
109 throw std::invalid_argument(
110 "Unsupported gate without parameters: " + gateName);
114 if (args.size() != expectedNrQubits)
115 throw std::invalid_argument(
116 "Gate " + gateName +
" requires exactly " +
117 std::to_string(expectedNrQubits) +
" qubits");
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");
137 stmt.
declOps = definedGateStmt.declOps;
141 int qubitsCounter = 1;
143 std::vector<std::vector<int>> allQubits(args.size());
144 for (
int i = 0; i < static_cast<int>(args.size()); ++i) {
146 std::vector<int> qubits =
ParseQubits(arg, qreg_map);
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");
156 allQubits[i] = std::move(qubits);
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]);
165 stmt.
qubits.push_back(qlist[i]);
168 }
else if (std::holds_alternative<ExpGatecallType>(gateCall)) {
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);
176 const std::vector<Expression> ¶ms = boost::fusion::at_c<1>(gate);
179 for (
const auto &p : params)
182 const auto it = definedGates.find(gateName);
183 if (it == definedGates.end()) {
186 throw std::invalid_argument(
"Gate " + gateName +
187 " requires parameters");
188 else if (params.size() == 1) {
190 throw std::invalid_argument(
191 "This gate does not allow one parameter: " + gateName);
192 }
else if (params.size() > 1) {
194 throw std::invalid_argument(
195 "This gate does not allow multiple parameters: " +
198 if (params.size() > 4)
199 throw std::invalid_argument(
"Too many parameters for gate: " +
205 if (args.size() != expectedNrQubits)
206 throw std::invalid_argument(
207 "Gate " + gateName +
" requires exactly " +
208 std::to_string(expectedNrQubits) +
" qubits");
210 if (gateNameLower ==
"u1") {
215 }
else if (gateNameLower ==
"u2") {
222 }
else if (gateNameLower ==
"cu1") {
227 }
else if (gateNameLower ==
"cu2") {
235 }
else if (gateNameLower ==
"u1") {
239 throw std::invalid_argument(
240 "Gate u1 requires exactly one parameter");
247 if (args.size() != 1)
248 throw std::invalid_argument(
"Gate " + gateName +
249 " requires exactly 1 qubit");
250 }
else if (gateNameLower ==
"u2") {
254 throw std::invalid_argument(
"Gate u2 requires two parameters");
263 if (args.size() != 1)
264 throw std::invalid_argument(
"Gate " + gateName +
265 " requires exactly 1 qubit");
266 }
else if (gateNameLower ==
"u3") {
270 throw std::invalid_argument(
"Gate u3 requires three parameters");
273 if (args.size() != 1)
274 throw std::invalid_argument(
"Gate " + gateName +
275 " requires exactly 1 qubit");
276 }
else if (gateNameLower ==
"cu1") {
280 throw std::invalid_argument(
281 "Gate cu1 requires exactly one parameter");
288 if (args.size() != 2)
289 throw std::invalid_argument(
"Gate " + gateName +
290 " requires exactly 2 qubits");
291 }
else if (gateNameLower ==
"cu2") {
295 throw std::invalid_argument(
"Gate cu2 requires two parameters");
304 if (args.size() != 2)
305 throw std::invalid_argument(
"Gate " + gateName +
306 " requires exactly 2 qubits");
307 }
else if (gateNameLower ==
"cu3") {
311 throw std::invalid_argument(
"Gate cu3 requires three parameters");
314 if (args.size() != 2)
315 throw std::invalid_argument(
"Gate " + gateName +
316 " requires exactly 2 qubits");
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");
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 " +
340 stmt.
declOps = definedGateStmt.declOps;
344 int qubitsCounter = 1;
346 std::vector<std::vector<int>> allQubits(args.size());
347 for (
int i = 0; i < static_cast<int>(args.size()); ++i) {
349 std::vector<int> qubits =
ParseQubits(arg, qreg_map);
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");
359 allQubits[i] = std::move(qubits);
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]);
368 stmt.
qubits.push_back(qlist[i]);