Class CircuitBuilder
Defined in File circuit_builder.hpp
Class Documentation
-
class CircuitBuilder
This class is used to build quantum circuits for execution.
It can build circuits that are executed using the session object.
We also provide high-level methods to construct quantum circuits for commonly-used quantum algorithms, such as QFT and amplitude amplification
Public Functions
-
CircuitBuilder()
Constructor.
A constructor for the CircuitBuilder class. Creates an empty circuit.
Constructor.
A constructor for the CircuitBuilder class. Creates a circuit from a specified list of instructions.
- Parameters:
composite – A pointer to a xacc::CompositeInstruction object [shared ptr]
copy_nodes – If true, child nodes (instructions) of the CompositeInstruction will be copied over. Otherwise, the input composite will become the root node of this CircuitBuilder. Default to true.
-
inline const std::size_t num_qubits()
Return the number of qubits in the circuit.
-
CircuitBuilder(const CircuitBuilder &other)
Copy constructor.
Creates a deep copy of another CircuitBuilder, including its circuit, variables, and configuration.
- Parameters:
other – The CircuitBuilder to copy.
-
inline CircuitBuilder copy() const
Create a deep copy of this CircuitBuilder.
- Returns:
A new CircuitBuilder instance with copied data.
-
inline const std::vector<std::string> &get_free_params() const
Get the names of the free parameters.
- Returns:
Names of the free parameters as a vector of strings
-
inline const std::size_t num_free_params() const
Get the number of free parameters.
- Returns:
The number of free parameters in this circuit.
-
const std::vector<double> param_map_to_vec(const std::map<std::string, double> ¶m_map) const
Helper function to create a vector of parameters from a map for input to the
sessionobject.- Parameters:
param_map – the map of parameters (e.g. {“alpha”: 0.5, “beta”: 0.3})
- Returns:
A vector of parameters values ordered by first appearance of the parameter in the circuit.
-
inline const bool is_parametrized() const
Get the parametrization flag for this circuit.
- Returns:
Whether or not the circuit is parametrized (i.e. has >0 free parameters)
-
inline std::shared_ptr<xacc::CompositeInstruction> get() const
return the list of instructions comprising the circuit
- Returns:
A pointer to the xacc::CompositeInstruction (list of instructions) that defines the circuit.
-
inline void print() const
print the list of instructions comprising the circuit
-
void append(const CircuitBuilder &other)
append another CircuitBuilder object to this one
- Parameters:
other – the circuit to be appended [CircuitBuilder]
-
void H(size_t idx)
Hadamard gate.
This method adds a Hadamard (H) gate to the circuit.
The H gate is defined by its action on the basis states
\[\begin{split} H\ket{0} \rightarrow \ket{+} \\ H\ket{1} \rightarrow \ket{-} \end{split}\]- Parameters:
idx – the index of the qubit being acted on [size_t]
-
void X(size_t idx)
Pauli-X gate.
This method adds a Pauli-X (X) gate to the circuit.
The X gate is defined by its action on the basis states
\[\begin{split} X\ket{0} \rightarrow \ket{1} \\ X\ket{1} \rightarrow \ket{0} \end{split}\]- Parameters:
idx – the index of the qubit being acted on [size_t]
-
void Y(size_t idx)
Pauli-Y gate.
This method adds a Pauli-Y (Y) gate to the circuit.
The Y gate is defined by its action on the basis states
\[\begin{split} Y\ket{0} \rightarrow -i\ket{1} \\ Y\ket{1} \rightarrow i\ket{0} \end{split}\]- Parameters:
idx – the index of the qubit being acted on [size_t]
-
void Z(size_t idx)
Pauli-Z gate.
This method adds a Pauli-Z (Z) gate to the circuit.
The Z gate is defined by its action on the basis states
\[\begin{split} Z\ket{0} \rightarrow \ket{0} \\ Z\ket{1} \rightarrow -\ket{1} \end{split}\]- Parameters:
idx – the index of the qubit being acted on [size_t]
-
void T(size_t idx)
T gate.
This method adds a T gate to the circuit.
The T gate is defined by its action on the basis states
\[\begin{split} T\ket{0} \rightarrow \ket{0} \\ T\ket{1} \rightarrow e^{i\pi/4}\ket{1} \end{split}\]- Parameters:
idx – the index of the qubit being acted on [size_t]
-
void S(size_t idx)
S gate.
This method adds an S gate to the circuit.
The S gate is defined by its action on the basis states
\[\begin{split} S\ket{0} \rightarrow \ket{0} \\ S\ket{1} \rightarrow i\ket{1} \end{split}\]- Parameters:
idx – the index of the qubit being acted on [size_t]
-
void Tdg(size_t idx)
Tdg gate.
This method adds an inverse of the T gate (Tdg) to the circuit.
The Tdg gate is defined by its action on the basis states
\[\begin{split} Tdg\ket{0} \rightarrow \ket{0} \\ Tdg\ket{1} \rightarrow e^{-i\pi/4}\ket{1} \end{split}\]- Parameters:
idx – the index of the qubit being acted on [size_t]
-
void Sdg(size_t idx)
Sdg gate.
This method adds an inverse of the S gate (Sdg) to the circuit.
The Sdg gate is defined by its action on the basis states
\[\begin{split} Sdg\ket{0} \rightarrow \ket{0} \\ Sdg\ket{1} \rightarrow -i\ket{1} \end{split}\]- Parameters:
idx – the index of the qubit being acted on [size_t]
-
void RX(size_t idx, double theta)
RX gate.
This method adds an x-axis rotation (RX) gate to the circuit.
The RX gate is defined by its action on the basis states
\[\begin{split} RX(\theta)\ket{0} \rightarrow \cos(\theta/2)\ket{0} - i\sin(\theta/2)\ket{1} \\ RX(\theta)\ket{1} \rightarrow -i\sin(\theta/2)\ket{0} + \cos(\theta/2)\ket{1} \end{split}\]- Parameters:
idx – the index of the qubit being acted on [size_t]
theta – the angle of rotation about the x-axis [double]
-
void RX(size_t idx, std::string param_name)
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
This overloaded method adds an x-axis rotation (RX) gate with a free parameter to the circuit.
- Parameters:
idx – the index of the qubit being acted on [size_t]
param_name – the name of the free parameter [std::string]
-
void RY(size_t idx, double theta)
RY gate.
This method adds a y-axis rotation (RY) gate to the circuit.
The RY gate is defined by its action on the basis states
\[\begin{split} RY(\theta)\ket{0} \rightarrow \cos(\theta/2)\ket{0} + \sin(\theta/2)\ket{1} \\ RY(\theta)\ket{1} \rightarrow -\sin(\theta/2)\ket{0} + \cos(\theta/2)\ket{1} \end{split}\]- Parameters:
idx – the index of the qubit being acted on [size_t]
theta – the angle of rotation about the y-axis [double]
-
void RY(size_t idx, std::string param_name)
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
This overloaded method adds an y-axis rotation (RY) gate with a free parameter to the circuit.
- Parameters:
idx – the index of the qubit being acted on [size_t]
param_name – the name of the free parameter [std::string]
-
void RZ(size_t idx, double theta)
RZ gate.
This method adds a z-axis rotation (RZ) gate to the circuit.
The RZ gate is defined by its action on the basis states
\[\begin{split} RZ(\theta)\ket{0} \rightarrow e^{-i\theta/2}\ket{0} \\ RZ(\theta)\ket{1} \rightarrow e^{i\theta/2}\ket{1} \end{split}\]- Parameters:
idx – the index of the qubit being acted on [size_t]
theta – the angle of rotation about the z-axis [double]
-
void RZ(size_t idx, std::string param_name)
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
This overloaded method adds an z-axis rotation (RZ) gate with a free parameter to the circuit. The name of the free parameter must be passed to the method.
- Parameters:
idx – the index of the qubit being acted on [size_t]
param_name – the name of the free parameter [std::string]
-
void U1(size_t idx, double theta)
U1 gate.
This method adds a phase (U1) gate to the circuit.
The U1 gate is defined by its action on the basis states
\[\begin{split} U1(\theta)\ket{0} \rightarrow \ket{0} \\ U1(\theta)\ket{1} \rightarrow e^{i\theta}\ket{1} \end{split}\]- Parameters:
idx – the index of the qubit being acted on [size_t]
theta – the value of the phase [double]
-
void U1(size_t idx, std::string param_name)
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
This overloaded method adds a parametrized phase (U1) gate with a free parameter to the circuit. The name of the free parameter must be passed to the method.
- Parameters:
idx – the index of the qubit being acted on [size_t]
param_name – the name of the free parameter [std::string]
-
void U3(size_t idx, double theta, double phi, double lambda)
U3 gate.
This method adds an arbitrary single qubit gate to the circuit.
The U3 gate is defined by its action on the basis states
\[\begin{split} U3(\theta,\phi,\lambda)\ket{0} \rightarrow \cos(\theta/2)\ket{0} + e^{i\phi}\sin(\theta/2)\ket{1} \\ U3(\theta,\phi,\lambda)\ket{1} \rightarrow -e^{i\lambda}\sin(\theta/2)\ket{0} + e^{i(\phi+\lambda)}\cos(\theta/2)\ket{1} \end{split}\]- Parameters:
idx – the index of the qubit being acted on [size_t]
theta – the first rotation parameter [double]
phi – the second rotation parameter [double]
lambda – the third rotation parameter [double]
-
void U3(size_t idx, std::string param1_name, std::string param2_name, std::string param3_name)
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
This overloaded method adds a multi-parametrized 1-qubit unitary (U) gate with 3 free parameters to the circuit. The names of the free parameters must be passed to the method.
- Parameters:
idx – the index of the qubit being acted on [size_t]
param1_name – the name of the first free parameter [std::string]
param2_name – the name of the second free parameter [std::string]
param3_name – the name of the third free parameter [std::string]
-
void CNOT(size_t ctrl_idx, size_t target_idx)
CNOT gate.
This method adds a controlled-X (CNOT) gate to the circuit.
The CNOT gate performs an X gate on the target qubit conditional on the control qubit being in the \(\ket{1}\) state. That is:
\[CNOT\ket{ab} \rightarrow \ket{a}X^a \ket{b}\]- Parameters:
ctrl_idx – the index of the control qubit [size_t]
target_idx – the index of the target qubit [size_t]
-
void MCX(const std::vector<int> &ctrl_inds, size_t target_idx)
MCX gate.
This method adds a multi-controlled X (MCX) gate to the circuit.
The MCX gate performs an X gate on the target qubit conditional on all control qubits being in the \(\ket{1}\) state. That is:
\[MCX\ket{c_1...c_Nt} \rightarrow \ket{c_1...c_N} X^{c_1...c_N} \ket{t}\]- Parameters:
ctrl_inds – the indices of the control qubits [vector of int]
target_idx – the index of the target qubit [size_t]
-
void CU(CircuitBuilder &circ, std::vector<int> ctrl_inds)
CU gate.
This method adds a controlled version of an arbitrary unitary (CU) to the circuit.
The CU gate implements the U gate on the target qubits conditional on all control qubits being in the \(\ket{1}\) state.
\[CU\ket{c_1...c_Nt_1...t_M} \rightarrow \ket{c_1...c_N} U^{c_1...c_N} \ket{t_1...t_M}\]- Parameters:
circ – the circuit for the unitary operation U [CircuitBuilder]
ctrl_inds – the indices of the control qubits [vector of int]
-
void CZ(size_t ctrl_idx, size_t target_idx)
CZ gate.
This method adds a controlled-Z (CZ) gate to the circuit.
The CZ gate performs a Z gate on the target qubit conditional on the control qubit being in the \(\ket{1}\) state. That is
\[CZ\ket{ab} \rightarrow \ket{a}Z^a \ket{b}\]- Parameters:
ctrl_idx – the index of the control qubit [size_t]
target_idx – the index of the target qubit [size_t]
-
void ACZ(size_t ctrl_idx, size_t target_idx)
ACZ gate.
This method adds an anti-controlled-Z (ACZ) gate to the circuit.
The ACZ gate performs a Z gate on the target qubit conditional on the control qubit being in the \(\ket{0}\) state. That is
\[CZ\ket{ab} \rightarrow \ket{a}Z^{a+1} \ket{b}\]- Parameters:
ctrl_idx – the index of the control qubit [size_t]
target_idx – the index of the target qubit [size_t]
-
void CH(size_t ctrl_idx, size_t target_idx)
CH gate.
This method adds a controlled-H (CH) gate to the circuit.
The CH gate performs an H gate on the target qubit conditional on the control qubit being in the \(\ket{1}\) state. That is:
\[CH\ket{ab} \rightarrow \ket{a}H^a \ket{b}\]- Parameters:
ctrl_idx – the index of the control qubit [size_t]
target_idx – the index of the target qubit [size_t]
-
void CPhase(size_t ctrl_idx, size_t target_idx, double theta)
CPhase gate.
This method adds a controlled-U1 (CPhase) gate to the circuit.
The CPHase gate performs a U1 gate on the target qubit conditional on the control qubit being in the \(\ket{1}\) state. That is:
\[CPhase(\theta)\ket{ab} \rightarrow \ket{a}U1(\theta)^a \ket{b}\]- Parameters:
ctrl_idx – the index of the control qubit [size_t]
target_idx – the index of the target qubit [size_t]
theta – the value of the phase [double]
-
void CPhase(size_t ctrl_idx, size_t target_idx, std::string param_name)
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
This overloaded method adds a parametrized phase (U1) gate with a free parameter to the circuit. The name of the free parameter must be passed to the method.
- Parameters:
ctrl_idx – the index of the control qubit [size_t]
target_idx – the index of the target qubit [size_t]
param_name – the name of the input parameter [std::string]
-
void CRZ(size_t ctrl_idx, size_t target_idx, double theta)
CRZ gate.
This method adds a controlled-RZ gate to the circuit.
The CRZ gate performs a RZ gate on the target qubit conditional on the control qubit being in the \(\ket{1}\) state. That is:
\[CRZ(\theta)\ket{ab} \rightarrow \ket{a}RZ(\theta)^a \ket{b}\]- Parameters:
ctrl_idx – the index of the control qubit [size_t]
target_idx – the index of the target qubit [size_t]
theta – the value of the phase [double]
-
void CRZ(size_t ctrl_idx, size_t target_idx, std::string param_name)
This method adds an z-axis rotation (CRZ) gate with a free parameter to the circuit. It is equivalent to the parameterized CPhase gate.
The name of the free parameter must be passed to the method.
The CRZ gate performs a RZ gate on the target qubit conditional on the control qubit being in the \(\ket{1}\) state. That is:
\[CRZ(\theta)\ket{ab} \rightarrow \ket{a}RZ(\theta)^a \ket{b}\]- Parameters:
ctrl_idx – the index of the control qubit [size_t]
target_idx – the index of the qubit being acted on [size_t]
param_name – the name of the free parameter [std::string]
-
void CRX(size_t ctrl_idx, size_t target_idx, double theta)
CRX gate.
This method adds a controlled-RX gate to the circuit.
The CRX gate performs a RX gate on the target qubit conditional on the control qubit being in the \(\ket{1}\) state. That is:
\[CRX(\theta)\ket{ab} \rightarrow \ket{a}RX(\theta)^a \ket{b}\]- Parameters:
ctrl_idx – the index of the control qubit [size_t]
target_idx – the index of the target qubit [size_t]
theta – the value of the phase [double]
-
void CRX(size_t ctrl_idx, size_t target_idx, std::string param_name)
This method adds an x-axis rotation (CRX) gate with a free parameter to the circuit. The name of the free parameter must be passed to the method.
The CRX gate performs a RX gate on the target qubit conditional on the control qubit being in the \(\ket{1}\) state. That is:
\[CRX(\theta)\ket{ab} \rightarrow \ket{a}RX(\theta)^a \ket{b}\]- Parameters:
ctrl_idx – the index of the control qubit [size_t]
target_idx – the index of the qubit being acted on [size_t]
param_name – the name of the free parameter [std::string]
-
void CRY(size_t ctrl_idx, size_t target_idx, double theta)
CRY gate.
This method adds a controlled-RY gate to the circuit.
The CRY gate performs a RY gate on the target qubit conditional on the control qubit being in the \(\ket{1}\) state. That is:
\[CRY(\theta)\ket{ab} \rightarrow \ket{a}RY(\theta)^a \ket{b}\]- Parameters:
ctrl_idx – the index of the control qubit [size_t]
target_idx – the index of the target qubit [size_t]
theta – the value of the phase [double]
-
void CRY(size_t ctrl_idx, size_t target_idx, std::string param_name)
This method adds an y-axis rotation (CRY) gate with a free parameter to the circuit. The name of the free parameter must be passed to the method.
The CRY gate performs a RY gate on the target qubit conditional on the control qubit being in the \(\ket{1}\) state. That is:
\[CRY(\theta)\ket{ab} \rightarrow \ket{a}RY(\theta)^a \ket{b}\]- Parameters:
ctrl_idx – the index of the control qubit [size_t]
target_idx – the index of the qubit being acted on [size_t]
param_name – the name of the free parameter [std::string]
-
void SWAP(size_t q1, size_t q2)
SWAP gate.
This method adds a SWAP gate to the circuit.
The SWAP gate is used to swap the quantum state of two qubits. That is, it acts as:
\[SWAP\ket{\psi}\ket{\phi} \rightarrow \ket{\phi}\ket{\psi}\]- Parameters:
q1 – the index of the first qubit [size_t]
q2 – the index of the second qubit [size_t]
-
void Measure(size_t idx)
Measurement.
This method is used to indicate a qubit in the circuit should be measured.
- Parameters:
idx – the index of the qubit to be measured [size_t]
-
void MeasureAll(int NUM_QUBITS)
Measure all qubits.
This method adds a measurement for all qubits involved in the circuit.
- Parameters:
NUM_QUBITS – the number of qubits in the circuit [int] [optional]
-
void QFT(const std::vector<int> &qubit_idxs)
Quantum Fourier Transform.
This method adds the Quantum Fourier Transform (QFT) to the circuit. This is a quantum analogue of the discrete Fourier Transform. It can be described by its action on basis states:
\[QFT\ket{x} \rightarrow \frac{1}{\sqrt{N}} \sum_{k=0}^{N-1} \omega_N^{xk} \ket{k}\]- Parameters:
qubit_idxs – the indices of the target qubits [vector of int]
-
void IQFT(const std::vector<int> &qubit_idxs)
Inverse Quantum Fourier Transform.
This method adds the inverse of the Quantum Fourier Transform (IQFT) to the circuit.
- Parameters:
qubit_idxs – the indices of the target qubits [vector of int]
-
void QPE(CircuitBuilder &oracle, int num_evaluation_qubits, std::vector<int> trial_qubits, std::vector<int> evaluation_qubits)
Quantum Phase Estimation.
This method adds the Quantum Phase Estimation (QPE) sub-routine to the circuit.
Given some unitary operator U and and eigenvector \(\ket{\psi}\) of U we can write
\[U\ket{\psi} = e^{2\pi i \theta}\ket{\psi}\]for some value of \( \theta \). QPE is used to provide a k-bit approximation to \( \theta \) storing the result in an evaluation register whilst leaving \( \ket{\psi} \) unchanged.
- Parameters:
oracle – The unitary operator U involved in the QPE routine [CircuitBuilder]
num_evaluation_qubits – The number of bits k used to approximate the phase [int]
trial_qubits – The indices of the qubits encoding the eigenvector of the unitary [vector of int]
evaluation_qubits – The indices of the qubits that will be used to store the approximate phase [vector of int]
-
void CanonicalAmplitudeEstimation(CircuitBuilder &state_prep, CircuitBuilder &grover_op, int num_evaluation_qubits, int num_state_qubits, int num_trial_qubits, std::vector<int> trial_qubits, std::vector<int> evaluation_qubits, bool no_state_prep)
Canonical Amplitude Estimation.
This method adds the canonical version of Quantum Amplitude Estimation (QAE) to the circuit.
Given a quantum state split into a good subspace and a bad subspace
\[\ket{\psi} = a\ket{good} + b\ket{bad} = A\ket{0}\]the QAE sub-routine provides a k-bit approximation to the amplitude of the good subspace, a.
QAE works by using the Grovers operator Q, which amplifies the amplitude of the good subspace, as the unitary input to a Quantum Phase Estimation routine.
- Parameters:
state_prep – The circuit A used to prepare the input state [CircuitBuilder]
grover_op – The circuit for the Grovers operator Q for the good subspace [CircuitBuilder]
num_evaluation_qubits – The number of bits k used to approximate the amplitude [int]
num_state_qubits – The number of qubits acted on by the state_prep circuit A [int]
num_trial_qubits – The number of qubits acted on by the grover_op circuit Q [int]
trial_qubits – The indices of the qubits acted on by the grover_op circuit Q [vector of int]
evaluation_qubits – The indices of the qubits used to store the approximate amplitude [vector of int]
no_state_prep – If true, assumes the state |psi> is already prepared in the appropriate register [bool]
-
void MultiControlledUWithAncilla(CircuitBuilder &U, std::vector<int> qubits_control, std::vector<int> qubits_ancilla)
Multi Controlled Unitary With Ancilla.
This method decomposes a multi-controlled unitary into Toffoli gates and the unitary itself, with the use of ancilla qubits. With N control qubits there should be N-1 ancilla. The resulting instructions are added to the circuit (AMCU gate).
- Parameters:
U – The unitary operation [CircuitBuilder]
qubits_control – The indices of the control qubits [vector of int]
qubits_ancilla – The indices of the ancilla qubits [vector of int]
-
std::string RunCanonicalAmplitudeEstimation(CircuitBuilder &state_prep, CircuitBuilder &grover_op, int num_evaluation_qubits, int num_state_qubits, int num_trial_qubits, std::vector<int> trial_qubits, std::vector<int> evaluation_qubits, std::string acc_name)
Run Canonical Amplitude Estimation.
This method sets up and executes an instance of the canonical amplitude estimation circuit.
- Parameters:
state_prep – The circuit A used to prepare the input state [CircuitBuilder]
grover_op – The circuit for the Grovers operator Q for the good subspace [CircuitBuilder]
num_evaluation_qubits – The number of bits k used to approximate the amplitude [int]
num_state_qubits – The number of qubits acted on by the state_prep circuit A [int]
num_trial_qubits – The number of qubits acted on by the grover_op circuit Q [int]
trial_qubits – The indices of the qubits acted on by the grover_op circuit Q [vector of int]
evaluation_qubits – The indices of the qubits used to store the approximate amplitude [vector of int]
acc_name – The name of the accelerator used to execute the circuit [string]
- Returns:
The output buffer of the execution
-
std::string RunCanonicalAmplitudeEstimationWithOracle(CircuitBuilder &state_prep, CircuitBuilder &oracle, int num_evaluation_qubits, int num_state_qubits, int num_trial_qubits, std::vector<int> evaluation_qubits, std::vector<int> trial_qubits, std::string acc_name)
Run Canonical Amplitude Estimation with Oracle.
This method sets up and executes an instance of the canonical amplitude estimation circuit, but instead of providing the grovers_op Q, we provide the oracle circuit O which acts as
\[O\ket{\psi} = O(a\ket{good} + b\ket{bad}) = -a\ket{good} + b\ket{bad}\]The Grover operator Q is then constructed within the method from O and the state_prep circuit A as
\[Q = A^\dagger S_0 A O\]where \( S_0 \) is an easily implementable rotation about the all 0 state \( \ket{000....0} \).
- Parameters:
state_prep – The circuit A used to prepare the input state [CircuitBuilder]
oracle – The oracle circuit O that marks the good subspace [CircuitBuilder]
num_evaluation_qubits – The number of bits k used to approximate the amplitude [int]
num_state_qubits – The number of qubits acted on by the state_prep circuit A [int]
num_trial_qubits – The number of qubits acted on by the grover_op circuit Q [int]
evaluation_qubits – The indices of the qubits used to store the approximate amplitude [vector of int]
trial_qubits – The indices of the qubits acted on by the grover_op circuit Q [vector of int]
acc_name – The name of the accelerator used to execute the circuit [string]
- Returns:
The output buffer of the execution
-
std::string RunMLAmplitudeEstimation(CircuitBuilder &state_prep, CircuitBuilder &oracle, std::function<int(std::string, int)> is_in_good_subspace, std::vector<int> score_qubits, int total_num_qubits, int num_runs, int shots, std::string acc_name)
Run Maximum-Likelihood Amplitude Estimation.
This method sets up and executes an instance of the maximum-likelihood amplitude estimation circuit.
Given the state
\[\ket{\psi} = a\ket{good} + b\ket{bad}\]MLQAE is an alternative to canonical QAE to find an estimate for the amplitude of the good subspace, a. It works by performing several runs of amplitude amplification with various iterations and recording the number of \( \ket{good} \) shots measured. Given this data, it finds the value of a that maximises the likelihood function.
- Parameters:
state_prep – The circuit A used to prepare the input state [CircuitBuilder]
oracle – The oracle circuit O that marks the good subspace [CircuitBuilder]
is_in_good_subspace – A function that, given a measured bitstring and potentially some other input value, returns a 1 if the measurement is in the good subspace and a 0 otherwise. [func(str, int) -> int]
score_qubits – The indices of the qubits that determine whether the state is in the good or bad subspace [vector of int]
total_num_qubits – The total number of qubits in the circuit [int]
num_runs – The number of runs of amplitude amplification (~4-6 is usually sufficient)
shots – The number of shots in each run [int]
acc_name – The name of the accelerator used to execute the circuit [string]
- Returns:
The output buffer of the execution
-
void AmplitudeAmplification(CircuitBuilder &oracle, CircuitBuilder &state_prep, int power)
Amplitude Amplification.
This method adds a number of Grovers operators to the circuit.
Grovers operators are used to amplify the amplitude of some desired subspace of your quantum state. Given a state
\[\ket{\psi} = a\ket{good} + b\ket{bad} = A\ket{0}\]and an oracle unitary O that acts as
\[O\ket{\psi} = -a\ket{good} + b\ket{bad}\]the Grovers operator that can be used to amplify the amplitude of the good state is
\[Q = A^\dagger S_0 A O\]where \( S_0 \) is an easily implemented reflection about the all zero state.
- Parameters:
oracle – The oracle circuit O that marks the good subspace [CircuitBuilder]
state_prep – The circuit A used to prepare the input state [CircuitBuilder]
power – The number of Grovers operators to append to the circuit [int]
-
void QPrime(int &nb_qubits_ancilla_metric, int &nb_qubits_ancilla_letter, int &nb_qubits_next_letter_probabilities, int &nb_qubits_next_letter)
Q’ Unitary.
This method adds a Q’ unitary to the circuit.
Q’ is a unitary required for the quantum decoder algorithm.
-
void UPrime(int &nb_qubits_ancilla_metric, int &nb_qubits_ancilla_letter, int &nb_qubits_next_letter_probabilities, int &nb_qubits_next_letter)
U’ Unitary.
This method adds a U’ unitary to the circuit.
U’ is a unitary required for the quantum decoder algorithm.
-
void WPrime(int iteration, std::vector<int> qubits_next_metric, std::vector<int> qubits_next_letter, std::vector<std::vector<float>> probability_table, std::vector<int> qubits_init_null, int null_integer, bool use_ancilla, std::vector<int> qubits_ancilla)
W’ Unitary.
This method adds a W’ unitary to the circuit.
W’ is a unitary required for the quantum decoder algorithm.
-
void UQPrime(int &nb_qubits_ancilla_metric, int &nb_qubits_ancilla_letter, int &nb_qubits_next_letter_probabilities, int &nb_qubits_next_letter)
UQ’ Unitary.
This method adds a UQ’ unitary to the circuit.
UQ’ is a unitary required for the quantum decoder algorithm.
-
void RippleAdd(const std::vector<int> &a, const std::vector<int> &b, int carry_bit)
Ripple Carry Adder.
This method adds a ripple carry adder to the circuit.
The ripple carry adder is an efficient in-line addition operation with a carry-in bit:
\[RippleAdd\ket{c_{in}}\ket{a}\ket{b} \rightarrow \ket{a} \ket{a+b+c_in}\]- Parameters:
a – The qubit indices of the first register in the addition [vector of int]
b – The qubit indices of the second register in the addition [vector of int]
carry_bit – The index of the carry-in bit [int]
-
void Comparator_as_Oracle(int BestScore, int num_scoring_qubits, std::vector<int> trial_score_qubits, int flag_qubit, std::vector<int> best_score_qubits, std::vector<int> ancilla_qubits, bool is_LSB, std::vector<int> controls_on, std::vector<int> controls_off)
Comparator as Oracle.
This method adds a quantum bit string comparator oracle to the circuit.
The quantum bit string comparator is used to add a negative phase to any trial state whose bit string value is greater than the state being compared to. In this way it can be used as an oracle in a Grovers operator that amplifies higher scoring strings. This may be useful in many search problems.
- Parameters:
BestScore – The score we are comparing strings to [int]
num_scoring_qubits – The number of qubits used to encode the scores [int]
trial_score_qubits – The indices of the qubits encoding the trial states [vector of int]
flag_qubit – The index of the flag qubit which acquires a negative phase whenever trial score > BestScore [int]
best_score_qubits – The indices of the qubits encoding the BestScore value [vector of int]
ancilla_qubits – The indices of the ancilla qubits required for the comparator circuit, if num_scoring_qubits = N we need 3N-1 ancilla [vector of int]
is_LSB – Indicates that the trial scores are encoded with LSB ordering [bool]
controls_on – The indices of any qubits that should be “on” controls (i.e. circuit executed if qubit = |1>) [vector of int]
controls_off – The indices of any qubits that should be “off” controls (i.e. circuit executed if qubit = |0>) [vector of int]
-
void Comparator(int BestScore, int num_scoring_qubits, std::vector<int> trial_score_qubits, int flag_qubit, std::vector<int> best_score_qubits, std::vector<int> ancilla_qubits, bool is_LSB, std::vector<int> controls_on, std::vector<int> controls_off)
Comparator.
This method adds a quantum bit string comparator to the circuit.
The quantum bit string comparator is used to compare the values of two bit string. If the trial score is greater than the best score, the flag qubit is flipped from 0 to 1.
- Parameters:
BestScore – The score we are comparing strings to [int]
num_scoring_qubits – The number of qubits used to encode the scores [int]
trial_score_qubits – The indices of the qubits encoding the trial states [vector of int]
flag_qubit – The index of the flag qubit which is flipped whenever trial score > BestScore [int]
best_score_qubits – The indices of the qubits encoding the BestScore value [vector of int]
ancilla_qubits – The indices of the ancilla qubits required for the comparator circuit, if num_scoring_qubits = N we need 3N-1 ancilla [vector of int]
is_LSB – Indicates that the trial scores are encoded with LSB ordering [bool]
controls_on – The indices of any qubits that should be “on” controls (i.e. circuit executed if qubit = |1>) [vector of int]
controls_off – The indices of any qubits that should be “off” controls (i.e. circuit executed if qubit = |0>) [vector of int]
-
void EfficientEncoding(std::function<int(int)> scoring_function, int num_state_qubits, int num_scoring_qubits, std::vector<int> state_qubits, std::vector<int> scoring_qubits, bool is_LSB, bool use_ancilla, std::vector<int> qubits_init_flag, int flag_integer)
Efficient Encoding.
This method adds an efficient encoding routine to the circuit.
Given a lookup function f that assigns a score to each binary string, we encode the state
\[\ket{\psi} = \ket{x} \ket{f(x)} + \ket{y} \ket{f(y)} + ...\]where the superposition is over all possible bitstrings. Rather than encoding states in order \( \ket{000}, \ket{001}, \ket{010} \)…etc. we cut down on the amount of X gates required by instead following the Gray code ordering of states.
This module can optionally also flag strings of a certain value.
- Parameters:
scoring_function – A function that inputs the integer value of a binary string and outputs its score [func(int) -> int]
num_state_qubits – The number of qubits encoding the strings [int]
num_scoring_qubits – The number of qubits encoding the scores [int]
state_qubits – The indices of the qubits encoding the strings [vector of int]
scoring_qubits – The indices of the qubits encoding the scores [vector of int]
is_LSB – Indicates that the trial scores are encoded with LSB ordering [bool]
use_ancilla – Indicates that ancilla qubits can be used to decompose MCX gates [bool]
qubits_init_flag – The indices of any flag qubits [vector of int]
flag_integer – The integer value of binary strings that should be flagged [int]
-
void EqualityChecker(std::vector<int> qubits_a, std::vector<int> qubits_b, int flag, bool use_ancilla, std::vector<int> qubits_ancilla, std::vector<int> controls_on, std::vector<int> controls_off)
Equality Checker.
This method adds an equality checker to the circuit.
Given two input bitstrings \( \ket{a} \) and \( \ket{b} \) the equality checker is used to flip a flag qubit \( \ket{0} \) \to \( \ket{1} \) whenever a=b.
- Parameters:
qubits_a – the indices of the qubits encoding a [vector of int]
qubits_b – the indices of the qubits encoding b [vector of int]
flag – the index of the flag qubit that gets flipped whenever a=b [int]
use_ancilla – Indicates that ancilla qubits can be used to decompose MCX gates [bool]
qubits_ancilla – The indices of the qubits to be used as ancilla qubits if use_ancilla=true [vector of int]
controls_on – The indices of any qubits that should be “on” controls (i.e. circuit executed if qubit = |1>) [vector of int]
controls_off – The indices of any qubits that should be “off” controls (i.e. circuit executed if qubit = |0>) [vector of int]
-
void ControlledSwap(std::vector<int> qubits_a, std::vector<int> qubits_b, std::vector<int> flags_on, std::vector<int> flags_off)
Controlled SWAP.
This method adds a controlled SWAP to the circuit.
Performs a SWAP operation on \( \ket{a} \) and \( \ket{b} \) if an only if the controls are satisfied.
- Parameters:
qubits_a – the indices of the qubits encoding a [vector of int]
qubits_b – the indices of the qubits encoding b [vector of int]
flags_on – The indices of any qubits that should be “on” controls (i.e. circuit executed if qubit = \( \ket{1} \)) [vector of int]
flags_off – The indices of any qubits that should be “off” controls (i.e. circuit executed if qubit = \( \ket{0} \)) [vector of int]
-
void ControlledAddition(std::vector<int> qubits_adder, std::vector<int> qubits_sum, int c_in, std::vector<int> flags_on, std::vector<int> flags_off, bool no_overflow)
Controlled Addition.
This method adds a controlled ripple carry adder to the circuit.
Performs a RippleAdd operation on adder_bits and sum_bits if an only if the controls are satisfied.
- Parameters:
qubits_adder – the indices of the qubits encoding adder_bits [vector of int]
qubits_sum – the indices of the qubits encoding sum_bits [vector of int]
c_in – the index of the carry-in bit [int]
flags_on – The indices of any qubits that should be “on” controls (i.e. circuit executed if qubit = \( \ket{1} \)) [vector of int]
flags_off – The indices of any qubits that should be “off” controls (i.e. circuit executed if qubit = \( \ket{0} \)) [vector of int]
no_overflow – Indicates that the sum adder_bits + sum_bits can be encoded on the same number of qubits as |sum> without overflowing [bool]
-
void GeneralisedMCX(int target, std::vector<int> controls_on, std::vector<int> controls_off)
Generalised MCX.
This method adds a generalised MCX gate to the circuit.
By generalised MCX we mean that we allow the control qubits to be conditional on being off or conditional on being on.
- Parameters:
target – The index of the target qubit [int]
controls_on – The indices of any qubits that should be “on” controls (i.e. circuit executed if qubit = \( \ket{1} \)) [vector of int]
controls_off – The indices of any qubits that should be “off” controls (i.e. circuit executed if qubit = \( \ket{0} \)) [vector of int]
-
void CompareBeamOracle(int q0, int q1, int q2, std::vector<int> FA, std::vector<int> FB, std::vector<int> SA, std::vector<int> SB, bool simplified)
Compare Beam Oracle.
This method adds a compare beam oracle to the circuit.
This method is required for the quantum decoder algorithm.
-
void SuperpositionAdder(int q0, int q1, int q2, std::vector<int> qubits_flags, std::vector<int> qubits_string, std::vector<int> qubits_metric, CircuitBuilder &ae_state_prep_circ, std::vector<int> qubits_ancilla, std::vector<int> qubits_beam_metric)
Superposition Adder.
This method adds a superposition adder to the current circuit.
Given a superposition state
\[\ket{\psi} = \sum a_1\ket{\phi_1} + a_2\ket{\phi_2} + ... + a_n\ket{\phi_n},\]this function finds the mean of the of the amplitudes, i.e.
\[(|a_1|^2 + |a_2|^2 + |a_n|^2) / N.\]- Parameters:
q0 – the index of the single required ancilla [int]
q1 – the index of the single required ancilla [int]
q2 – the index of the single required ancilla [int]
qubits_flags – the indices of the flag qubits [vector of int]
qubits_string – the indices of the qubits encoding the string [vector of int]
qubits_metric – the indices of the qubits encoding the metric value corresponding to the string [vector of int]
ae_state_prep_circ – The circuit A used to prepare the input state [CircuitBuilder]
qubits_ancilla – the indices of the required ancilla qubits [vector of int]
qubits_beam_metric – the indices of the qubits encoding class’ metric [vector of int]
-
void InverseCircuit(CircuitBuilder &circ)
Inverse Circuit.
This method adds the inverse of a circuit to the current circuit.
Given some collection of unitary operations,
\[U = U_N*U_{N-1}...U_2*U_1\]this method appends the inverse to the circuit:
\[U^{-1} = U_1^\dagger U_2^\dagger...U_{N-1}^\dagger U_N^\dagger\]This may be useful for un-computing ancilla or for constructing Grovers operators.
- Parameters:
circ – The circuit whose inverse we want to add to the current circuit [CircuitBuilder]
-
void Subtraction(std::vector<int> qubits_larger, std::vector<int> qubits_smaller, bool is_LSB, int qubit_ancilla)
Subtraction.
This method adds a subtraction to the circuit.
Performs the mapping:
\[\ket{a}\ket{b} \rightarrow \ket{a-b}\ket{b}\]assuming a>b.
- Parameters:
qubits_larger – the indices of the qubits encoding the larger value [vector of int]
qubits_smaller – the indices of the qubits encoding the smaller value [vector of int]
is_LSB – Indicates that the trial scores are encoded with LSB ordering [bool]
qubit_ancilla – the index of the required ancilla [vector of int]
-
void ControlledSubtraction(std::vector<int> qubits_larger, std::vector<int> qubits_smaller, std::vector<int> controls_on, std::vector<int> controls_off, bool is_LSB, int qubit_ancilla)
Controlled Subtraction.
This method adds a controlled subtraction to the circuit.
Performs a subtraction operation on a and b if an only if the controls are satisfied.
- Parameters:
qubits_larger – the indices of the qubits encoding the larger value [vector of int]
qubits_smaller – the indices of the qubits encoding the smaller value [vector of int]
controls_on – The indices of any qubits that should be “on” controls (i.e. circuit executed if qubit = |1>) [vector of int]
controls_off – The indices of any qubits that should be “off” controls (i.e. circuit executed if qubit = |0>) [vector of int]
is_LSB – Indicates that the trial scores are encoded with LSB ordering [bool]
qubit_ancilla – the index of the required ancilla [vector of int]
-
void ProperFractionDivision(std::vector<int> qubits_numerator, std::vector<int> qubits_denominator, std::vector<int> qubits_fraction, std::vector<int> qubits_ancilla, bool is_LSB)
Proper Fraction Division.
This method adds a proper fraction division to the circuit.
Performs the mapping:
\[\ket{num}\ket{denom}\ket{0} \rightarrow \ket{num}\ket{denom}\ket{num/denom}\]assuming denom > num
- Parameters:
qubits_numerator – the indices of the qubits encoding the numerator [vector of int]
qubits_denominator – the indices of the qubits encoding the denominator [vector of int]
qubits_fraction – the indices of the qubits that will ecode the division result [vector of int]
qubit_ancilla – the index of the required ancilla [vector of int]
is_LSB – Indicates that the trial scores are encoded with LSB ordering [bool]
-
void ControlledProperFractionDivision(std::vector<int> qubits_numerator, std::vector<int> qubits_denominator, std::vector<int> qubits_fraction, std::vector<int> qubits_ancilla, std::vector<int> controls_on, std::vector<int> controls_off, bool is_LSB)
Controlled Proper Fraction Division.
This method adds a controlled proper fraction division to the circuit.
Performs a PFD operation on a and b if an only if the controls are satisfied.
- Parameters:
qubits_numerator – the indices of the qubits encoding the numerator [vector of int]
qubits_denominator – the indices of the qubits encoding the denominator [vector of int]
qubits_fraction – the indices of the qubits that will ecode the division result [vector of int]
qubit_ancilla – the index of the required ancilla [vector of int]
controls_on – The indices of any qubits that should be “on” controls (i.e. circuit executed if qubit = |1>) [vector of int]
controls_off – The indices of any qubits that should be “off” controls (i.e. circuit executed if qubit = |0>) [vector of int]
is_LSB – Indicates that the trial scores are encoded with LSB ordering [bool]
-
void CompareGT(std::vector<int> qubits_a, std::vector<int> qubits_b, int qubit_flag, int qubit_ancilla, bool is_LSB)
Compare Greater Than.
This method adds a > comparator to the circuit.
Given two binary strings \( \ket{a} \) and \( \ket{b} \), this comparator flips a flag qubit whenever a>b. This method uses far less ancilla than the more general comparator method provided.
- Parameters:
qubits_a – The indices of the qubits encoding a [vector of int]
qubits_b – The indices of the qubits encoding b [vector of int]
qubit_flag – The index of the flag qubit that is flipped whenever a>b [int]
qubit_ancilla – The index of the single ancilla qubit required [int]
is_LSB – Indicates that the trial scores are encoded with LSB ordering [bool]
-
void Multiplication(std::vector<int> qubits_a, std::vector<int> qubits_b, std::vector<int> qubits_result, int qubit_ancilla, bool is_LSB)
Multiplication.
This method adds a Multiplication to the circuit.
Performs the mapping:
\[\ket{a}\ket{b}\ket{0} \rightarrow \ket{a}\ket{b}\ket{ab}\]- Parameters:
qubits_a – the indices of the qubits encoding a [vector of int]
qubits_b – the indices of the qubits encoding b [vector of int]
qubits_result – the indices of the qubits that will ecode the multiplication result [vector of int]
qubit_ancilla – the index of the single required ancilla [int]
is_LSB – Indicates that the trial scores are encoded with LSB ordering [bool]
-
void ControlledMultiplication(std::vector<int> qubits_a, std::vector<int> qubits_b, std::vector<int> qubits_result, int qubit_ancilla, bool is_LSB, std::vector<int> controls_on, std::vector<int> controls_off)
Controlled Multiplication.
This method adds a controlled Multiplication to the circuit.
Performs a Multiplication operation on a and b if an only if the controls are satisfied.
- Parameters:
qubits_a – the indices of the qubits encoding a [vector of int]
qubits_b – the indices of the qubits encoding b [vector of int]
qubits_result – the indices of the qubits that will ecode the multiplication result [vector of int]
qubit_ancilla – the index of the single required ancilla [int]
is_LSB – Indicates that the trial scores are encoded with LSB ordering [bool]
controls_on – The indices of any qubits that should be “on” controls (i.e. circuit executed if qubit = |1>) [vector of int]
controls_off – The indices of any qubits that should be “off” controls (i.e. circuit executed if qubit = |0>) [vector of int]
-
int ExponentialSearch(std::string method, StatePrepFuncCType state_prep_circ, OracleFuncCType oracle_func, int best_score, std::function<int(int)> f_score, int total_num_qubits, std::vector<int> qubits_string, std::vector<int> total_metric, std::string acc_name)
Exponential Search.
This method sets up and executes the exponential search routine.
Exponential search is a way to perform amplitude estimation when the size of the “good” subspace is unknown (so the number of Grovers operators to use is unknown).
We implement three variants:
canonical exponential search is a specific “guess and check” method
MLQAE exponential search uses MLQAE to first estimate the size of the good subspace then perform regular amplitude estimation with the appropriate number of Grovers operators
CQAE exponential search uses canonical QAE to first estimate the size of the good subspace then perform regular amplitude estimation with the appropriate number of Grovers operators
Exponential search here has been designed for use in the quantum decoder algorithm, so many inputs may not be required for general use.
- Parameters:
method – indicates which method to use. Options are “canonical”, “MLQAE”, “CQAE” [string]
state_prep_circ – a function which produces the state prep circuit [StatePrepFuncCType]
oracle_func – a function which produces the oracle circuit that marks the good subspace [OracleFuncCType]
best_score – the current best score [int]
f_score – a function that returns a 1 if the input binary string has value greater than the current best score and 0 otherwise [func(int)->int]
total_num_qubits – the total number of qubits, i.e. number of string qubits + number of metric qubits [int]
qubits_string – the indices of the qubits encoding the strings [vector of int]
total_metric – the indices of the qubits encoding the string scores [vector of int]
acc_name – the name of the accelerator used to execute the algorithm [string]
- Returns:
a better score if found, otherwise returns the current best score
Protected Functions
-
virtual void add_gate_with_free_parameters(std::string gate_name, std::vector<size_t> qubits, std::vector<std::string> param_names)
Process a gate and its parameter names, then add the gate to the circuit.
Add the parameters of an instruction to the list of circuit params.
Protected Attributes
-
std::shared_ptr<xacc::IRProvider> gate_provider_
The registry used to fetch quantum gates from XACC.
-
std::shared_ptr<xacc::CompositeInstruction> circuit_
The circuit that is built using the gate API.
-
size_t num_qubits_
The number of qubits in the circuit.
-
std::vector<std::string> free_params_
The free parameters in the circuit.
-
bool is_parametrized_ = {false}
Whether the circuit is parametrized.
Private Static Attributes
-
static const char *help_execute_
-
CircuitBuilder()