48 operator std::string()
const
50 return declType +
" " +
id +
"[" + std::to_string(
index) +
"]";
75 return "quantum register";
77 return "classical register";
91 const auto [it, inserted] = declarations.emplace(name, kind);
95 if (it->second == kind)
96 throw std::invalid_argument(
"Duplicate declaration of '" + name +
"'.");
98 throw std::invalid_argument(
"Declaration of '" + name +
"' conflicts with an existing " + std::string(
DeclarationKindName(it->second)) +
".");
103 const int size =
id.index;
105 throw std::invalid_argument(std::string(kind) +
" register '" +
id.
id +
"' must have a positive size.");
107 if (currentSize < 0 || currentSize > std::numeric_limits<int>::max() - size)
108 throw std::overflow_error(std::string(kind) +
" register allocation exceeds supported "
116 template <
typename,
typename>
struct result
134using InputDeclType = boost::fusion::vector<std::string, boost::optional<int>, std::string>;
138 const std::string &name = std::holds_alternative<IndexedId>(argument) ? std::get<IndexedId>(argument).id : std::get<std::string>(argument);
139 const auto it = registers.find(name);
140 if (it == registers.end())
141 throw std::invalid_argument(
"Undeclared " + std::string(kind) +
" register '" + name +
"'.");
143 const IndexedId &declaration = it->second;
144 if (std::holds_alternative<IndexedId>(argument))
146 const int index = std::get<IndexedId>(argument).index;
147 if (index < 0 || index >= declaration.
index)
149 std::string titledKind(kind);
150 titledKind[0] =
static_cast<char>(std::toupper(
static_cast<unsigned char>(titledKind[0])));
151 throw std::out_of_range(titledKind +
" register '" + name +
"' index " + std::to_string(index) +
" is out of range [0, " +
152 std::to_string(declaration.
index) +
").");
155 return {declaration.
base + index};
158 std::vector<int> resolved;
159 resolved.reserve(
static_cast<size_t>(declaration.
index));
160 for (
int index = 0; index < declaration.
index; ++index)
161 resolved.push_back(declaration.
base + index);
167 if (left.size() != right.size())
168 throw std::invalid_argument(std::string(operation) +
" operands must have the same width.");
178using UopType = std::variant<UGateCallType, CXGateCallType, GatecallType>;
217 template <
typename,
typename>
struct result
249 template <
typename,
typename,
typename>
struct result
259 const double value = count->Eval(variables);
260 if (!std::isfinite(value))
261 throw std::invalid_argument(
"The control count of ctrl(n) @ / negctrl(n) @ must be finite, "
263 std::to_string(value));
265 const double rounded = std::round(value);
267 if (std::abs(value - rounded) > 1e-9 || rounded < 1. || rounded > 64.)
268 throw std::invalid_argument(
"The control count of ctrl(n) @ / negctrl(n) @ must be a positive "
269 "whole number, got: " +
270 std::to_string(value));
272 return ModifierType(kind, 0.,
static_cast<int>(rounded));
319using ProgramType = boost::fusion::vector<std::vector<std::string>, double, std::vector<std::string>, std::vector<StatementType>>;
322using MeasureType = boost::fusion::vector<ArgumentType, ArgumentType>;
333using CondOpType = boost::fusion::vector<std::string, int, QopType>;
425using GateDeclType = boost::fusion::vector<std::string, std::vector<std::string>, std::vector<std::string>>;
428using OpaqueDeclType = boost::fusion::vector<std::string, std::vector<std::string>, std::vector<std::string>>;
443 id_copy.
base = counter;
447 creg_map[id_copy.
id] = id_copy;
468 id_copy.
base = counter;
472 qreg_map[id_copy.
id] = id_copy;
521 if (width && *width <= 0)
522 throw std::invalid_argument(
"Input '" + name +
"' must have a positive type width.");
527 throw std::invalid_argument(
"Boolean input '" + name +
"' cannot have a width designator.");
533 if (width && *width != 32 && *width != 64)
534 throw std::invalid_argument(
"Input '" + name +
535 "' uses an unsupported float width; only float, float[32], and "
536 "float[64] are supported.");
543 throw std::invalid_argument(
"Precisely quantized sized angle inputs are not supported.");
547 if (width && *width > 64)
548 throw std::invalid_argument(
"Input '" + name +
549 "' uses an integer width above 64, which "
550 "the numeric binding API cannot represent.");
553inline double ValidateInputBinding(
const std::string &name,
const std::string &type,
const boost::optional<int> &width,
double value)
557 if (!std::isfinite(value))
558 throw std::invalid_argument(
"Input binding '" + name +
"' must be finite.");
562 if (value != 0. && value != 1.)
563 throw std::invalid_argument(
"Input binding '" + name +
"' must be a boolean value (0 or 1).");
569 if (!width || *width == 64)
571 const float narrowed =
static_cast<float>(value);
572 if (!std::isfinite(narrowed))
573 throw std::invalid_argument(
"Input binding '" + name +
"' does not fit float[32].");
574 return static_cast<double>(narrowed);
579 double normalized = std::fmod(value, 2. * M_PI);
581 normalized += 2. * M_PI;
585 const bool isUnsigned = type ==
"uint";
586 if (std::trunc(value) != value)
587 throw std::invalid_argument(
"Input binding '" + name +
"' must be an integer value.");
588 if (isUnsigned && value < 0.)
589 throw std::invalid_argument(
"Unsigned input binding '" + name +
"' must be non-negative.");
593 const double upper = std::ldexp(1., isUnsigned ? *width : *width - 1);
594 const double lower = isUnsigned ? 0. : -upper;
595 if (value < lower || value >= upper)
596 throw std::invalid_argument(
"Input binding '" + name +
"' does not fit its declared " + type +
"[" + std::to_string(*width) +
"] type.");
612 const std::unordered_map<std::string, double> &inputBindings,
613 std::unordered_map<std::string, double> &visibleInputValues)
const
615 const std::string &type = boost::fusion::at_c<0>(inputDecl);
616 const boost::optional<int> &width = boost::fusion::at_c<1>(inputDecl);
617 const std::string &name = boost::fusion::at_c<2>(inputDecl);
620 inputNames.push_back(name);
622 const auto binding = inputBindings.find(name);
623 if (binding != inputBindings.end())
684 throw std::invalid_argument(
"A measurement without a classical target ('measure q;') is not "
685 "supported: every measurement must name the classical bit that "
686 "receives its result, as in 'measure q -> c;' or 'c = measure q;'");
721 std::set<int> qubit_set;
727 for (
const auto &[name, reg] : qreg_map)
728 for (
int index = 0; index < reg.index; ++index)
729 qubit_set.insert(reg.base + index);
733 for (
const auto &operand : barrier)
736 qubit_set.insert(resolved.begin(), resolved.end());
740 stmt.
qubits.assign(qubit_set.begin(), qubit_set.end());
749 template <
typename,
typename,
typename>
struct result
754 template <
typename D,
typename M,
typename V>
DelayType operator()(
const D &dur,
const M &operands,
const V &variables)
const
756 const auto &expr = boost::fusion::at_c<0>(dur);
757 const auto &unitOpt = boost::fusion::at_c<1>(dur);
758 double val = expr.Eval(variables);
759 double scale = unitOpt ? *unitOpt : 1.0;
762 throw std::invalid_argument(
"OpenQASM 'dt' unit delays require hardware timing context and are not "
763 "supported without a target waveform configuration.");
783 for (
const auto &operand : delay.
operands)
786 stmt.
qubits.insert(stmt.
qubits.end(), resolved.begin(), resolved.end());
802 const std::unordered_map<std::string, IndexedId> &qreg_map,
DeclarationRegistry &declarations)
const
807 std::string gateName = boost::fusion::at_c<0>(opaqueDecl);
813 const std::vector<std::string> ¶ms = boost::fusion::at_c<1>(opaqueDecl);
814 const std::vector<std::string> &args = boost::fusion::at_c<2>(opaqueDecl);
820 opaqueGates[gateName] = stmt;
836 std::unordered_map<std::string, StatementType> &definedGates,
DeclarationRegistry &declarations)
const
841 const GateDeclType &declInfo = boost::fusion::at_c<0>(gateDecl);
843 const std::string &gateName = boost::fusion::at_c<0>(declInfo);
844 const std::vector<std::string> ¶ms = boost::fusion::at_c<1>(declInfo);
845 const std::vector<std::string> &args = boost::fusion::at_c<2>(declInfo);
850 throw std::invalid_argument(
"Gate declaration must have at least one qubit argument: " + gateName);
851 else if (definedGates.find(gateName) != definedGates.end())
855 throw std::invalid_argument(
"Gate already defined: " + gateName);
861 const std::vector<GateDeclOpType> &declOps = boost::fusion::at_c<1>(gateDecl);
863 for (
const auto &op : declOps)
865 if (std::holds_alternative<UopType>(op))
867 const UopType &uop = std::get<UopType>(op);
877 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
boost::fusion::vector< std::vector< std::string >, double, std::vector< std::string >, std::vector< StatementType > > ProgramType
std::variant< double, int, std::string > SimpleExpType
MixedListType BarrierType
std::unordered_map< std::string, DeclarationKind > DeclarationRegistry
boost::fusion::vector< std::vector< Expression >, ArgumentType > UGateCallType
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
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
boost::fusion::vector< std::string, std::vector< std::string >, std::vector< std::string > > GateDeclType
std::vector< std::string > SimpleBarrierType
phx::function< AddCregExpr > AddCreg
std::vector< CondBitTest > bits
boost::fusion::vector< std::string, int, QopType > CondOpType
void ValidateInputDeclaration(const std::string &name, const std::string &type, const boost::optional< int > &width)
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< Expression >, MixedListType > ExpGatecallType
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)
boost::fusion::vector< std::string, std::vector< std::string >, std::vector< std::string > > OpaqueDeclType
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