26 const std::unordered_map<std::string, double> &variables) {
27 const double value = parameter.
Eval(variables);
28 if (!std::isfinite(value))
29 throw std::invalid_argument(
"Gate parameters must be finite, got: " +
30 std::to_string(value));
41 const std::unordered_map<std::string, IndexedId> &qreg_map,
42 const std::unordered_map<std::string, StatementType> &opaqueGates,
43 const std::unordered_map<std::string, StatementType> &definedGates,
44 const std::unordered_map<std::string, double> &variables = {})
const {
48 if (std::holds_alternative<UGateCallType>(uop)) {
49 const auto &gate = std::get<UGateCallType>(uop);
50 const std::vector<Expression> ¶ms = boost::fusion::at_c<0>(gate);
55 for (
const auto &p : params)
59 }
else if (std::holds_alternative<CXGateCallType>(uop)) {
60 const auto &gate = std::get<CXGateCallType>(uop);
68 const std::vector<int> qubits1 =
ParseQubits(arg1, qreg_map);
69 const std::vector<int> qubits2 =
ParseQubits(arg2, qreg_map);
72 if (qubits1.size() == 1 && qubits2.size() == 1) {
74 stmt.
qubits.push_back(qubits1[0]);
75 stmt.
qubits.push_back(qubits2[0]);
76 }
else if (qubits1.size() == 1 && qubits2.size() > 1) {
78 for (
const auto &q2 : qubits2) {
80 throw std::invalid_argument(
81 "Control and target qubits cannot be the same for CX gate");
82 stmt.
qubits.push_back(qubits1[0]);
85 }
else if (qubits1.size() > 1 && qubits2.size() == 1) {
87 for (
const auto &q1 : qubits1) {
89 throw std::invalid_argument(
90 "Control and target qubits cannot be the same for CX gate");
92 stmt.
qubits.push_back(qubits2[0]);
94 }
else if (qubits1.size() == qubits2.size()) {
96 for (
size_t i = 0; i < qubits1.size(); ++i) {
97 if (qubits1[i] == qubits2[i])
98 throw std::invalid_argument(
99 "Control and target qubits cannot be the same for CX gate");
100 stmt.
qubits.push_back(qubits1[i]);
101 stmt.
qubits.push_back(qubits2[i]);
104 throw std::invalid_argument(
105 "Mismatched qubits sizes for CX gate arguments");
106 }
else if (std::holds_alternative<GatecallType>(uop)) {
107 const auto &gateCall = std::get<GatecallType>(uop);
109 if (std::holds_alternative<SimpleGatecallType>(gateCall)) {
111 const auto &gate = std::get<SimpleGatecallType>(gateCall);
112 const std::string &gateName = boost::fusion::at_c<0>(gate);
130 const auto it = definedGates.find(gateName);
131 if (it == definedGates.end()) {
133 throw std::invalid_argument(
134 "Unsupported gate without parameters: " + gateName);
143 throw std::invalid_argument(
"Gate " + gateName +
144 " requires parameters");
164 const int expectedNrQubits =
166 if (
static_cast<int>(args.size()) != expectedNrQubits)
167 throw std::invalid_argument(
168 "Gate " + gateName +
" requires exactly " +
169 std::to_string(expectedNrQubits) +
" qubits");
173 const int expectedNrQubits =
174 static_cast<int>(definedGateStmt.qubitsDecl.size());
175 if (
static_cast<int>(args.size()) != expectedNrQubits)
176 throw std::invalid_argument(
177 "Defined gate " + gateName +
" requires exactly " +
178 std::to_string(expectedNrQubits) +
" qubits");
179 if (definedGateStmt.parameters.size() != 0)
180 throw std::invalid_argument(
181 "Defined gate " + gateName +
182 " requires parameters, but none were provided");
189 stmt.
declOps = definedGateStmt.declOps;
193 int qubitsCounter = 1;
195 std::vector<std::vector<int>> allQubits(args.size());
196 for (
int i = 0; i < static_cast<int>(args.size()); ++i) {
198 std::vector<int> qubits =
ParseQubits(arg, qreg_map);
200 if (qubits.size() != 1) {
201 if (qubitsCounter == 1)
202 qubitsCounter =
static_cast<int>(qubits.size());
203 else if (qubitsCounter !=
static_cast<int>(qubits.size()))
204 throw std::invalid_argument(
205 "Mismatched qubits sizes for gate arguments");
208 allQubits[i] = std::move(qubits);
212 for (
int i = 0; i < qubitsCounter; ++i) {
213 for (
const auto &qlist : allQubits) {
214 if (qlist.size() == 1)
215 stmt.
qubits.push_back(qlist[0]);
217 stmt.
qubits.push_back(qlist[i]);
220 }
else if (std::holds_alternative<ExpGatecallType>(gateCall)) {
222 const auto &gate = std::get<ExpGatecallType>(gateCall);
223 const std::string &gateName = boost::fusion::at_c<0>(gate);
225 const std::vector<Expression> ¶ms = boost::fusion::at_c<1>(gate);
228 for (
const auto &p : params)
234 const auto it = definedGates.find(gateName);
235 if (it == definedGates.end()) {
238 throw std::invalid_argument(
"Gate " + gateName +
239 " requires parameters");
240 else if (params.size() == 1) {
242 throw std::invalid_argument(
243 "This gate does not allow one parameter: " + gateName);
244 }
else if (params.size() > 1) {
246 throw std::invalid_argument(
247 "This gate does not allow multiple parameters: " +
250 if (params.size() > 4)
251 throw std::invalid_argument(
"Too many parameters for gate: " +
257 if (
static_cast<int>(args.size()) != expectedNrQubits)
258 throw std::invalid_argument(
259 "Gate " + gateName +
" requires exactly " +
260 std::to_string(expectedNrQubits) +
" qubits");
262 if (gateName ==
"u1") {
267 }
else if (gateName ==
"u2") {
274 }
else if (gateName ==
"cu1") {
279 }
else if (gateName ==
"cu2") {
287 }
else if (gateName ==
"u2") {
295 throw std::invalid_argument(
"Gate u2 requires two parameters");
304 if (args.size() != 1)
305 throw std::invalid_argument(
"Gate " + gateName +
306 " requires exactly 1 qubit");
307 }
else if (gateName ==
"cu2") {
311 throw std::invalid_argument(
"Gate cu2 requires two parameters");
320 if (args.size() != 2)
321 throw std::invalid_argument(
"Gate " + gateName +
322 " requires exactly 2 qubits");
324 throw std::invalid_argument(
"Unsupported gate with parameters: " +
330 const int expectedNrQubits =
331 static_cast<int>(definedGateStmt.qubitsDecl.size());
332 if (
static_cast<int>(args.size()) != expectedNrQubits)
333 throw std::invalid_argument(
334 "Defined gate " + gateName +
" requires exactly " +
335 std::to_string(expectedNrQubits) +
" qubits");
337 if (definedGateStmt.paramsDecl.size() != stmt.
parameters.size())
338 throw std::invalid_argument(
339 "Defined gate " + gateName +
" requires a different number (" +
340 std::to_string(definedGateStmt.paramsDecl.size()) +
341 ") of parameters than " +
349 stmt.
declOps = definedGateStmt.declOps;
353 int qubitsCounter = 1;
355 std::vector<std::vector<int>> allQubits(args.size());
356 for (
int i = 0; i < static_cast<int>(args.size()); ++i) {
358 std::vector<int> qubits =
ParseQubits(arg, qreg_map);
360 if (qubits.size() != 1) {
361 if (qubitsCounter == 1)
362 qubitsCounter =
static_cast<int>(qubits.size());
363 else if (qubitsCounter !=
static_cast<int>(qubits.size()))
364 throw std::invalid_argument(
365 "Mismatched qubits sizes for gate arguments");
368 allQubits[i] = std::move(qubits);
372 for (
int i = 0; i < qubitsCounter; ++i) {
373 for (
const auto &qlist : allQubits) {
374 if (qlist.size() == 1)
375 stmt.
qubits.push_back(qlist[0]);
377 stmt.
qubits.push_back(qlist[i]);
388 const std::unordered_map<std::string, IndexedId> &qreg_map) {
393 return allowedNoParamGates.find(gateName) != allowedNoParamGates.end();
397 return allowedOneParamGates.find(gateName) != allowedOneParamGates.end();
401 return allowedMultipleParamsGates.find(gateName) !=
402 allowedMultipleParamsGates.end();
406 return allowedNoParamGates.find(gateName) != allowedNoParamGates.end() ||
407 allowedOneParamGates.find(gateName) != allowedOneParamGates.end() ||
408 allowedMultipleParamsGates.find(gateName) !=
409 allowedMultipleParamsGates.end();
423 else if (gateName ==
"y")
425 else if (gateName ==
"z")
427 else if (gateName ==
"h")
429 else if (gateName ==
"s")
431 else if (gateName ==
"sdg" || gateName ==
"sdag")
433 else if (gateName ==
"t")
435 else if (gateName ==
"tdg" || gateName ==
"tdag")
437 else if (gateName ==
"sx")
439 else if (gateName ==
"sxdg" || gateName ==
"sxdag")
441 else if (gateName ==
"k")
443 else if (gateName ==
"swap")
445 else if (gateName ==
"cx" || gateName ==
"CX")
447 else if (gateName ==
"cy")
449 else if (gateName ==
"cz")
451 else if (gateName ==
"ch")
453 else if (gateName ==
"csx")
455 else if (gateName ==
"csxdg" || gateName ==
"csxdag")
457 else if (gateName ==
"cswap")
459 else if (gateName ==
"ccx")
461 else if (gateName ==
"p" || gateName ==
"phase")
463 else if (gateName ==
"rx")
465 else if (gateName ==
"ry")
467 else if (gateName ==
"rz")
469 else if (gateName ==
"cp" || gateName ==
"cphase")
471 else if (gateName ==
"crx")
473 else if (gateName ==
"cry")
475 else if (gateName ==
"crz")
477 else if (gateName ==
"U" || gateName ==
"u" || gateName ==
"u3" ||
480 else if (gateName ==
"cu" || gateName ==
"cu3" || gateName ==
"cu1")
492 const int gateT =
static_cast<int>(gateType);
510 return allowedNoParamGates;
514 return allowedOneParamGates;
518 return allowedMultipleParamsGates;
530 static inline std::unordered_set<std::string> allowedNoParamGates = {
531 "x",
"y",
"z",
"h",
"s",
"sdg",
"sdag",
"t",
"tdg",
532 "tdag",
"sx",
"sxdg",
"sxdag",
"k",
"swap",
"cx",
"CX",
"cy",
533 "cz",
"ch",
"csx",
"csxdg",
"csxdag",
"cswap",
"ccx",
"id"};
534 static inline std::unordered_set<std::string> allowedOneParamGates = {
535 "p",
"rx",
"ry",
"rz",
"cp",
"crx",
"cry",
536 "crz",
"u1",
"cu1",
"phase",
"cphase",
"gphase"};
539 static inline std::unordered_set<std::string> allowedMultipleParamsGates = {
540 "u",
"U",
"u3",
"cu",
"cu3"};
558 const std::unordered_map<std::string, IndexedId> &qreg_map,
559 const std::unordered_map<std::string, StatementType> &opaqueGates,
560 const std::unordered_map<std::string, StatementType> &definedGates,
561 const std::unordered_map<std::string, double> &variables = {})
const {
563 const UopType &uop = boost::fusion::at_c<1>(modifiedUop);
566 if (modifiers.empty())
567 return addGate(uop, qreg_map, opaqueGates, definedGates, variables);
569 std::string gateName;
570 std::vector<double> params;
574 if (definedGates.find(gateName) != definedGates.end())
575 throw std::invalid_argument(
576 "Gate modifiers cannot be applied to the user-defined gate: " +
585 std::string canonicalName = gateName;
592 size_t nrControls = 0;
593 for (
const auto &modifier : modifiers)
595 nrControls +=
static_cast<size_t>(modifier.count);
598 throw std::invalid_argument(
599 "ctrl @ with more than two controls is not supported, " +
600 std::to_string(nrControls) +
601 " were requested for the gate: " + canonicalName);
607 if (canonicalName ==
"id") {
608 static constexpr const char *validationGates[] = {
"id",
"cx",
"ccx"};
609 addGate(
MakeCall(validationGates[nrControls], params, args), qreg_map,
610 opaqueGates, definedGates);
619 for (
auto it = modifiers.rbegin(); it != modifiers.rend(); ++it) {
625 ApplyPow(it->exponent, canonicalName, params, repetitions);
632 for (
int c = 0; c < it->count; ++c)
ApplyCtrl(canonicalName, params);
640 qreg_map, opaqueGates, definedGates);
647 const std::vector<int> singleRound = stmt.qubits;
648 for (
int r = 1; r < repetitions; ++r)
649 stmt.qubits.insert(stmt.qubits.end(), singleRound.begin(),
652 const std::vector<size_t> negatedControls =
NegatedControls(modifiers);
653 if (negatedControls.empty())
return stmt;
666 std::vector<size_t> negatedControls;
667 size_t controlPos = 0;
669 for (
const auto &modifier : modifiers) {
671 for (
int c = 0; c < modifier.count; ++c, ++controlPos)
673 negatedControls.push_back(controlPos);
676 return negatedControls;
688 const std::vector<double> ¶ms,
689 const std::vector<size_t> &negatedControls) {
696 for (
int q = 0; q < nrQubits; ++q)
697 stmt.
qubitsDecl.push_back(
"__negctrl_q" + std::to_string(q));
704 for (
const size_t control : negatedControls)
707 for (
const auto &flipArg : flipArgs)
710 for (
const auto &flipArg : flipArgs)
730 const UopType &uop, std::string &gateName, std::vector<double> ¶ms,
732 const std::unordered_map<std::string, double> &variables) {
733 if (std::holds_alternative<UGateCallType>(uop)) {
734 const auto &gate = std::get<UGateCallType>(uop);
736 for (
const auto &p : boost::fusion::at_c<0>(gate))
738 args.push_back(boost::fusion::at_c<1>(gate));
739 }
else if (std::holds_alternative<CXGateCallType>(uop)) {
740 const auto &gate = std::get<CXGateCallType>(uop);
742 args.push_back(boost::fusion::at_c<0>(gate));
743 args.push_back(boost::fusion::at_c<1>(gate));
745 const auto &gateCall = std::get<GatecallType>(uop);
746 if (std::holds_alternative<SimpleGatecallType>(gateCall)) {
747 const auto &gate = std::get<SimpleGatecallType>(gateCall);
748 gateName = boost::fusion::at_c<0>(gate);
749 args = boost::fusion::at_c<1>(gate);
751 const auto &gate = std::get<ExpGatecallType>(gateCall);
752 gateName = boost::fusion::at_c<0>(gate);
753 for (
const auto &p : boost::fusion::at_c<1>(gate))
755 args = boost::fusion::at_c<2>(gate);
767 static const std::unordered_map<std::string, std::string> aliases = {
768 {
"phase",
"p"}, {
"cphase",
"cp"}, {
"u3",
"u"},
769 {
"cu3",
"cu"}, {
"sdag",
"sdg"}, {
"sxdag",
"sxdg"},
770 {
"tdag",
"tdg"}, {
"csxdag",
"csxdg"}};
772 const auto it = aliases.find(gateName);
773 if (it != aliases.end()) gateName = it->second;
780 const std::vector<double> ¶ms,
784 std::vector<Expression> paramExprs;
800 static void ApplyInv(std::string &gateName, std::vector<double> ¶ms) {
801 static const std::unordered_set<std::string> selfInverseGates = {
802 "x",
"y",
"z",
"h",
"cx",
"cy",
"cz",
"ch",
"swap",
"cswap",
"ccx"};
803 static const std::unordered_map<std::string, std::string> daggerGates = {
804 {
"s",
"sdg"}, {
"sdg",
"s"}, {
"t",
"tdg"}, {
"tdg",
"t"},
805 {
"sx",
"sxdg"}, {
"sxdg",
"sx"}, {
"csx",
"csxdg"}, {
"csxdg",
"csx"}};
807 if (selfInverseGates.find(gateName) != selfInverseGates.end())
return;
809 const auto daggerIt = daggerGates.find(gateName);
810 if (daggerIt != daggerGates.end()) {
811 gateName = daggerIt->second;
815 if (rotationGates.find(gateName) != rotationGates.end()) {
816 for (
auto &p : params) p = -p;
820 if (gateName ==
"u" || gateName ==
"cu") {
825 params.resize(std::max<size_t>(params.size(), 3), 0.);
826 std::swap(params[1], params[2]);
827 for (
auto &p : params) p = -p;
831 throw std::invalid_argument(
"inv @ is not supported for the gate: " +
835 static void ApplyPow(
double exponent, std::string &gateName,
836 std::vector<double> ¶ms,
int &repetitions) {
837 if (!std::isfinite(exponent))
838 throw std::invalid_argument(
839 "pow(k) @ requires a finite exponent for "
846 exponent = -exponent;
849 if (exponent == 0.) {
856 if (rotationGates.find(gateName) != rotationGates.end()) {
857 for (
auto &p : params) p *= exponent;
861 const double rounded = std::round(exponent);
862 if (std::abs(exponent - rounded) > 1e-12)
863 throw std::invalid_argument(
864 "pow(k) @ with a fractional exponent is not supported for the "
871 if (rounded >
static_cast<double>(kMaxRepetitions) ||
872 static_cast<double>(repetitions) * rounded >
873 static_cast<double>(kMaxRepetitions))
874 throw std::invalid_argument(
875 "pow(k) @ with an exponent above " + std::to_string(kMaxRepetitions) +
876 " is not supported for the gate: " + gateName);
878 repetitions *=
static_cast<int>(rounded);
881 static void ApplyCtrl(std::string &gateName, std::vector<double> ¶ms) {
882 static const std::unordered_map<std::string, std::string> controlledGates =
883 {{
"x",
"cx"}, {
"y",
"cy"}, {
"z",
"cz"}, {
"h",
"ch"},
884 {
"sx",
"csx"}, {
"sxdg",
"csxdg"}, {
"p",
"cp"}, {
"rx",
"crx"},
885 {
"ry",
"cry"}, {
"rz",
"crz"}, {
"swap",
"cswap"}, {
"cx",
"ccx"}};
889 static const std::unordered_map<std::string, double> phaseAngles = {
893 {
"tdg", -M_PI / 4.}};
895 if (gateName ==
"gphase")
896 throw std::invalid_argument(
897 "Controlled global phase ('ctrl @ gphase') is not supported by "
900 if (gateName ==
"u") {
903 params.resize(std::max<size_t>(params.size(), 3), 0.);
908 const auto controlledIt = controlledGates.find(gateName);
909 if (controlledIt != controlledGates.end()) {
910 gateName = controlledIt->second;
914 const auto phaseIt = phaseAngles.find(gateName);
915 if (phaseIt != phaseAngles.end()) {
917 params.assign(1, phaseIt->second);
921 throw std::invalid_argument(
"ctrl @ is not supported for the gate: " +
933 static inline std::unordered_set<std::string> rotationGates = {
934 "rx",
"ry",
"rz",
"p",
"cp",
"crx",
"cry",
"crz"};
937 static constexpr int kMaxRepetitions = 1024;
954 throw std::invalid_argument(
955 "Gate modifiers (ctrl, negctrl, inv, pow) are not supported inside a "
956 "gate declaration body");
976 throw std::invalid_argument(message);
1000 template <
typename,
typename>
1006 const std::unordered_map<std::string, StatementType>
1007 &definedGates)
const {
1008 if (definedGates.find(gateName) != definedGates.end())
return false;
1010 const std::string qasm2Spelling = gateName ==
"phase" ?
"p"
1011 : gateName ==
"cphase" ?
"cp"
1014 throw std::invalid_argument(
1016 "' is an OpenQASM 3 stdgates.inc gate and is not available under "
1018 (qasm2Spelling.empty()
1019 ?
" (it has no qelib1.inc equivalent)"
1020 :
"; the qelib1.inc spelling is '" + qasm2Spelling +
"'"));
1026template <
class Time>
1028 const std::vector<int> &conditionBits,
1029 const std::vector<bool> &expectedValues) {
1030 if (conditionBits.size() != expectedValues.size())
1031 throw std::invalid_argument(
1032 "Condition bit indices and expected values must have the same width.");
1034 std::vector<size_t> ind;
1035 ind.reserve(conditionBits.size());
1036 for (
const int bit : conditionBits) ind.push_back(
static_cast<size_t>(bit));
1043 const std::string ®isterName,
int value,
size_t width) {
1045 throw std::invalid_argument(
"Condition value for classical register '" +
1046 registerName +
"' must be non-negative.");
1048 const auto unsignedValue =
static_cast<unsigned int>(value);
1049 if (width < std::numeric_limits<unsigned int>::digits &&
1050 unsignedValue >= (1u << width))
1051 throw std::invalid_argument(
"Condition value " + std::to_string(value) +
1052 " does not fit classical register '" +
1053 registerName +
"' of width " +
1054 std::to_string(width) +
".");
1056 std::vector<bool> expected(width,
false);
1057 auto remaining = unsignedValue;
1058 for (
size_t bit = 0; bit < width && remaining != 0; ++bit) {
1059 expected[bit] = (remaining & 1u) != 0;
1068 const std::vector<int> &conditionBits,
1069 const std::vector<bool> &expectedValues) {
1078 stmt.
cbits = conditionBits;
1088 const std::unordered_map<std::string, IndexedId> &qreg_map,
1089 const std::unordered_map<std::string, IndexedId> &creg_map,
1090 const std::unordered_map<std::string, StatementType> &opaqueGates,
1091 const std::unordered_map<std::string, StatementType> &definedGates)
1095 const std::string &condId = boost::fusion::at_c<0>(condOp);
1096 int condVal = boost::fusion::at_c<1>(condOp);
1101 const std::vector<int> conditionBits =
1104 stmt, conditionBits,
1117 typedef std::vector<QoperationStatement>
type;
1121 const std::vector<QopType> &body,
const std::vector<int> &absoluteBits,
1122 const std::vector<bool> &expectedValues)
const {
1123 std::vector<QoperationStatement> stmts;
1124 stmts.reserve(body.size());
1126 for (
const auto &bodyStmt : body) {
1129 stmts.push_back(stmt);
1137 const std::vector<QopType> &body,
const std::vector<int> &conditionBits,
1138 bool followedByElse, std::string_view branchName) {
1139 for (
size_t statementIndex = 0; statementIndex < body.size();
1141 const auto &stmt = body[statementIndex];
1145 const bool writesPredicate =
1146 std::any_of(stmt.cbits.begin(), stmt.cbits.end(), [&](
int targetBit) {
1147 return std::find(conditionBits.begin(), conditionBits.end(),
1148 targetBit) != conditionBits.end();
1150 const bool predicateWillBeReadAgain =
1151 statementIndex + 1 < body.size() || followedByElse;
1152 if (writesPredicate && predicateWillBeReadAgain)
1153 throw std::invalid_argument(
1154 "A measurement in the " + std::string(branchName) +
1155 " branch changes a predicate bit before the braced condition is "
1156 "evaluated again. The Circuit IR cannot preserve the source-level "
1157 "single evaluation of that predicate.");
1179 typedef std::vector<QoperationStatement>
type;
1183 const CondHeadType &condHead,
const std::vector<QopType> &body,
1184 const boost::optional<std::vector<QopType>> &elseBody,
1185 const std::unordered_map<std::string, IndexedId> &qreg_map,
1186 const std::unordered_map<std::string, IndexedId> &creg_map,
1187 const std::unordered_map<std::string, StatementType> &opaqueGates,
1188 const std::unordered_map<std::string, StatementType> &definedGates)
1191 std::vector<int> absoluteBits;
1192 std::vector<bool> expectedValues;
1193 for (
const auto &test : condHead.
bits) {
1195 creg_map,
"classical")
1197 expectedValues.push_back(test.expected);
1201 elseBody.has_value(),
"if");
1207 std::vector<QoperationStatement> stmts =
1208 addBranch(body, absoluteBits, expectedValues);
1213 if (absoluteBits.size() > 1)
1214 throw std::invalid_argument(
1215 "'else' on a multi-bit condition (if (... && ...) { ... } else "
1216 "{ ... }) is not supported: negating a conjunction would require "
1217 "a disjunctive condition, and no such primitive exists.");
1219 std::vector<bool> elseValues{!expectedValues.front()};
1220 std::vector<QoperationStatement> elseStmts =
1221 addBranch(*elseBody, absoluteBits, elseValues);
1222 stmts.insert(stmts.end(), elseStmts.begin(), elseStmts.end());
1230 throw std::invalid_argument(
1231 "'else' on a register-comparison condition (if (" + condHead.
regId +
1232 " == " + std::to_string(condHead.
regValue) +
1233 ") { ... } else { ... }) is not supported: it would require a "
1234 "not-equal condition, and no such primitive exists. Only "
1235 "single-bit conditions (if (" +
1236 condHead.
regId +
"[i]) { ... } else { ... }) support 'else'.");
1245 return addBranch(body, absoluteBits, expectedValues);
1258 comments = boost::fusion::at_c<0>(program);
1259 version = boost::fusion::at_c<1>(program);
1260 includes = boost::fusion::at_c<2>(program);
1261 statements = boost::fusion::at_c<3>(program);
1271 template <
typename Time = Types::time_type>
1273 std::unordered_map<std::string, StatementType> &opaqueGates,
1274 std::unordered_map<std::string, StatementType> &definedGates)
const {
1275 auto circuit = std::make_shared<Circuits::Circuit<Time>>();
1278 AddToCircuit(circuit, stmt, opaqueGates, definedGates);
1283 template <
typename Time = Types::time_type>
1287 std::unordered_map<std::string, StatementType> &opaqueGates,
1288 std::unordered_map<std::string, StatementType> &definedGates) {
1292 throw std::invalid_argument(
1293 "Measurement operation: number of qubits "
1294 "and classical bits do not match.");
1296 std::vector<std::pair<Types::qubit_t, size_t>> qs;
1297 for (
size_t i = 0; i < stmt.
qubits.size(); ++i)
1298 qs.push_back({static_cast<Types::qubit_t>(stmt.qubits[i]),
1299 static_cast<size_t>(stmt.cbits[i])});
1302 std::make_shared<Circuits::MeasurementOperation<Time>>(qs);
1305 circuit->AddOperation(measureOp);
1309 circuit->AddOperation(
1316 throw std::invalid_argument(
1317 "Conditional 'reset' (if ( ... ) reset q[i];) is not supported: "
1318 "the circuit representation has no conditional reset operation.");
1322 circuit->AddOperation(resetOp);
1327 for (
auto q : stmt.
qubits) {
1347 if (stmt.
qubits.size() % nrQubits != 0)
1348 throw std::invalid_argument(
1349 "Uop operation: number of qubits does "
1350 "not match the gate requirements.");
1352 for (
int pos = 0; pos < static_cast<int>(stmt.
qubits.size());
1355 for (
int q = 0; q < nrQubits; ++q)
1356 gateQubits.push_back(
1360 stmt.
gateType, gateQubits[0], nrQubits > 1 ? gateQubits[1] : 0,
1361 nrQubits > 2 ? gateQubits[2] : 0, param1, param2, param3,
1364 circuit->AddOperation(gateOp);
1370 throw std::invalid_argument(
1371 "Uop operation: number of parameters do "
1372 "not match the declaration.");
1374 std::unordered_map<std::string, double> variables;
1376 for (
size_t i = 0; i < stmt.
paramsDecl.size(); ++i)
1379 int nrQubits =
static_cast<int>(stmt.
qubitsDecl.size());
1380 if (stmt.
qubits.size() % nrQubits != 0)
1381 throw std::invalid_argument(
1382 "Defined Uop operation: number of qubits "
1383 "does not match the gate requirements.");
1385 for (
int pos = 0; pos < static_cast<int>(stmt.
qubits.size());
1387 std::unordered_map<std::string, IndexedId> qubitMap;
1388 for (
int q = 0; q < nrQubits; ++q) {
1391 id.base = stmt.
qubits[pos + q];
1393 qubitMap[
id.id] = id;
1398 for (
const auto &op : stmt.
declOps) {
1400 addGate(op, qubitMap, opaqueGates, definedGates, variables);
1402 AddToCircuit(circuit, gateStmt, opaqueGates, definedGates);
1425 if (stmt.
qubits.size() % nrQubits != 0)
1426 throw std::invalid_argument(
1427 "Uop operation: number of qubits does "
1428 "not match the gate requirements.");
1430 const auto condition =
1433 for (
int pos = 0; pos < static_cast<int>(stmt.
qubits.size());
1436 for (
int q = 0; q < nrQubits; ++q)
1437 gateQubits.push_back(
1441 stmt.
gateType, gateQubits[0], nrQubits > 1 ? gateQubits[1] : 0,
1442 nrQubits > 2 ? gateQubits[2] : 0, param1, param2, param3,
1447 circuit->AddOperation(condOp);
1453 throw std::invalid_argument(
1454 "Uop operation: number of parameters do "
1455 "not match the declaration.");
1457 std::unordered_map<std::string, double> variables;
1459 for (
size_t i = 0; i < stmt.
paramsDecl.size(); ++i)
1462 int nrQubits =
static_cast<int>(stmt.
qubitsDecl.size());
1463 if (stmt.
qubits.size() % nrQubits != 0)
1464 throw std::invalid_argument(
1465 "Defined Uop operation: number of qubits "
1466 "does not match the gate requirements.");
1468 for (
int pos = 0; pos < static_cast<int>(stmt.
qubits.size());
1470 std::unordered_map<std::string, IndexedId> qubitMap;
1471 for (
int q = 0; q < nrQubits; ++q) {
1474 id.base = stmt.
qubits[pos + q];
1476 qubitMap[
id.id] = id;
1481 for (
const auto &op : stmt.
declOps) {
1483 addGate(op, qubitMap, opaqueGates, definedGates, variables);
1490 AddToCircuit(circuit, gateStmt, opaqueGates, definedGates);
1501 case QoperationStatement::OperationType::
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 std::shared_ptr< IOperation< Time > > CreateDelay(Types::qubit_t qubit=0, Time duration=0)
Construct a delay operation.
static std::shared_ptr< IOperation< Time > > CreateConditionalMeasurement(const std::shared_ptr< MeasurementOperation< Time > > &measurement, const std::shared_ptr< ICondition > &condition)
Constructs a conditional measurement.
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.
AbstractSyntaxTree()=default
double Eval() const override
QuantumGateType
The type of quantum gates.
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
uint_fast64_t qubit_t
The type of a qubit.
phx::function< AddCondQopExpr > AddCondQop
std::variant< UGateCallType, CXGateCallType, GatecallType > UopType
boost::fusion::vector< std::string, MixedListType > SimpleGatecallType
phx::function< AddCondQopBracedExpr > AddCondQopBraced
phx::function< AddModifiedGateExpr > AddModifiedGate
std::vector< ArgumentType > MixedListType
std::vector< bool > DecodeRegisterCondition(const std::string ®isterName, int value, size_t width)
double EvaluateGateParameter(const Expression ¶meter, const std::unordered_map< std::string, double > &variables)
std::vector< ModifierType > ModifierListType
std::variant< SimpleGatecallType, ExpGatecallType > GatecallType
std::shared_ptr< Circuits::ICondition > MakeEqualCondition(const std::vector< int > &conditionBits, const std::vector< bool > &expectedValues)
boost::fusion::vector< std::vector< std::string >, double, std::vector< std::string >, std::vector< StatementType > > ProgramType
void ApplyCondition(StatementType &stmt, const std::vector< int > &conditionBits, const std::vector< bool > &expectedValues)
void RejectPredicateMutationBeforeReevaluation(const std::vector< QopType > &body, const std::vector< int > &conditionBits, bool followedByElse, std::string_view branchName)
std::vector< CondBitTest > bits
boost::fusion::vector< std::string, std::vector< Expression >, MixedListType > ExpGatecallType
boost::fusion::vector< std::string, int, QopType > CondOpType
phx::function< AddGateExpr > AddGate
phx::function< RejectUnsupportedConstructExpr > RejectUnsupportedConstruct
boost::fusion::vector< ModifierListType, UopType > ModifiedUopType
phx::function< RejectGateBodyModifierExpr > RejectGateBodyModifier
std::variant< std::string, IndexedId > ArgumentType
phx::function< RejectQasm3OnlyGateExpr > RejectQasm3OnlyGate
QoperationStatement StatementType
std::vector< int > ResolveRegisterOperand(const ArgumentType &argument, const RegisterMap ®isters, std::string_view kind)
std::vector< QoperationStatement > type
std::vector< QoperationStatement > operator()(const std::vector< QopType > &body, const std::vector< int > &absoluteBits, const std::vector< bool > &expectedValues) const
std::vector< QoperationStatement > operator()(const CondHeadType &condHead, const std::vector< QopType > &body, const boost::optional< std::vector< QopType > > &elseBody, 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
std::vector< QoperationStatement > type
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
static bool IsSuppportedGate(const std::string &gateName)
static int GateNrQubits(Circuits::QuantumGateType gateType)
static const std::unordered_set< std::string > & AllowedMultipleParamsGates()
static std::vector< int > ParseQubits(const ArgumentType &arg, const std::unordered_map< std::string, IndexedId > &qreg_map)
static const std::unordered_set< std::string > & AllowedOneParamGates()
static bool IsSuppportedOneParamGate(const std::string &gateName)
static const std::unordered_set< std::string > & AllowedNoParamGates()
static bool IsSuppportedMultipleParamsGate(const std::string &gateName)
static bool IsSuppportedNoParamGate(const std::string &gateName)
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
Circuits::QuantumGateType GetGateType(const std::string &gateName) const
static QoperationStatement ConjugateNegatedControls(const QoperationStatement &gate, const std::string &gateName, const std::vector< double > ¶ms, const std::vector< size_t > &negatedControls)
QoperationStatement operator()(const ModifiedUopType &modifiedUop, 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
static void ApplyCtrl(std::string &gateName, std::vector< double > ¶ms)
static bool IsControl(const ModifierType &modifier)
static void Canonicalize(const UopType &uop, std::string &gateName, std::vector< double > ¶ms, MixedListType &args, const std::unordered_map< std::string, double > &variables)
static void ApplyPow(double exponent, std::string &gateName, std::vector< double > ¶ms, int &repetitions)
static void ApplyInv(std::string &gateName, std::vector< double > ¶ms)
static QoperationStatement NoOpStatement()
static void NormalizeGateName(std::string &gateName)
static std::vector< size_t > NegatedControls(const ModifierListType &modifiers)
static UopType MakeCall(const std::string &gateName, const std::vector< double > ¶ms, const MixedListType &args)
std::shared_ptr< Circuits::Circuit< Time > > ToCircuit(std::unordered_map< std::string, StatementType > &opaqueGates, std::unordered_map< std::string, StatementType > &definedGates) const
std::vector< StatementType > statements
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)
std::vector< std::string > comments
Program(const ProgramType &program={})
std::vector< std::string > includes
std::vector< UopType > declOps
std::vector< bool > condExpected
std::vector< int > condBits
std::vector< std::string > qubitsDecl
std::vector< double > parameters
std::vector< std::string > paramsDecl
std::vector< int > qubits
Circuits::QuantumGateType gateType
UopType operator()(const ModifierListType &) const
bool operator()(const std::string &gateName, const std::unordered_map< std::string, StatementType > &definedGates) const
QoperationStatement operator()(const std::string &message) const