36 operator std::string()
const {
37 return declType +
" " +
id +
"[" + std::to_string(
index) +
"]";
53 return "quantum register";
55 return "classical register";
69 const auto [it, inserted] = declarations.emplace(name, kind);
72 if (it->second == kind)
73 throw std::invalid_argument(
"Duplicate declaration of '" + name +
"'.");
75 throw std::invalid_argument(
76 "Declaration of '" + name +
"' conflicts with an existing " +
81 std::string_view kind) {
82 const int size =
id.index;
84 throw std::invalid_argument(std::string(kind) +
" register '" +
id.
id +
85 "' must have a positive size.");
87 if (currentSize < 0 || currentSize > std::numeric_limits<int>::max() - size)
88 throw std::overflow_error(std::string(kind) +
89 " register allocation exceeds supported "
96 template <
typename,
typename>
101 template <
typename ID,
typename IND>
115 boost::fusion::vector<std::string, boost::optional<int>, std::string>;
119 std::string_view kind) {
120 const std::string &name = std::holds_alternative<IndexedId>(argument)
121 ? std::get<IndexedId>(argument).id
122 : std::get<std::string>(argument);
123 const auto it = registers.find(name);
124 if (it == registers.end())
125 throw std::invalid_argument(
"Undeclared " + std::string(kind) +
126 " register '" + name +
"'.");
128 const IndexedId &declaration = it->second;
129 if (std::holds_alternative<IndexedId>(argument)) {
130 const int index = std::get<IndexedId>(argument).index;
131 if (index < 0 || index >= declaration.
index) {
132 std::string titledKind(kind);
133 titledKind[0] =
static_cast<char>(
134 std::toupper(
static_cast<unsigned char>(titledKind[0])));
135 throw std::out_of_range(titledKind +
" register '" + name +
"' index " +
136 std::to_string(index) +
" is out of range [0, " +
137 std::to_string(declaration.
index) +
").");
140 return {declaration.
base + index};
143 std::vector<int> resolved;
144 resolved.reserve(
static_cast<size_t>(declaration.
index));
145 for (
int index = 0; index < declaration.
index; ++index)
146 resolved.push_back(declaration.
base + index);
151 const std::vector<int> &right,
152 std::string_view operation) {
153 if (left.size() != right.size())
154 throw std::invalid_argument(std::string(operation) +
155 " operands must have the same width.");
160 boost::fusion::vector<std::string, std::vector<Expression>,
MixedListType>;
164 boost::fusion::vector<std::vector<Expression>,
ArgumentType>;
167using UopType = std::variant<UGateCallType, CXGateCallType, GatecallType>;
196 template <
typename,
typename>
208 template <
typename E,
typename V>
227 template <
typename,
typename,
typename>
232 template <
typename K,
typename E,
typename V>
236 const double value = count->Eval(variables);
237 if (!std::isfinite(value))
238 throw std::invalid_argument(
239 "The control count of ctrl(n) @ / negctrl(n) @ must be finite, "
241 std::to_string(value));
243 const double rounded = std::round(value);
245 if (std::abs(value - rounded) > 1e-9 || rounded < 1. || rounded > 64.)
246 throw std::invalid_argument(
247 "The control count of ctrl(n) @ / negctrl(n) @ must be a positive "
248 "whole number, got: " +
249 std::to_string(value));
251 return ModifierType(kind, 0.,
static_cast<int>(rounded));
297 boost::fusion::vector<std::vector<std::string>, double,
298 std::vector<std::string>, std::vector<StatementType>>;
301using MeasureType = boost::fusion::vector<ArgumentType, ArgumentType>;
309using CondOpType = boost::fusion::vector<std::string, int, QopType>;
391 boost::fusion::vector<std::string, std::vector<std::string>,
392 std::vector<std::string>>;
396 boost::fusion::vector<std::string, std::vector<std::string>,
397 std::vector<std::string>>;
405 std::unordered_map<std::string, IndexedId> &creg_map,
412 id_copy.
base = counter;
416 creg_map[id_copy.
id] = id_copy;
430 std::unordered_map<std::string, IndexedId> &qreg_map,
437 id_copy.
base = counter;
441 qreg_map[id_copy.
id] = id_copy;
483 const std::string &type,
484 const boost::optional<int> &width) {
485 if (width && *width <= 0)
486 throw std::invalid_argument(
"Input '" + name +
487 "' must have a positive type width.");
489 if (type ==
"bool") {
491 throw std::invalid_argument(
"Boolean input '" + name +
492 "' cannot have a width designator.");
496 if (type ==
"float") {
497 if (width && *width != 32 && *width != 64)
498 throw std::invalid_argument(
500 "' uses an unsupported float width; only float, float[32], and "
501 "float[64] are supported.");
505 if (type ==
"angle") {
507 throw std::invalid_argument(
508 "Precisely quantized sized angle inputs are not supported.");
512 if (width && *width > 64)
513 throw std::invalid_argument(
"Input '" + name +
514 "' uses an integer width above 64, which "
515 "the numeric binding API cannot represent.");
519 const std::string &type,
520 const boost::optional<int> &width,
524 if (!std::isfinite(value))
525 throw std::invalid_argument(
"Input binding '" + name +
"' must be finite.");
527 if (type ==
"bool") {
528 if (value != 0. && value != 1.)
529 throw std::invalid_argument(
"Input binding '" + name +
530 "' must be a boolean value (0 or 1).");
534 if (type ==
"float") {
535 if (!width || *width == 64)
return value;
536 const float narrowed =
static_cast<float>(value);
537 if (!std::isfinite(narrowed))
538 throw std::invalid_argument(
"Input binding '" + name +
539 "' does not fit float[32].");
540 return static_cast<double>(narrowed);
543 if (type ==
"angle") {
544 double normalized = std::fmod(value, 2. * M_PI);
545 if (normalized < 0.) normalized += 2. * M_PI;
549 const bool isUnsigned = type ==
"uint";
550 if (std::trunc(value) != value)
551 throw std::invalid_argument(
"Input binding '" + name +
552 "' must be an integer value.");
553 if (isUnsigned && value < 0.)
554 throw std::invalid_argument(
"Unsigned input binding '" + name +
555 "' must be non-negative.");
558 const double upper = std::ldexp(1., isUnsigned ? *width : *width - 1);
559 const double lower = isUnsigned ? 0. : -upper;
560 if (value < lower || value >= upper)
561 throw std::invalid_argument(
"Input binding '" + name +
562 "' does not fit its declared " + type +
"[" +
563 std::to_string(*width) +
"] type.");
577 const InputDeclType &inputDecl, std::vector<std::string> &inputNames,
579 const std::unordered_map<std::string, double> &inputBindings,
580 std::unordered_map<std::string, double> &visibleInputValues)
const {
581 const std::string &type = boost::fusion::at_c<0>(inputDecl);
582 const boost::optional<int> &width = boost::fusion::at_c<1>(inputDecl);
583 const std::string &name = boost::fusion::at_c<2>(inputDecl);
586 inputNames.push_back(name);
588 const auto binding = inputBindings.find(name);
589 if (binding != inputBindings.end())
590 visibleInputValues[name] =
621 qreg_map,
"quantum");
623 creg_map,
"classical");
650 throw std::invalid_argument(
651 "A measurement without a classical target ('measure q;') is not "
652 "supported: every measurement must name the classical bit that "
653 "receives its result, as in 'measure q -> c;' or 'c = measure q;'");
684 std::set<int> qubit_set;
688 if (barrier.empty()) {
689 for (
const auto &[name, reg] : qreg_map)
690 for (
int index = 0; index < reg.index; ++index)
691 qubit_set.insert(reg.base + index);
693 for (
const auto &operand : barrier) {
694 const std::vector<int> resolved =
696 qubit_set.insert(resolved.begin(), resolved.end());
700 stmt.
qubits.assign(qubit_set.begin(), qubit_set.end());
708 template <
typename,
typename,
typename>
713 template <
typename D,
typename M,
typename V>
715 const V &variables)
const {
716 const auto &expr = boost::fusion::at_c<0>(dur);
717 const auto &unitOpt = boost::fusion::at_c<1>(dur);
718 double val = expr.Eval(variables);
719 double scale = unitOpt ? *unitOpt : 1.0;
721 throw std::invalid_argument(
722 "OpenQASM 'dt' unit delays require hardware timing context and are not "
723 "supported without a target waveform configuration.");
741 for (
const auto &operand : delay.
operands) {
742 const std::vector<int> resolved =
744 stmt.
qubits.insert(stmt.
qubits.end(), resolved.begin(), resolved.end());
759 std::unordered_map<std::string, StatementType> &opaqueGates,
760 const std::unordered_map<std::string, IndexedId> &qreg_map,
765 std::string gateName = boost::fusion::at_c<0>(opaqueDecl);
771 const std::vector<std::string> ¶ms = boost::fusion::at_c<1>(opaqueDecl);
772 const std::vector<std::string> &args = boost::fusion::at_c<2>(opaqueDecl);
778 opaqueGates[gateName] = stmt;
792 const boost::fusion::vector<
GateDeclType, std::vector<GateDeclOpType>>
794 std::unordered_map<std::string, StatementType> &definedGates,
799 const GateDeclType &declInfo = boost::fusion::at_c<0>(gateDecl);
801 const std::string &gateName = boost::fusion::at_c<0>(declInfo);
802 const std::vector<std::string> ¶ms = boost::fusion::at_c<1>(declInfo);
803 const std::vector<std::string> &args = boost::fusion::at_c<2>(declInfo);
808 throw std::invalid_argument(
809 "Gate declaration must have at least one qubit argument: " +
811 else if (definedGates.find(gateName) !=
817 throw std::invalid_argument(
"Gate already defined: " + gateName);
823 const std::vector<GateDeclOpType> &declOps =
824 boost::fusion::at_c<1>(gateDecl);
826 for (
const auto &op : declOps) {
827 if (std::holds_alternative<UopType>(op)) {
828 const UopType &uop = std::get<UopType>(op);
838 definedGates[gateName] = stmt;
AbstractSyntaxTree()=default
IndexedId(const std::string &id, int index)
QuantumGateType
The type of quantum gates.
phx::function< MakeRegCondHeadExpression > MakeRegCondHead
std::variant< UGateCallType, CXGateCallType, GatecallType > UopType
double ValidateInputBinding(const std::string &name, const std::string &type, const boost::optional< int > &width, double value)
boost::fusion::vector< std::string, MixedListType > SimpleGatecallType
std::variant< double, int, std::string > SimpleExpType
MixedListType BarrierType
std::unordered_map< std::string, DeclarationKind > DeclarationRegistry
boost::fusion::vector< std::string, std::vector< std::string >, std::vector< std::string > > GateDeclType
phx::function< MakeCondBitTestExpression > MakeCondBitTest
std::vector< ArgumentType > MixedListType
phx::function< MakeCtrlModifierExpression > MakeCtrlModifier
std::vector< ModifierType > ModifierListType
std::variant< SimpleGatecallType, ExpGatecallType > GatecallType
phx::function< RejectMeasureWithoutTargetExpr > RejectMeasureWithoutTarget
phx::function< AddQregExpr > AddQreg
boost::fusion::vector< ArgumentType, ArgumentType > CXGateCallType
phx::function< MakeIndexedIdExpression > MakeIndexedId
phx::function< AddCommentExpr > AddComment
boost::fusion::vector< std::vector< std::string >, double, std::vector< std::string >, std::vector< StatementType > > ProgramType
void RequireMatchingRegisterWidths(const std::vector< int > &left, const std::vector< int > &right, std::string_view operation)
phx::function< AddDeclarationExpr > AddDeclaration
phx::function< MakeDelayExpr > MakeDelay
phx::function< AddBarrierExpr > AddBarrier
std::vector< std::string > SimpleBarrierType
phx::function< AddCregExpr > AddCreg
std::vector< CondBitTest > bits
boost::fusion::vector< std::string, std::vector< Expression >, MixedListType > ExpGatecallType
boost::fusion::vector< std::string, int, QopType > CondOpType
void ValidateInputDeclaration(const std::string &name, const std::string &type, const boost::optional< int > &width)
boost::fusion::vector< std::vector< Expression >, ArgumentType > UGateCallType
phx::function< MakePowModifierExpression > MakePowModifier
boost::fusion::vector< ModifierListType, UopType > ModifiedUopType
phx::function< AddOpaqueDeclExpr > AddOpaqueDecl
phx::function< MakeBitCondHeadExpression > MakeBitCondHead
std::variant< std::string, IndexedId > ArgumentType
boost::fusion::vector< std::string, std::vector< std::string >, std::vector< std::string > > OpaqueDeclType
phx::function< AddDelayExpr > AddDelay
QoperationStatement StatementType
phx::function< AddMeasureExpr > AddMeasure
phx::function< AddInputDeclExpr > AddInputDecl
int ValidateRegisterAllocation(const IndexedId &id, int currentSize, std::string_view kind)
phx::function< AddGateDeclExpr > AddGateDecl
std::variant< UopType, SimpleBarrierType > GateDeclOpType
std::vector< int > ResolveRegisterOperand(const ArgumentType &argument, const RegisterMap ®isters, std::string_view kind)
boost::fusion::vector< ArgumentType, ArgumentType > MeasureType
boost::fusion::vector< std::string, boost::optional< int >, std::string > InputDeclType
std::unordered_map< std::string, IndexedId > RegisterMap
std::string_view DeclarationKindName(DeclarationKind kind)
void RegisterDeclaration(DeclarationRegistry &declarations, const std::string &name, DeclarationKind kind)
phx::function< AddResetExpr > AddReset
QoperationStatement operator()(const BarrierType &barrier, const RegisterMap &qreg_map) const
IndexedId operator()(int &counter, std::unordered_map< std::string, IndexedId > &creg_map, DeclarationRegistry &declarations, const IndexedId &id) const
QoperationStatement operator()(const IndexedId &id) const
QoperationStatement operator()(const DelayType &delay, const RegisterMap &qreg_map) const
QoperationStatement operator()(const boost::fusion::vector< GateDeclType, std::vector< GateDeclOpType > > &gateDecl, std::unordered_map< std::string, StatementType > &definedGates, DeclarationRegistry &declarations) const
QoperationStatement operator()(const MeasureType &measure, const RegisterMap &creg_map, const RegisterMap &qreg_map) const
QoperationStatement operator()(const OpaqueDeclType &opaqueDecl, std::unordered_map< std::string, StatementType > &opaqueGates, const std::unordered_map< std::string, IndexedId > &qreg_map, DeclarationRegistry &declarations) const
IndexedId operator()(int &counter, std::unordered_map< std::string, IndexedId > &qreg_map, DeclarationRegistry &declarations, const IndexedId &id) const
QoperationStatement operator()(const ResetType &reset, const RegisterMap &qreg_map) const
CondHeadType operator()(const std::vector< CondBitTest > &bits) const
CondBitTest operator()(const IndexedId &bit, bool expected) const
ModifierType operator()(K kind, const E &count, const V &variables) const
DelayType operator()(const D &dur, const M &operands, const V &variables) const
IndexedId operator()(const ID &id, IND index) const
ModifierType operator()(const E &exponent, const V &variables) const
CondHeadType operator()(const std::string ®Id, int regValue) const
ModifierType(ModifierKind kind, double exponent=0., int count=1)
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
QoperationStatement operator()(const ArgumentType &) const