Class CircuitBuilder

Inheritance Relationships

Derived Type

Class Documentation

class CircuitBuilder

This class is used to build quantum circuits for execution.

This class is used to construct quantum circuits from elementary gates, such as X, Y, Z, Hadamard and CNOT.

We also provide high-level methods to construct quantum circuits for commonly-used quantum algorithms, such as QFT and amplitude amplification

Subclassed by qb::qml::ParamCirc

Public Functions

inline CircuitBuilder()

Constructor.

A constructor for the CircuitBuilder class. Creates an empty circuit.

inline CircuitBuilder(std::shared_ptr<xacc::CompositeInstruction> &composite, bool copy_nodes = true)

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 std::shared_ptr<xacc::CompositeInstruction> get()

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

inline void append(CircuitBuilder &other)

append another CircuitBuilder object to this one

Parameters:

other – the circuit to be appended [CircuitBuilder]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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 angle of rotation about the z-axis [double]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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

inline 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

inline 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

inline 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]

inline 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.

inline 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.

inline 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.

inline 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.

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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.

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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]

inline 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 Attributes

std::shared_ptr<xacc::IRProvider> gate_provider_
std::shared_ptr<xacc::CompositeInstruction> circuit_

Private Static Attributes

static const char *help_execute_