27 const double value = parameter.
Eval(variables);
28 if (!std::isfinite(value))
29 throw std::invalid_argument(
"Gate parameters must be finite, got: " + std::to_string(value));
41 std::vector<Expression> paramExprs;
42 for (
const double p : params)
56 const std::unordered_map<std::string, StatementType> &opaqueGates,
57 const std::unordered_map<std::string, StatementType> &definedGates,
58 const std::unordered_map<std::string, double> &variables = {})
const
63 if (std::holds_alternative<UGateCallType>(uop))
65 const auto &gate = std::get<UGateCallType>(uop);
66 const std::vector<Expression> ¶ms = boost::fusion::at_c<0>(gate);
71 for (
const auto &p : params)
76 else if (std::holds_alternative<CXGateCallType>(uop))
78 const auto &gate = std::get<CXGateCallType>(uop);
86 const std::vector<int> qubits1 =
ParseQubits(arg1, qreg_map);
87 const std::vector<int> qubits2 =
ParseQubits(arg2, qreg_map);
90 if (qubits1.size() == 1 && qubits2.size() == 1)
93 stmt.
qubits.push_back(qubits1[0]);
94 stmt.
qubits.push_back(qubits2[0]);
96 else if (qubits1.size() == 1 && qubits2.size() > 1)
99 for (
const auto &q2 : qubits2)
101 if (q2 == qubits1[0])
102 throw std::invalid_argument(
"Control and target qubits cannot be the same for CX gate");
103 stmt.
qubits.push_back(qubits1[0]);
104 stmt.
qubits.push_back(q2);
107 else if (qubits1.size() > 1 && qubits2.size() == 1)
110 for (
const auto &q1 : qubits1)
112 if (q1 == qubits2[0])
113 throw std::invalid_argument(
"Control and target qubits cannot be the same for CX gate");
114 stmt.
qubits.push_back(q1);
115 stmt.
qubits.push_back(qubits2[0]);
118 else if (qubits1.size() == qubits2.size())
121 for (
size_t i = 0; i < qubits1.size(); ++i)
123 if (qubits1[i] == qubits2[i])
124 throw std::invalid_argument(
"Control and target qubits cannot be the same for CX gate");
125 stmt.
qubits.push_back(qubits1[i]);
126 stmt.
qubits.push_back(qubits2[i]);
130 throw std::invalid_argument(
"Mismatched qubits sizes for CX gate arguments");
132 else if (std::holds_alternative<GatecallType>(uop))
134 const auto &gateCall = std::get<GatecallType>(uop);
136 if (std::holds_alternative<SimpleGatecallType>(gateCall))
139 const auto &gate = std::get<SimpleGatecallType>(gateCall);
140 const std::string &gateName = boost::fusion::at_c<0>(gate);
158 const auto it = definedGates.find(gateName);
159 if (it == definedGates.end())
162 throw std::invalid_argument(
"Unsupported gate without parameters: " + gateName);
171 throw std::invalid_argument(
"Gate " + gateName +
" requires parameters");
192 if (
static_cast<int>(args.size()) != expectedNrQubits)
193 throw std::invalid_argument(
"Gate " + gateName +
" requires exactly " + std::to_string(expectedNrQubits) +
" qubits");
199 const int expectedNrQubits =
static_cast<int>(definedGateStmt.qubitsDecl.size());
200 if (
static_cast<int>(args.size()) != expectedNrQubits)
201 throw std::invalid_argument(
"Defined gate " + gateName +
" requires exactly " + std::to_string(expectedNrQubits) +
" qubits");
202 if (definedGateStmt.parameters.size() != 0)
203 throw std::invalid_argument(
"Defined gate " + gateName +
" requires parameters, but none were provided");
210 stmt.
declOps = definedGateStmt.declOps;
214 int qubitsCounter = 1;
216 std::vector<std::vector<int>> allQubits(args.size());
217 for (
int i = 0; i < static_cast<int>(args.size()); ++i)
220 std::vector<int> qubits =
ParseQubits(arg, qreg_map);
222 if (qubits.size() != 1)
224 if (qubitsCounter == 1)
225 qubitsCounter =
static_cast<int>(qubits.size());
226 else if (qubitsCounter !=
static_cast<int>(qubits.size()))
227 throw std::invalid_argument(
"Mismatched qubits sizes for gate arguments");
230 allQubits[i] = std::move(qubits);
234 for (
int i = 0; i < qubitsCounter; ++i)
236 for (
const auto &qlist : allQubits)
238 if (qlist.size() == 1)
239 stmt.
qubits.push_back(qlist[0]);
241 stmt.
qubits.push_back(qlist[i]);
245 else if (std::holds_alternative<ExpGatecallType>(gateCall))
248 const auto &gate = std::get<ExpGatecallType>(gateCall);
249 const std::string &gateName = boost::fusion::at_c<0>(gate);
251 const std::vector<Expression> ¶ms = boost::fusion::at_c<1>(gate);
254 for (
const auto &p : params)
260 const auto it = definedGates.find(gateName);
261 if (it == definedGates.end())
266 throw std::invalid_argument(
"Gate " + gateName +
" requires parameters");
267 else if (params.size() == 1)
270 throw std::invalid_argument(
"This gate does not allow one parameter: " + gateName);
272 else if (params.size() > 1)
275 throw std::invalid_argument(
"This gate does not allow multiple parameters: " + gateName);
277 if (params.size() > 4)
278 throw std::invalid_argument(
"Too many parameters for gate: " + gateName);
286 if (
static_cast<int>(args.size()) != expectedNrQubits)
287 throw std::invalid_argument(
"Gate " + gateName +
" requires exactly " + std::to_string(expectedNrQubits) +
" qubits");
289 if (gateName ==
"u1")
296 else if (gateName ==
"u2")
305 else if (gateName ==
"cu1")
312 else if (gateName ==
"cu2")
322 else if (gateName ==
"u2")
331 throw std::invalid_argument(
"Gate u2 requires two parameters");
340 if (args.size() != 1)
341 throw std::invalid_argument(
"Gate " + gateName +
" requires exactly 1 qubit");
343 else if (gateName ==
"cu2")
348 throw std::invalid_argument(
"Gate cu2 requires two parameters");
357 if (args.size() != 2)
358 throw std::invalid_argument(
"Gate " + gateName +
" requires exactly 2 qubits");
360 else if (gateName ==
"rzz" || gateName ==
"rxx")
364 throw std::invalid_argument(
"Gate " + gateName +
" requires exactly 1 parameter");
365 if (args.size() != 2)
366 throw std::invalid_argument(
"Gate " + gateName +
" requires exactly 2 qubits");
374 const bool xBasis = gateName ==
"rxx";
386 throw std::invalid_argument(
"Unsupported gate with parameters: " + gateName);
393 const int expectedNrQubits =
static_cast<int>(definedGateStmt.qubitsDecl.size());
394 if (
static_cast<int>(args.size()) != expectedNrQubits)
395 throw std::invalid_argument(
"Defined gate " + gateName +
" requires exactly " + std::to_string(expectedNrQubits) +
" qubits");
397 if (definedGateStmt.paramsDecl.size() != stmt.
parameters.size())
398 throw std::invalid_argument(
"Defined gate " + gateName +
" requires a different number (" +
399 std::to_string(definedGateStmt.paramsDecl.size()) +
") of parameters than " +
407 stmt.
declOps = definedGateStmt.declOps;
411 int qubitsCounter = 1;
413 std::vector<std::vector<int>> allQubits(args.size());
414 for (
int i = 0; i < static_cast<int>(args.size()); ++i)
417 std::vector<int> qubits =
ParseQubits(arg, qreg_map);
419 if (qubits.size() != 1)
421 if (qubitsCounter == 1)
422 qubitsCounter =
static_cast<int>(qubits.size());
423 else if (qubitsCounter !=
static_cast<int>(qubits.size()))
424 throw std::invalid_argument(
"Mismatched qubits sizes for gate arguments");
427 allQubits[i] = std::move(qubits);
431 for (
int i = 0; i < qubitsCounter; ++i)
433 for (
const auto &qlist : allQubits)
435 if (qlist.size() == 1)
436 stmt.
qubits.push_back(qlist[0]);
438 stmt.
qubits.push_back(qlist[i]);
454 return allowedNoParamGates.find(gateName) != allowedNoParamGates.end();
459 return allowedOneParamGates.find(gateName) != allowedOneParamGates.end();
464 return allowedMultipleParamsGates.find(gateName) != allowedMultipleParamsGates.end();
469 return allowedNoParamGates.find(gateName) != allowedNoParamGates.end() || allowedOneParamGates.find(gateName) != allowedOneParamGates.end() ||
470 allowedMultipleParamsGates.find(gateName) != allowedMultipleParamsGates.end();
485 else if (gateName ==
"y")
487 else if (gateName ==
"z")
489 else if (gateName ==
"h")
491 else if (gateName ==
"s")
493 else if (gateName ==
"sdg" || gateName ==
"sdag")
495 else if (gateName ==
"t")
497 else if (gateName ==
"tdg" || gateName ==
"tdag")
499 else if (gateName ==
"sx")
501 else if (gateName ==
"sxdg" || gateName ==
"sxdag")
503 else if (gateName ==
"k")
505 else if (gateName ==
"swap")
507 else if (gateName ==
"cx" || gateName ==
"CX")
509 else if (gateName ==
"cy")
511 else if (gateName ==
"cz")
513 else if (gateName ==
"ch")
515 else if (gateName ==
"csx")
517 else if (gateName ==
"csxdg" || gateName ==
"csxdag")
519 else if (gateName ==
"cswap")
521 else if (gateName ==
"ccx")
523 else if (gateName ==
"p" || gateName ==
"phase")
525 else if (gateName ==
"rx")
527 else if (gateName ==
"ry")
529 else if (gateName ==
"rz")
531 else if (gateName ==
"cp" || gateName ==
"cphase")
533 else if (gateName ==
"crx")
535 else if (gateName ==
"cry")
537 else if (gateName ==
"crz")
539 else if (gateName ==
"U" || gateName ==
"u" || gateName ==
"u3" || gateName ==
"u1")
541 else if (gateName ==
"cu" || gateName ==
"cu3" || gateName ==
"cu1")
554 const int gateT =
static_cast<int>(gateType);
572 return allowedNoParamGates;
577 return allowedOneParamGates;
582 return allowedMultipleParamsGates;
594 static inline std::unordered_set<std::string> allowedNoParamGates = {
"x",
"y",
"z",
"h",
"s",
"sdg",
"sdag",
"t",
"tdg",
595 "tdag",
"sx",
"sxdg",
"sxdag",
"k",
"swap",
"cx",
"CX",
"cy",
596 "cz",
"ch",
"csx",
"csxdg",
"csxdag",
"cswap",
"ccx",
"id"};
597 static inline std::unordered_set<std::string> allowedOneParamGates = {
"p",
"rx",
"ry",
"rz",
"cp",
"crx",
"cry",
598 "crz",
"u1",
"cu1",
"phase",
"cphase",
"gphase",
"u0"};
601 static inline std::unordered_set<std::string> allowedMultipleParamsGates = {
"u",
"U",
"u3",
"cu",
"cu3"};
620 const std::unordered_map<std::string, StatementType> &opaqueGates,
621 const std::unordered_map<std::string, StatementType> &definedGates,
622 const std::unordered_map<std::string, double> &variables = {})
const
625 const UopType &uop = boost::fusion::at_c<1>(modifiedUop);
628 if (modifiers.empty())
629 return addGate(uop, qreg_map, opaqueGates, definedGates, variables);
631 std::string gateName;
632 std::vector<double> params;
634 Canonicalize(uop, gateName, params, args, variables);
636 if (definedGates.find(gateName) != definedGates.end())
637 throw std::invalid_argument(
"Gate modifiers cannot be applied to the user-defined gate: " + gateName);
645 std::string canonicalName = gateName;
646 NormalizeGateName(canonicalName);
652 size_t nrControls = 0;
653 for (
const auto &modifier : modifiers)
654 if (IsControl(modifier))
655 nrControls +=
static_cast<size_t>(modifier.count);
658 throw std::invalid_argument(
"ctrl @ with more than two controls is not supported, " + std::to_string(nrControls) +
659 " were requested for the gate: " + canonicalName);
665 if (canonicalName ==
"id")
667 static constexpr const char *validationGates[] = {
"id",
"cx",
"ccx"};
668 addGate(MakeCall(validationGates[nrControls], params, args), qreg_map, opaqueGates, definedGates);
669 return NoOpStatement();
677 for (
auto it = modifiers.rbegin(); it != modifiers.rend(); ++it)
681 case ModifierKind::Inv:
682 ApplyInv(canonicalName, params);
684 case ModifierKind::Pow:
685 ApplyPow(it->exponent, canonicalName, params, repetitions);
687 case ModifierKind::Ctrl:
688 case ModifierKind::NegCtrl:
692 for (
int c = 0; c < it->count; ++c)
693 ApplyCtrl(canonicalName, params);
700 StatementType stmt = addGate(
MakeCall(canonicalName, params, args), qreg_map, opaqueGates, definedGates);
702 if (repetitions == 0)
703 return NoOpStatement();
708 const std::vector<int> singleRound = stmt.qubits;
709 for (
int r = 1; r < repetitions; ++r)
710 stmt.qubits.insert(stmt.qubits.end(), singleRound.begin(), singleRound.end());
712 const std::vector<size_t> negatedControls = NegatedControls(modifiers);
713 if (negatedControls.empty())
716 return ConjugateNegatedControls(stmt, canonicalName, params, negatedControls);
726 std::vector<size_t> negatedControls;
727 size_t controlPos = 0;
729 for (
const auto &modifier : modifiers)
733 for (
int c = 0; c < modifier.count; ++c, ++controlPos)
735 negatedControls.push_back(controlPos);
738 return negatedControls;
749 const std::vector<size_t> &negatedControls)
757 for (
int q = 0; q < nrQubits; ++q)
758 stmt.
qubitsDecl.push_back(
"__negctrl_q" + std::to_string(q));
765 for (
const size_t control : negatedControls)
768 for (
const auto &flipArg : flipArgs)
771 for (
const auto &flipArg : flipArgs)
791 const std::unordered_map<std::string, double> &variables)
793 if (std::holds_alternative<UGateCallType>(uop))
795 const auto &gate = std::get<UGateCallType>(uop);
797 for (
const auto &p : boost::fusion::at_c<0>(gate))
799 args.push_back(boost::fusion::at_c<1>(gate));
801 else if (std::holds_alternative<CXGateCallType>(uop))
803 const auto &gate = std::get<CXGateCallType>(uop);
805 args.push_back(boost::fusion::at_c<0>(gate));
806 args.push_back(boost::fusion::at_c<1>(gate));
810 const auto &gateCall = std::get<GatecallType>(uop);
811 if (std::holds_alternative<SimpleGatecallType>(gateCall))
813 const auto &gate = std::get<SimpleGatecallType>(gateCall);
814 gateName = boost::fusion::at_c<0>(gate);
815 args = boost::fusion::at_c<1>(gate);
819 const auto &gate = std::get<ExpGatecallType>(gateCall);
820 gateName = boost::fusion::at_c<0>(gate);
821 for (
const auto &p : boost::fusion::at_c<1>(gate))
823 args = boost::fusion::at_c<2>(gate);
836 static const std::unordered_map<std::string, std::string> aliases = {{
"phase",
"p"}, {
"cphase",
"cp"}, {
"u3",
"u"}, {
"cu3",
"cu"},
837 {
"sdag",
"sdg"}, {
"sxdag",
"sxdg"}, {
"tdag",
"tdg"}, {
"csxdag",
"csxdg"}};
839 const auto it = aliases.find(gateName);
840 if (it != aliases.end())
841 gateName = it->second;
855 static void ApplyInv(std::string &gateName, std::vector<double> ¶ms)
857 static const std::unordered_set<std::string> selfInverseGates = {
"x",
"y",
"z",
"h",
"cx",
"cy",
"cz",
"ch",
"swap",
"cswap",
"ccx"};
858 static const std::unordered_map<std::string, std::string> daggerGates = {{
"s",
"sdg"}, {
"sdg",
"s"}, {
"t",
"tdg"}, {
"tdg",
"t"},
859 {
"sx",
"sxdg"}, {
"sxdg",
"sx"}, {
"csx",
"csxdg"}, {
"csxdg",
"csx"}};
861 if (selfInverseGates.find(gateName) != selfInverseGates.end())
864 const auto daggerIt = daggerGates.find(gateName);
865 if (daggerIt != daggerGates.end())
867 gateName = daggerIt->second;
871 if (rotationGates.find(gateName) != rotationGates.end())
873 for (
auto &p : params)
878 if (gateName ==
"u" || gateName ==
"cu")
884 params.resize(std::max<size_t>(params.size(), 3), 0.);
885 std::swap(params[1], params[2]);
886 for (
auto &p : params)
891 throw std::invalid_argument(
"inv @ is not supported for the gate: " + gateName);
894 static void ApplyPow(
double exponent, std::string &gateName, std::vector<double> ¶ms,
int &repetitions)
896 if (!std::isfinite(exponent))
897 throw std::invalid_argument(
"pow(k) @ requires a finite exponent for "
905 exponent = -exponent;
916 if (rotationGates.find(gateName) != rotationGates.end())
918 for (
auto &p : params)
923 const double rounded = std::round(exponent);
924 if (std::abs(exponent - rounded) > 1e-12)
925 throw std::invalid_argument(
"pow(k) @ with a fractional exponent is not supported for the "
932 if (rounded >
static_cast<double>(kMaxRepetitions) ||
static_cast<double>(repetitions) * rounded >
static_cast<double>(kMaxRepetitions))
933 throw std::invalid_argument(
"pow(k) @ with an exponent above " + std::to_string(kMaxRepetitions) +
" is not supported for the gate: " + gateName);
935 repetitions *=
static_cast<int>(rounded);
938 static void ApplyCtrl(std::string &gateName, std::vector<double> ¶ms)
940 static const std::unordered_map<std::string, std::string> controlledGates = {{
"x",
"cx"}, {
"y",
"cy"}, {
"z",
"cz"}, {
"h",
"ch"},
941 {
"sx",
"csx"}, {
"sxdg",
"csxdg"}, {
"p",
"cp"}, {
"rx",
"crx"},
942 {
"ry",
"cry"}, {
"rz",
"crz"}, {
"swap",
"cswap"}, {
"cx",
"ccx"}};
946 static const std::unordered_map<std::string, double> phaseAngles = {{
"s", M_PI / 2.}, {
"sdg", -M_PI / 2.}, {
"t", M_PI / 4.}, {
"tdg", -M_PI / 4.}};
948 if (gateName ==
"gphase")
949 throw std::invalid_argument(
"Controlled global phase ('ctrl @ gphase') is not supported by "
956 params.resize(std::max<size_t>(params.size(), 3), 0.);
961 const auto controlledIt = controlledGates.find(gateName);
962 if (controlledIt != controlledGates.end())
964 gateName = controlledIt->second;
968 const auto phaseIt = phaseAngles.find(gateName);
969 if (phaseIt != phaseAngles.end())
972 params.assign(1, phaseIt->second);
976 throw std::invalid_argument(
"ctrl @ is not supported for the gate: " + gateName);
987 static inline std::unordered_set<std::string> rotationGates = {
"rx",
"ry",
"rz",
"p",
"cp",
"crx",
"cry",
"crz",
"rxx",
"rzz"};
990 static constexpr int kMaxRepetitions = 1024;
1010 throw std::invalid_argument(
"Gate modifiers (ctrl, negctrl, inv, pow) are not supported inside a "
1011 "gate declaration body");
1034 throw std::invalid_argument(message);
1064 bool operator()(
const std::string &gateName,
const std::unordered_map<std::string, StatementType> &definedGates)
const
1066 if (definedGates.find(gateName) != definedGates.end())
1069 const std::string qasm2Spelling = gateName ==
"phase" ?
"p" : gateName ==
"cphase" ?
"cp" :
"";
1071 throw std::invalid_argument(
"'" + gateName +
1072 "' is an OpenQASM 3 stdgates.inc gate and is not available under "
1074 (qasm2Spelling.empty() ?
" (it has no qelib1.inc equivalent)" :
"; the qelib1.inc spelling is '" + qasm2Spelling +
"'"));
1080template <
class Time>
1081inline std::shared_ptr<Circuits::ICondition>
MakeEqualCondition(
const std::vector<int> &conditionBits,
const std::vector<bool> &expectedValues)
1083 if (conditionBits.size() != expectedValues.size())
1084 throw std::invalid_argument(
"Condition bit indices and expected values must have the same width.");
1086 std::vector<size_t> ind;
1087 ind.reserve(conditionBits.size());
1088 for (
const int bit : conditionBits)
1089 ind.push_back(
static_cast<size_t>(bit));
1097 throw std::invalid_argument(
"Condition value for classical register '" + registerName +
"' must be non-negative.");
1099 const auto unsignedValue =
static_cast<unsigned int>(value);
1100 if (width < std::numeric_limits<unsigned int>::digits && unsignedValue >= (1u << width))
1101 throw std::invalid_argument(
"Condition value " + std::to_string(value) +
" does not fit classical register '" + registerName +
"' of width " +
1102 std::to_string(width) +
".");
1104 std::vector<bool> expected(width,
false);
1105 auto remaining = unsignedValue;
1106 for (
size_t bit = 0; bit < width && remaining != 0; ++bit)
1108 expected[bit] = (remaining & 1u) != 0;
1126 stmt.
cbits = conditionBits;
1137 const std::unordered_map<std::string, IndexedId> &creg_map,
1138 const std::unordered_map<std::string, StatementType> &opaqueGates,
1139 const std::unordered_map<std::string, StatementType> &definedGates)
const
1143 const std::string &condId = boost::fusion::at_c<0>(condOp);
1144 int condVal = boost::fusion::at_c<1>(condOp);
1164 typedef std::vector<QoperationStatement>
type;
1167 std::vector<QoperationStatement>
operator()(
const std::vector<QopType> &body,
const std::vector<int> &absoluteBits,
1168 const std::vector<bool> &expectedValues)
const
1170 std::vector<QoperationStatement> stmts;
1171 stmts.reserve(body.size());
1173 for (
const auto &bodyStmt : body)
1177 stmts.push_back(stmt);
1185 std::string_view branchName)
1187 for (
size_t statementIndex = 0; statementIndex < body.size(); ++statementIndex)
1189 const auto &stmt = body[statementIndex];
1193 const bool writesPredicate = std::any_of(stmt.cbits.begin(), stmt.cbits.end(), [&](
int targetBit) {
1194 return std::find(conditionBits.begin(), conditionBits.end(), targetBit) != conditionBits.end();
1196 const bool predicateWillBeReadAgain = statementIndex + 1 < body.size() || followedByElse;
1197 if (writesPredicate && predicateWillBeReadAgain)
1198 throw std::invalid_argument(
"A measurement in the " + std::string(branchName) +
1199 " branch changes a predicate bit before the braced condition is "
1200 "evaluated again. The Circuit IR cannot preserve the source-level "
1201 "single evaluation of that predicate.");
1225 typedef std::vector<QoperationStatement>
type;
1229 const boost::optional<std::vector<QopType>> &elseBody,
1230 const std::unordered_map<std::string, IndexedId> &qreg_map,
1231 const std::unordered_map<std::string, IndexedId> &creg_map,
1232 const std::unordered_map<std::string, StatementType> &opaqueGates,
1233 const std::unordered_map<std::string, StatementType> &definedGates)
const
1237 std::vector<int> absoluteBits;
1238 std::vector<bool> expectedValues;
1239 for (
const auto &test : condHead.
bits)
1242 expectedValues.push_back(test.expected);
1250 std::vector<QoperationStatement> stmts = addBranch(body, absoluteBits, expectedValues);
1256 if (absoluteBits.size() > 1)
1257 throw std::invalid_argument(
"'else' on a multi-bit condition (if (... && ...) { ... } else "
1258 "{ ... }) is not supported: negating a conjunction would require "
1259 "a disjunctive condition, and no such primitive exists.");
1261 std::vector<bool> elseValues{!expectedValues.front()};
1262 std::vector<QoperationStatement> elseStmts = addBranch(*elseBody, absoluteBits, elseValues);
1263 stmts.insert(stmts.end(), elseStmts.begin(), elseStmts.end());
1271 throw std::invalid_argument(
"'else' on a register-comparison condition (if (" + condHead.
regId +
" == " + std::to_string(condHead.
regValue) +
1272 ") { ... } else { ... }) is not supported: it would require a "
1273 "not-equal condition, and no such primitive exists. Only "
1274 "single-bit conditions (if (" +
1275 condHead.
regId +
"[i]) { ... } else { ... }) support 'else'.");
1282 return addBranch(body, absoluteBits, expectedValues);
1297 comments = boost::fusion::at_c<0>(program);
1298 version = boost::fusion::at_c<1>(program);
1299 includes = boost::fusion::at_c<2>(program);
1300 statements = boost::fusion::at_c<3>(program);
1311 template <
typename Time = Types::time_type>
1312 std::shared_ptr<Circuits::Circuit<Time>>
ToCircuit(std::unordered_map<std::string, StatementType> &opaqueGates,
1313 std::unordered_map<std::string, StatementType> &definedGates)
const
1315 auto circuit = std::make_shared<Circuits::Circuit<Time>>();
1318 AddToCircuit(circuit, stmt, opaqueGates, definedGates);
1323 template <
typename Time = Types::time_type>
1325 std::unordered_map<std::string, StatementType> &opaqueGates, std::unordered_map<std::string, StatementType> &definedGates)
1331 throw std::invalid_argument(
"Measurement operation: number of qubits "
1332 "and classical bits do not match.");
1334 std::vector<std::pair<Types::qubit_t, size_t>> qs;
1335 for (
size_t i = 0; i < stmt.
qubits.size(); ++i)
1336 qs.push_back({static_cast<Types::qubit_t>(stmt.qubits[i]), static_cast<size_t>(stmt.cbits[i])});
1338 auto measureOp = std::make_shared<Circuits::MeasurementOperation<Time>>(qs);
1342 circuit->AddOperation(measureOp);
1346 circuit->AddOperation(
1352 throw std::invalid_argument(
"Conditional 'reset' (if ( ... ) reset q[i];) is not supported: "
1353 "the circuit representation has no conditional reset operation.");
1357 circuit->AddOperation(resetOp);
1363 for (
auto q : stmt.
qubits)
1385 if (stmt.
qubits.size() % nrQubits != 0)
1386 throw std::invalid_argument(
"Uop operation: number of qubits does "
1387 "not match the gate requirements.");
1389 for (
int pos = 0; pos < static_cast<int>(stmt.
qubits.size()); pos += nrQubits)
1392 for (
int q = 0; q < nrQubits; ++q)
1396 nrQubits > 2 ? gateQubits[2] : 0, param1, param2, param3, param4);
1398 circuit->AddOperation(gateOp);
1406 throw std::invalid_argument(
"Uop operation: number of parameters do "
1407 "not match the declaration.");
1409 std::unordered_map<std::string, double> variables;
1411 for (
size_t i = 0; i < stmt.
paramsDecl.size(); ++i)
1414 int nrQubits =
static_cast<int>(stmt.
qubitsDecl.size());
1415 if (stmt.
qubits.size() % nrQubits != 0)
1416 throw std::invalid_argument(
"Defined Uop operation: number of qubits "
1417 "does not match the gate requirements.");
1419 for (
int pos = 0; pos < static_cast<int>(stmt.
qubits.size()); pos += nrQubits)
1421 std::unordered_map<std::string, IndexedId> qubitMap;
1422 for (
int q = 0; q < nrQubits; ++q)
1426 id.base = stmt.
qubits[pos + q];
1428 qubitMap[
id.id] = id;
1433 for (
const auto &op : stmt.
declOps)
1435 StatementType gateStmt = addGate(op, qubitMap, opaqueGates, definedGates, variables);
1437 AddToCircuit(circuit, gateStmt, opaqueGates, definedGates);
1461 if (stmt.
qubits.size() % nrQubits != 0)
1462 throw std::invalid_argument(
"Uop operation: number of qubits does "
1463 "not match the gate requirements.");
1467 for (
int pos = 0; pos < static_cast<int>(stmt.
qubits.size()); pos += nrQubits)
1470 for (
int q = 0; q < nrQubits; ++q)
1474 nrQubits > 2 ? gateQubits[2] : 0, param1, param2, param3, param4);
1477 circuit->AddOperation(condOp);
1485 throw std::invalid_argument(
"Uop operation: number of parameters do "
1486 "not match the declaration.");
1488 std::unordered_map<std::string, double> variables;
1490 for (
size_t i = 0; i < stmt.
paramsDecl.size(); ++i)
1493 int nrQubits =
static_cast<int>(stmt.
qubitsDecl.size());
1494 if (stmt.
qubits.size() % nrQubits != 0)
1495 throw std::invalid_argument(
"Defined Uop operation: number of qubits "
1496 "does not match the gate requirements.");
1498 for (
int pos = 0; pos < static_cast<int>(stmt.
qubits.size()); pos += nrQubits)
1500 std::unordered_map<std::string, IndexedId> qubitMap;
1501 for (
int q = 0; q < nrQubits; ++q)
1505 id.base = stmt.
qubits[pos + q];
1507 qubitMap[
id.id] = id;
1512 for (
const auto &op : stmt.
declOps)
1514 StatementType gateStmt = addGate(op, qubitMap, opaqueGates, definedGates, variables);
1521 AddToCircuit(circuit, gateStmt, opaqueGates, definedGates);
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
boost::fusion::vector< std::vector< std::string >, double, std::vector< std::string >, std::vector< StatementType > > ProgramType
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)
UopType MakeCall(const std::string &gateName, const std::vector< double > ¶ms, const MixedListType &args)
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)
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, 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
boost::fusion::vector< std::string, std::vector< Expression >, MixedListType > ExpGatecallType
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)
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