Algorithms#
Qibo provides circuit constructions of quantum algorithms. They are implemented in
qibo/models/algorithms, and all of them are available from qibo.models, e.g.
from qibo.models import QFT.
Fourier transform and phase estimation#
Quantum Fourier Transform (QFT)#
- class qibo.models.QFT(nqubits, with_swaps=True, accelerators=None, **kwargs)[source]#
Creates a circuit that implements the Quantum Fourier Transform.
- Parameters:
nqubits (int) – number of qubits in the circuit.
with_swaps (bool, optional) – If
True, usesqibo.gates.SWAPgates at the end of the circuit so that the qubit order in the final state is the same as the initial state. Defauts toTrue.accelerators (dict, optional) – Accelerator device dictionary in order to use a distributed circuit. If
None, a simple (non-distributed) circuit will be used.kwargs (dict, optional) – Additional arguments used to initialize
qibo.models.Circuit. For details, see the documentation ofqibo.models.circuit.Circuit.
- Returns:
implementation of the Quantum Fourier Transform.
- Return type:
qibo.models.Circuit
Example
import numpy as np from qibo.models import QFT nqubits = 6 circuit = QFT(nqubits) # Random normalized initial state vector init_state = np.random.random(2 ** nqubits) + 1j * np.random.random(2 ** nqubits) init_state = init_state / np.sqrt((np.abs(init_state)**2).sum()) # Execute the circuit final_state = circuit(init_state)
Quantum Phase Estimation (QPE)#
- qibo.models.QPE(unitary, nqubits_counting, measure=True, **kwargs)[source]#
Creates a circuit that implements the canonical Quantum Phase Estimation.
Given a unitary \(U\) and one of its eigenstates \(|\psi\rangle\), such that \(U|\psi\rangle = e^{2 \pi i \varphi}|\psi\rangle\), the circuit estimates \(\varphi \in [0, \, 1)\) with \(t\) bits of precision, where \(t\) is the number of counting qubits. It acts on \(t + n\) qubits, with \(n\) being the number of qubits of \(U\), and it is composed of the following steps:
a Hadamard gate on each of the \(t\) counting qubits, which are the first qubits of the circuit;
\(U^{2^{t - 1 - j}}\), controlled by the counting qubit \(j\), acting on the last \(n\) qubits of the circuit, the target qubits;
the inverse
qibo.models.QFTon the counting qubits;the measurement of the counting qubits, if
measure=True.
The target qubits have to be prepared in \(|\psi\rangle\) before the circuit is applied, e.g. by adding the circuit that prepares it to a larger circuit before the one returned by this function. At the end, the counting qubits hold a bitstring \(b_{1} \cdots b_{t}\), with \(b_{1}\) being the outcome of the first qubit, such that \(\varphi\) is approximated by \(0.b_{1} \cdots b_{t}\) in binary, which is exact if \(\varphi\) is an integer multiple of \(2^{-t}\). The conversion from the bitstring into the phase can be done with
qibo.quantum_info.bitstring_to_phase(), and the phase of the most probable outcome, i.e. the estimate of \(\varphi\), withqibo.quantum_info.estimate_phase().Note
The power \(U^{2^{k}}\) is implemented by applying the controlled \(U\) a number \(2^{k}\) of times. Hence, \(U\) is applied \(2^{t} - 1\) times in total.
- Parameters:
unitary (
qibo.models.circuit.Circuitorqibo.gates.Gateor ndarray) – unitary \(U\), given as a circuit, as a gate, e.g.qibo.gates.Unitary, or as a matrix. A matrix must be unitary and of dimension \(2^{n} \times 2^{n}\) with \(n > 0\), and it is converted into aqibo.gates.Unitaryacting on \(n\) qubits. The qubits of a gate are relabeled, in increasing order, as the qubits of a circuit with the same number of qubits as the gate. All of the gates must be supported byqibo.models.circuit.Circuit.controlled_by().nqubits_counting (int) – number of counting qubits \(t\). The phase is estimated with a resolution of \(2^{-t}\).
measure (bool, optional) – If
True, adds a measurement of the counting qubits at the end of the circuit. Defaults toTrue.kwargs (dict, optional) – Additional arguments used to initialize
qibo.models.circuit.Circuit. For details, see the documentation ofqibo.models.circuit.Circuit.
- Returns:
implementation of the Quantum Phase Estimation.
- Return type:
Example
import math from qibo import Circuit, gates from qibo.models import QPE from qibo.quantum_info import estimate_phase # unitary with eigenstate |1> and eigenvalue exp(2 pi i phase) phase = 5 / 16 unitary = Circuit(1) unitary.add(gates.U1(0, theta=2 * math.pi * phase)) # phase estimation with 4 counting qubits nqubits_counting = 4 qpe = QPE(unitary, nqubits_counting) # prepare the eigenstate in the target qubit and apply the phase estimation circuit = Circuit(qpe.nqubits) circuit.add(gates.X(nqubits_counting)) circuit.add(qpe) result = circuit(nshots=100) print(estimate_phase(result))
0.3125
References
1. R. Cleve, A. Ekert, C. Macchiavello, and M. Mosca, Quantum algorithms revisited, Proc. R. Soc. Lond. A 454, 339 (1998).
2. M. A. Nielsen and I. L. Chuang, Quantum Computation and Quantum Information, Cambridge University Press (2010), Sec. 5.2.
Iterative Quantum Phase Estimation (IQPE)#
- qibo.models.IQPE(unitary, nbits, **kwargs)[source]#
Creates a circuit that implements the Iterative Quantum Phase Estimation.
Given a unitary \(U\) and one of its eigenstates \(|\psi\rangle\), such that \(U|\psi\rangle = e^{2 \pi i \varphi}|\psi\rangle\), the circuit estimates \(\varphi \in [0, \, 1)\) with \(t\) bits of precision, where \(t\) is
nbits, asqibo.models.QPE()does. However, a single counting qubit is measured \(t\) times, instead of using \(t\) counting qubits and the inverseqibo.models.QFT. The circuit acts on \(1 + n\) qubits, with \(n\) being the number of qubits of \(U\). The first qubit is the counting qubit and the last \(n\) qubits are the target qubits.The bits of \(\varphi\) are obtained one at a time, starting from the least significant one. In each step \(k = 1, \dots, t\):
a Hadamard gate is applied to the counting qubit;
\(U^{2^{t - k}}\) is applied to the target qubits, controlled by the counting qubit;
a phase gate is applied to the counting qubit, with the angle \(-2 \pi \sum_{j=1}^{k-1} m_{j} \, 2^{-(k - j + 1)}\), where \(m_{j}\) is the outcome of the step \(j\), which removes the contribution of the bits that were already measured;
a Hadamard gate is applied to the counting qubit, which is measured with
collapse=True, and the outcome \(m_{k}\) is the bit \(b_{t - k + 1}\) of \(\varphi = 0.b_{1} \cdots b_{t}\);if it is not the last step, the counting qubit is reset to \(|0\rangle\) with an \(X\) rotation conditioned on \(m_{k}\).
The circuit finishes with a measurement of the counting qubit that is not collapsed, so that it can be simulated with state vectors. The target qubits have to be prepared in \(|\psi\rangle\) before the circuit is applied, e.g. by adding the circuit that prepares it to a larger circuit before the one returned by this function.
The outcomes of the measurements are not merged into the result of the execution of the circuit. They are returned as a list of
qibo.measurements.MeasurementResult, which is ordered from the most to the least significant bit, i.e. in the reverse order of the measurements. Hence, they can be joined withqibo.measurements.MeasurementResult.join()and the estimate of \(\varphi\) is obtained withqibo.quantum_info.estimate_phase().Note
As in
qibo.models.QPE(), \(U\) is applied \(2^{t} - 1\) times in total. The circuit has fewer qubits, but when it is simulated, each shot has to be simulated separately because of the measurements with collapse.- Parameters:
unitary (
qibo.models.circuit.Circuitorqibo.gates.Gateor ndarray) – unitary \(U\), given as a circuit, as a gate, e.g.qibo.gates.Unitary, or as a matrix. Seeqibo.models.QPE()for the details.nbits (int) – number of bits \(t\) of the phase to be estimated, which sets the resolution \(2^{-t}\) and the number of measurements.
kwargs (dict, optional) – Additional arguments used to initialize
qibo.models.circuit.Circuit, e.g.density_matrix=True. For details, see the documentation ofqibo.models.circuit.Circuit.
- Returns:
the circuit that implements the Iterative Quantum Phase Estimation and the list of
qibo.measurements.MeasurementResultwith the outcomes of the measurements of the counting qubit, from the most to the least significant bit.- Return type:
Example
import math from qibo import Circuit, gates from qibo.measurements import MeasurementResult from qibo.models import IQPE from qibo.quantum_info import estimate_phase # unitary with eigenstate |1> and eigenvalue exp(2 pi i phase) phase = 5 / 16 unitary = Circuit(1) unitary.add(gates.U1(0, theta=2 * math.pi * phase)) # phase estimation with 4 bits iqpe, results = IQPE(unitary, 4) # prepare the eigenstate in the target qubit and apply the phase estimation circuit = Circuit(iqpe.nqubits) circuit.add(gates.X(1)) circuit.add(iqpe) circuit(nshots=100) print(estimate_phase(MeasurementResult.join(*results)))
0.3125
References
1. A. Yu. Kitaev, Quantum measurements and the Abelian Stabilizer Problem, arXiv:quant-ph/9511026.
2. R. B. Griffiths and C.-S. Niu, Semiclassical Fourier Transform for Quantum Computation, Phys. Rev. Lett. 76, 3228 (1996).
Amplitude amplification and search#
Grover’s Algorithm#
- class qibo.models.Grover(oracle, superposition_circuit=None, initial_state_circuit=None, superposition_qubits=None, superposition_size=None, number_solutions=None, target_amplitude=None, check=None, check_args=(), iterative=False)[source]#
Model that performs Grover’s algorithm.
For Grover’s original search algorithm: arXiv:quant-ph/9605043 For the iterative version with unknown solutions:arXiv:quant-ph/9605034 For the Grover algorithm with any superposition:arXiv:quant-ph/9712011
- Parameters:
oracle (
qibo.core.circuit.Circuit) – quantum circuit that flips the sign using a Grover ancilla initialized with -X-H-. Grover ancilla expected to be last qubit of oracle circuit.superposition_circuit (
qibo.core.circuit.Circuit) – quantum circuit that takes an initial state to a superposition. Expected to use the first set of qubits to store the relevant superposition.initial_state_circuit (
qibo.core.circuit.Circuit) – quantum circuit that initializes the state. If empty defaults to|000..00>superposition_qubits (int) – number of qubits that store the relevant superposition. Leave empty if superposition does not use ancillas.
superposition_size (int) – how many states are in a superposition. Leave empty if its an equal superposition of quantum states.
number_solutions (int) – number of expected solutions. Needed for normal Grover. Leave empty for iterative version.
target_amplitude (float) – absolute value of the amplitude of the target state. Only for advanced use and known systems.
check (function) – function that returns True if the solution has been found. Required of iterative approach. First argument should be the bitstring to check.
check_args (tuple) – arguments needed for the check function. The found bitstring not included.
iterative (bool) – force the use of the iterative Grover
Example
import numpy as np from qibo import Circuit, gates from qibo.models import Grover # Create an oracle. Ex: Oracle that detects state |11111> oracle = Circuit(5 + 1) oracle.add(gates.X(5).controlled_by(*range(5))) # Create superoposition circuit. Ex: Full superposition over 5 qubits. superposition = Circuit(5) superposition.add([gates.H(qubit) for qubit in range(5)]) # Generate and execute Grover class grover = Grover(oracle, superposition_circuit=superposition, number_solutions=1) solution, iterations = grover()
- circuit(iterations)[source]#
Creates circuit that performs Grover’s algorithm with a set amount of iterations.
- Parameters:
iterations (int) – number of times to repeat the Grover step.
- Returns:
qibo.core.circuit.Circuitthat performs Grover’s algorithm.
- iterative_grover(lamda_value=1.2, backend=None)[source]#
Iterative approach of Grover for when the number of solutions is not known.
- Parameters:
lamda_value (real) – parameter that controls the evolution of the iterative method. Must be between 1 and 4/3.
backend (
qibo.backends.abstract.Backend) – Backend to use for circuit execution.
- Returns:
bitstring measured and checked as a valid solution. total_iterations (int): number of times the oracle has been called.
- Return type:
measured (str)
- execute(nshots=100, freq=False, logs=False, backend=None)[source]#
Execute Grover’s algorithm.
If the number of solutions is given, calculates iterations, otherwise it uses an iterative approach.
- Parameters:
nshots (int) – number of shots in order to get the frequencies.
freq (bool) – print the full frequencies after the exact Grover algorithm.
backend (
qibo.backends.abstract.Backend) – Backend to use for circuit execution.
- Returns:
bitstring (or list of bitstrings) measured as solution of the search. iterations (int): number of oracle calls done to reach a solution.
- Return type:
solution (str)
Quantum Amplitude Amplification#
Quantum Amplitude Amplification (QAA) generalizes Grover’s algorithm to an arbitrary circuit \(\mathcal{A}\) that prepares the state \(|\Psi\rangle = \mathcal{A}|0\rangle\) from the all-zero state \(|0\rangle\). Given a Boolean function \(\chi\), which marks the “good” computational basis states, let \(a\) be the probability of measuring a good state in \(|\Psi\rangle\). Repeating the circuit and measuring it takes \(O(1 / a)\) runs on average to find a good state, whereas amplification needs only \(O(1 / \sqrt{a})\) applications of \(\mathcal{A}\) and its inverse \(\mathcal{A}^{-1}\). This is done by applying the operator
where \(\mathbf{S}_{\chi}\) changes the sign of the amplitude of the good states and \(\mathbf{S}_{0}\) changes the sign of the amplitude of the state \(|0\rangle\). After \(m\) applications, the probability of measuring a good state is \(\sin^{2}((2m + 1)\theta_{a})\), where \(a = \sin^{2}(\theta_{a})\). Depending on what is known about \(a\), the following can be used:
qibo.models.amplification_operator()builds the circuit of \(\mathbf{Q}\);qibo.models.QAA()builds the circuit \(\mathbf{Q}^{m}\mathcal{A}\), either with a chosen number \(m\) of iterations, or with the number that is computed from a known \(a\), which can also find a good state with certainty;qibo.models.FPQAA()builds a fixed-point version, which only needs a lower bound of \(a\), and whose failure probability stays below a chosen bound if more iterations are applied, while keeping the quadratic speedup;qibo.models.OAA()builds an oblivious version, which amplifies the amplitude with which a circuit implements a unitary on an input state that is unknown, so that the reflection about that state, which is not available, is not needed;qibo.models.QSearch()finds a good state when \(a\) is unknown, by running circuits with an exponentially increasing number of iterations.
- qibo.models.amplification_operator(algorithm, oracle, **kwargs)[source]#
Creates the circuit of the amplitude amplification operator.
Given a circuit \(\mathcal{A}\), which prepares the state \(|\Psi\rangle = \mathcal{A}|0\rangle\) from the all-zero state \(|0\rangle\), and a Boolean function \(\chi\), which marks the “good” computational basis states, the amplification operator is
\[\mathbf{Q} = -\mathcal{A} \, \mathbf{S}_{0} \, \mathcal{A}^{-1} \, \mathbf{S}_{\chi}.\]Here, \(\mathbf{S}_{\chi}\) changes the sign of the amplitude of every good state and \(\mathbf{S}_{0}\) changes the sign of the amplitude of the state \(|0\rangle\) only. The operator \(\mathbf{Q}\) rotates \(|\Psi\rangle\), in the plane spanned by its good and bad components, by an angle \(2\theta_{a}\), where \(a = \sin^{2}(\theta_{a})\) is the probability of measuring a good state in \(|\Psi\rangle\). For \(\mathcal{A}\) equal to Hadamard gates on every qubit, \(\mathbf{Q}\) is the iterate of Grover’s search algorithm.
The operator is applied to the circuit as \(\mathbf{S}_{\chi}\), \(\mathcal{A}^{-1}\), \(\mathbf{S}_{0}\), \(\mathcal{A}\) and a global phase of \(\pi\), which accounts for the minus sign and matters if the circuit is controlled.
- Parameters:
algorithm (
qibo.models.circuit.Circuit) – circuit \(\mathcal{A}\). It cannot contain measurements.oracle (
qibo.models.circuit.Circuit) – circuit \(\mathbf{S}_{\chi}\), a diagonal operator that multiplies the good states by \(-1\), e.g. a multi-controlledqibo.gates.Zgate. It must act on the same number of qubits asalgorithm, and it cannot contain measurements.kwargs (dict, optional) – Additional arguments used to initialize
qibo.models.circuit.Circuit, e.g.density_matrix=True. For details, see the documentation ofqibo.models.circuit.Circuit.
- Returns:
circuit that implements \(\mathbf{Q}\), with the same number of qubits as
algorithm.- Return type:
Example
from qibo import Circuit, gates from qibo.models import amplification_operator # Hadamard gates on 2 qubits, and the oracle that marks the state |11> algorithm = Circuit(2) algorithm.add(gates.H(qubit) for qubit in range(2)) oracle = Circuit(2) oracle.add(gates.CZ(0, 1)) # for 2 qubits and 1 good state, one application of Q finds the good state circuit = Circuit(2) circuit.add(algorithm) circuit.add(amplification_operator(algorithm, oracle)) circuit.add(gates.M(0, 1)) result = circuit(nshots=10) print(result.frequencies())
Counter({'11': 10})References
1. G. Brassard, P. Høyer, M. Mosca, and A. Tapp, Quantum Amplitude Amplification and Estimation, Contemporary Mathematics 305, 53 (2002).
- qibo.models.FPQAA(algorithm, oracle, delta, niterations=None, probability=None, measure=True, backend=None, **kwargs)[source]#
Creates a circuit that implements fixed-point Quantum Amplitude Amplification (FPQAA).
Let \(\mathcal{A}\) be the circuit
algorithm, \(\chi\) a Boolean function that marks “good” computational basis states, and \(a\) the probability of measuring a good state in \(|\Psi\rangle = \mathcal{A}|0\rangle\), where \(|0\rangle\) is the all-zero state. The success probability ofqibo.models.QAA()oscillates with the number of iterations, so too many iterations decrease it, and the right number depends on \(a\). In contrast, this circuit, which follows Yoder, Low and Chuang, only needs a lower bound for \(a\), and more iterations never push its success probability below the bound.The circuit applies \(\mathcal{A}\) and then \(l\) generalized Grover iterates,
\[\mathcal{S}_{L} = G(\alpha_{l}, \beta_{l}) \cdots G(\alpha_{1}, \beta_{1}), \qquad G(\alpha, \beta) = -\mathbf{S}_{\Psi}(\alpha) \, \mathbf{S}_{\chi}(\beta),\]with \(L = 2l + 1\). Here, \(\mathbf{S}_{\chi}(\beta)\) multiplies the amplitude of every good state by \(e^{i\beta}\), and \(\mathbf{S}_{\Psi}(\alpha) = \mathcal{A} \, \mathbf{S}_{0}(\alpha) \, \mathcal{A}^{-1}\) multiplies the amplitude of \(|\Psi\rangle\) by \(e^{-i\alpha}\), where \(\mathbf{S}_{0}(\alpha)\) does it for \(|0\rangle\). The phases are
\[\alpha_{j} = -\beta_{l - j + 1} = 2 \cot^{-1}\left(\tan(2 \pi j / L) \sqrt{1 - \gamma^{2}}\right), \qquad \gamma^{-1} = T_{1 / L}(1 / \delta),\]where \(T_{n}(x) = \cos(n \cos^{-1}(x))\) is the Chebyshev polynomial of the first kind of degree \(n\), which is also defined for \(x > 1\) and non-integer \(n\). The probability of measuring a good state is then
\[P_{L} = 1 - \delta^{2} \, T_{L}\left(T_{1 / L}(1 / \delta) \sqrt{1 - a}\right)^{2} \geq 1 - \delta^{2} \quad \text{for every} \quad a \geq 1 - T_{1 / L}(1 / \delta)^{-2}.\]The lower bound on \(a\) decreases as \(L\) grows, and it is about \((\log(2 / \delta) / L)^{2}\) for large \(L\) and small \(\delta\). Thus, the oracle is used \(2l = L - 1\) times, which is in \(O(\log(2 / \delta) / \sqrt{a})\) for a suitable \(L\), as in
qibo.models.QAA(). For \(\delta = 1\) the circuit is Grover’s one, i.e. the one ofqibo.models.QAA()withniterations=l, and for \(\delta = 0\) and \(l = 1\) it is the \(\pi / 3\) fixed-point search of Grover, whose probability is \(1 - (1 - a)^{L}\).The circuit acts on the qubits of
algorithmand on one auxiliary qubit, which is the last qubit, starts in the state \(|0\rangle\) and returns to it. It is used to apply the phase \(e^{i\beta}\) to the good states: the oracle is controlled by the auxiliary qubit and surrounded by Hadamard gates, which flips the auxiliary qubit if and only if the state is good, then a phase gate acts on it and the flip is undone. Hence, all of the gates of the oracle must be supported byqibo.models.circuit.Circuit.controlled_by(). The measurement, ifmeasure=True, is applied to the qubits ofalgorithmonly. The number of iterations \(l\) is determined in one of the following ways:niterationsis given, and \(l\) is its value;probabilityis given, which is a lower bound \(a_{0}\) of \(a\), and \(l\) is the smallest number of iterations for which \(P_{L} \geq 1 - \delta^{2}\) for every \(a \geq a_{0}\), i.e. \(L \geq \cosh^{-1}(1 / \delta) / \tanh^{-1}(\sqrt{a_{0}})\). Note that the bound on the failure probability is trivial for \(\delta = 1\), and then \(l = 0\).
Example
from qibo import Circuit, gates from qibo.models import FPQAA # Hadamard gates on 3 qubits, and the oracle that marks the state |111> nqubits = 3 algorithm = Circuit(nqubits) algorithm.add(gates.H(qubit) for qubit in range(nqubits)) oracle = Circuit(nqubits) oracle.add(gates.CCZ(0, 1, 2)) # the failure probability is at most 0.1^2 if the probability of |111>, which is # 1 / 8, is not smaller than 1 / 16 circuit = FPQAA(algorithm, oracle, delta=0.1, probability=1 / 16) result = circuit(nshots=1000) print(result.frequencies().most_common(1)[0][0])
111
- Parameters:
algorithm (
qibo.models.circuit.Circuit) – circuit \(\mathcal{A}\) without measurements.oracle (
qibo.models.circuit.Circuit) – circuit \(\mathbf{S}_{\chi}\) that multiplies the good states by \(-1\), without measurements and with the same number of qubits asalgorithm. Seeqibo.models.amplification_operator().delta (float) – bound \(\delta \in [0, 1]\) of the failure probability, which is at most \(\delta^{2}\) over the range of \(a\) above.
niterations (int, optional) – number \(l \geq 0\) of generalized Grover iterates. Exactly one of
niterationsandprobabilityhas to be given. Defaults toNone.probability (float, optional) – lower bound \(a_{0} \in (0, 1]\) of the probability of measuring a good state in \(\mathcal{A}|0\rangle\), from which the number of iterations is computed. It requires \(\delta > 0\). Defaults to
None.measure (bool, optional) – If
True, adds a measurement of the qubits ofalgorithmat the end of the circuit. Defaults toTrue.backend (
qibo.backends.abstract.Backend, optional) – backend to be used in the calculation of the number of iterations and of the phases. IfNone, it uses the current backend. Defaults toNone.kwargs (dict, optional) – Additional arguments used to initialize
qibo.models.circuit.Circuit, e.g.density_matrix=True. For details, see the documentation ofqibo.models.circuit.Circuit.
- Returns:
implementation of fixed-point Quantum Amplitude Amplification, with one more qubit than
algorithm.- Return type:
References
1. T. J. Yoder, G. H. Low, and I. L. Chuang, Fixed-Point Quantum Search with an Optimal Number of Queries, Phys. Rev. Lett. 113, 210501 (2014).
- qibo.models.OAA(unitary, nauxiliary, niterations=None, probability=None, exact=False, backend=None, **kwargs)[source]#
Create a circuit that implements Oblivious Amplitude Amplification (OAA).
Let \(U\) be the circuit
unitary, which acts on \(\mu\) auxiliary qubits, the first ones of the circuit, and on \(n\) system qubits, the last ones. Let \(|0^{\mu}\rangle\) be the all-zero state of the auxiliary qubits and \(\Pi = |0^{\mu}\rangle\langle 0^{\mu}| \otimes \mathbb{1}\) the projector onto it. The circuit applies a unitary \(V\) on the system qubits with amplitude \(\sin(\theta)\), for every state \(|\psi\rangle\) of the system qubits, i.e.\[U |0^{\mu}\rangle |\psi\rangle = \sin(\theta) |0^{\mu}\rangle V |\psi\rangle + \cos(\theta) |\Phi^{\perp}\rangle,\]where \(|\Phi^{\perp}\rangle\), which depends on \(|\psi\rangle\), satisfies \(\Pi |\Phi^{\perp}\rangle = 0\). This is the case of a block encoding of \(\sin(\theta) V\), and the probability \(p = \sin^{2}(\theta)\) of measuring the auxiliary qubits in the state \(|0^{\mu}\rangle\) is the same for every \(|\psi\rangle\). The circuit then boosts this amplitude with the operator
\[\mathbf{S} = -U \mathbf{R} U^{\dagger} \mathbf{R}, \qquad \mathbf{R} = 2 \Pi - \mathbb{1},\]which satisfies, for any integer \(l\),
\[\mathbf{S}^{l} U |0^{\mu}\rangle |\psi\rangle = \sin((2l + 1)\theta) |0^{\mu}\rangle V |\psi\rangle + \cos((2l + 1)\theta) |\Phi^{\perp}\rangle.\]In contrast with
qibo.models.amplification_operator(), \(\mathbf{S}\) does not reflect about the state \(U|0^{\mu}\rangle|\psi\rangle\), which is unknown since \(|\psi\rangle\) is not. Thus, the circuit amplifies the implementation of \(V\) without knowing, preparing or measuring the input state, so it can be a part of a larger circuit. It is applied to the circuit as \(U\), followed by \(l\) times a sign flip of \(|0^{\mu}\rangle\), \(U^{\dagger}\), the sign flip, \(U\) and a global phase of \(\pi\), since \(\mathbf{R}\) is minus the sign flip. The number \(l\) of iterations is determined in one of the following ways:niterationsis given, and \(l\) is its value;probabilityis given, which is \(p\), and \(l = \lfloor \pi / (4 \theta) \rfloor\). The probability of measuring the auxiliary qubits in the state \(|0^{\mu}\rangle\) is then at least \(\max(p, 1 - p)\);probabilityis given andexact=True. Then \(V\) is implemented exactly, i.e. the final state is \(|0^{\mu}\rangle V|\psi\rangle\). The circuit uses \(l = \lceil \pi / (4 \theta) - 1 / 2 \rceil\) iterations, which is a fraction of an iteration too many. To compensate it, the amplitude is lowered to \(\sin(\pi / (4l + 2))\) with an extra auxiliary qubit, which is the last qubit of the circuit, and rotated by a \(R_{y}\) gate. The extra qubit is also required to be in the state \(|0\rangle\) at the end, where it is found with certainty. For \(p = 1 / 4\), one iteration is enough, so \(U\) is used three times.
Example
import math from qibo import Circuit, gates from qibo.models import OAA # U acts on 1 auxiliary qubit and 1 system qubit. If the auxiliary qubit is found in # the state 0, which has probability sin(theta)^2 = 1 / 4, V is the X gate theta = math.pi / 6 unitary = Circuit(2) unitary.add(gates.X(1)) unitary.add(gates.RY(0, theta=math.pi - 2 * theta)) unitary.add(gates.H(1).controlled_by(0)) # one iteration implements V with certainty, so the system qubit, in the state 0, # is flipped without measuring the auxiliary qubit before circuit = Circuit(2) circuit.add(OAA(unitary, 1, probability=1 / 4)) circuit.add(gates.M(0, 1)) result = circuit(nshots=100) print(result.frequencies())
Counter({'01': 100})- Parameters:
unitary (
qibo.models.circuit.Circuit) – circuit \(U\) without measurements.nauxiliary (int) – number \(\mu \geq 1\) of auxiliary qubits, which are the first qubits of
unitary.niterations (int, optional) – number \(l \geq 0\) of applications of \(\mathbf{S}\). Exactly one of
niterationsandprobabilityhas to be given. Defaults toNone.probability (float, optional) – probability \(p \in (0, 1]\) of measuring the auxiliary qubits in the state \(|0^{\mu}\rangle\) after \(U\), from which the number of iterations is computed. Defaults to
None.exact (bool, optional) – If
True, \(V\) is implemented exactly, which requiresprobability. Defaults toFalse.backend (
qibo.backends.abstract.Backend, optional) – backend to be used in the calculation of the number of iterations and of the rotation angle. IfNone, it uses the current backend. Defaults toNone.kwargs (dict, optional) – Additional arguments used to initialize
qibo.models.circuit.Circuit, e.g.density_matrix=True. For details, see the documentation ofqibo.models.circuit.Circuit.
- Returns:
implementation of Oblivious Amplitude Amplification, with one more qubit than
unitaryifexact=True.- Return type:
References
1. D. W. Berry, A. M. Childs, R. Cleve, R. Kothari, and R. D. Somma, Exponential improvement in precision for simulating sparse Hamiltonians, Forum Math. Sigma 5, e8 (2017).
- qibo.models.QAA(algorithm, oracle, niterations=None, probability=None, exact=False, measure=True, backend=None, **kwargs)[source]#
Creates a circuit that implements Quantum Amplitude Amplification (QAA).
Given a circuit \(\mathcal{A}\) and a Boolean function \(\chi\) that marks “good” computational basis states, let \(a\) be the probability of measuring a good state in \(\mathcal{A}|0\rangle\), where \(|0\rangle\) is the all-zero state. The circuit applies \(\mathcal{A}\) and then \(m\) times the operator \(\mathbf{Q}\) of
qibo.models.amplification_operator(), such that the probability of measuring a good state becomes \(\sin^{2}((2m + 1)\theta_{a})\), with \(a = \sin^{2}(\theta_{a})\) and \(0 \leq \theta_{a} \leq \pi / 2\). The number \(m\) of iterations is determined in one of the following ways:niterationsis given, and \(m\) is its value;probabilityis given, which is \(a\), and \(m = \lfloor \pi / (4 \theta_{a}) \rfloor\). The probability of measuring a good state is then at least \(\max(a, 1 - a)\), and \(m\) is in \(O(1 / \sqrt{a})\), whereas \(O(1 / a)\) repetitions of \(\mathcal{A}\) are needed without amplification;probabilityis given andexact=True. Then the good states are found with certainty. The circuit uses \(m = \lceil \pi / (4 \theta_{a}) - 1 / 2 \rceil\) iterations, which is a fraction of an iteration too many. To compensate it, the success probability of \(\mathcal{A}\) is lowered to \(\sin^{2}(\pi / (4m + 2))\) with an extra auxiliary qubit, which is the last qubit of the circuit. It is rotated by \(R_{y}\) gate and a state is considered good only if \(\chi\) marks it and the auxiliary qubit is in the state \(|1\rangle\). The oracle is controlled by the auxiliary qubit, so all of its gates must be supported byqibo.models.circuit.Circuit.controlled_by().
The circuit acts on the qubits of
algorithm, plus the auxiliary qubit ifexact=True, and the measurement, ifmeasure=True, is applied to the qubits ofalgorithmonly. If the probability \(a\) is unknown, useqibo.models.QSearch().- Parameters:
algorithm (
qibo.models.circuit.Circuit) – circuit \(\mathcal{A}\) without measurements.oracle (
qibo.models.circuit.Circuit) – circuit \(\mathbf{S}_{\chi}\) that multiplies the good states by \(-1\), without measurements and with the same number of qubits asalgorithm. Seeqibo.models.amplification_operator().niterations (int, optional) – number \(m \geq 0\) of applications of \(\mathbf{Q}\). Exactly one of
niterationsandprobabilityhas to be given. Defaults toNone.probability (float, optional) – probability \(a \in (0, 1]\) of measuring a good state in \(\mathcal{A}|0\rangle\), from which the number of iterations is computed. Defaults to
None.exact (bool, optional) – If
True, the good states are found with certainty, which requiresprobability. Defaults toFalse.measure (bool, optional) – If
True, adds a measurement of the qubits ofalgorithmat the end of the circuit. Defaults toTrue.backend (
qibo.backends.abstract.Backend, optional) – backend to be used in the calculation of the number of iterations and of the rotation angle. IfNone, it uses the current backend. Defaults toNone.kwargs (dict, optional) – Additional arguments used to initialize
qibo.models.circuit.Circuit, e.g.density_matrix=True. For details, see the documentation ofqibo.models.circuit.Circuit.
- Returns:
implementation of Quantum Amplitude Amplification.
- Return type:
Example
from qibo import Circuit, gates from qibo.models import QAA # Hadamard gates on 3 qubits, and the oracle that marks the state |111> nqubits = 3 algorithm = Circuit(nqubits) algorithm.add(gates.H(qubit) for qubit in range(nqubits)) oracle = Circuit(nqubits) oracle.add(gates.CCZ(0, 1, 2)) # the initial probability of measuring |111> is 1 / 8 circuit = QAA(algorithm, oracle, probability=1 / 8) result = circuit(nshots=1000) print(result.frequencies().most_common(1)[0][0])
111
References
1. G. Brassard, P. Høyer, M. Mosca, and A. Tapp, Quantum Amplitude Amplification and Estimation, Contemporary Mathematics 305, 53 (2002).
- qibo.models.QSearch(algorithm, oracle, check, growth=1.2, max_rounds=30, seed=None, backend=None)[source]#
Finds a good state with Quantum Amplitude Amplification when its probability is unknown.
Let \(a\) be the unknown probability of measuring a good state in \(\mathcal{A}|0\rangle\), where \(\mathcal{A}\) is the circuit
algorithmand \(|0\rangle\) is the all-zero state. In each round \(\ell = 1, 2, \dots\), the algorithm:sets \(M = \lceil c^{\ell} \rceil\), where \(c\) is
growth;measures \(\mathcal{A}|0\rangle\), and stops if the outcome is good;
draws an integer \(j\) uniformly at random between \(1\) and \(M\), measures \(\mathbf{Q}^{j}\mathcal{A}|0\rangle\), with \(\mathbf{Q}\) the operator of
qibo.models.amplification_operator(), and stops if the outcome is good.
A good outcome is detected with the classical function
check. If \(a > 0\), the expected number of applications of \(\mathcal{A}\) and \(\mathcal{A}^{-1}\) is in \(\Theta(1 / \sqrt{a})\), and otherwise the search never finishes, which is why the number of rounds is limited bymax_rounds.- Parameters:
algorithm (
qibo.models.circuit.Circuit) – circuit \(\mathcal{A}\) without measurements.oracle (
qibo.models.circuit.Circuit) – circuit \(\mathbf{S}_{\chi}\) that multiplies the good states by \(-1\), without measurements and with the same number of qubits asalgorithm. Seeqibo.models.amplification_operator().check (Callable) – function that receives a measured bitstring, e.g.
"101", and returnsTrueif the state is good.growth (float, optional) – factor \(c\) by which the maximum number of iterations grows in each round, which has to be in the interval \((1, 2)\). Defaults to \(6 / 5\).
max_rounds (int, optional) – maximum number of rounds. Defaults to \(30\).
seed (int or
numpy.random.Generator, optional) – seed or generator used to draw \(j\). The measurements are sampled by the backend, so they are reproducible only if the seed of the backend is set, e.g. withqibo.backends.abstract.Backend.set_seed(). Defaults toNone.backend (
qibo.backends.abstract.Backend, optional) – backend to be used in the execution of the circuits. IfNone, it uses the current backend. Defaults toNone.
- Returns:
the good bitstring, or
Noneif none was found inmax_roundsrounds, and the number of applications of \(\mathcal{A}\) and \(\mathcal{A}^{-1}\) used.- Return type:
Example
from qibo import Circuit, gates from qibo.models import QSearch # Hadamard gates on 4 qubits, and the oracle that marks the state |1011> nqubits = 4 algorithm = Circuit(nqubits) algorithm.add(gates.H(qubit) for qubit in range(nqubits)) oracle = Circuit(nqubits) oracle.add(gates.X(1)) oracle.add(gates.Z(3).controlled_by(0, 1, 2)) oracle.add(gates.X(1)) bitstring, napplications = QSearch( algorithm, oracle, check=lambda bitstring: bitstring == "1011", seed=0 ) print(bitstring)
1011
References
1. G. Brassard, P. Høyer, M. Mosca, and A. Tapp, Quantum Amplitude Amplification and Estimation, Contemporary Mathematics 305, 53 (2002).
Amplitude estimation#
Quantum Amplitude Estimation (QAE)#
- qibo.models.QAE(algorithm, oracle, nqubits_counting, measure=True, **kwargs)[source]#
Creates a circuit that implements the canonical Quantum Amplitude Estimation.
Given a circuit \(\mathcal{A}\), which prepares the state \(|\Psi\rangle = \mathcal{A}|0\rangle\) from the all-zero state \(|0\rangle\), and an oracle that marks the “good” computational basis states, the circuit estimates the probability \(a = \sin^{2}(\theta_{a})\) of measuring a good state in \(|\Psi\rangle\), where \(\theta_{a} \in [0, \, \pi / 2]\). It acts on \(t + n\) qubits, with \(t\) being the number of counting qubits and \(n\) the number of qubits of \(\mathcal{A}\), and it is composed of the following steps:
\(\mathcal{A}\) on the last \(n\) qubits of the circuit;
the
qibo.models.QPE()of the amplification operator \(\mathbf{Q}\) ofqibo.models.amplification_operator(), with the \(t\) first qubits as counting qubits.
The state \(|\Psi\rangle\) is a superposition of two eigenvectors of \(\mathbf{Q}\), with eigenvalues \(e^{\pm 2 i \theta_{a}}\). Hence, if \(y\) is the integer represented by the bitstring of the counting qubits, and \(M = 2^{t}\), then \(y / M\) approximates \(\theta_{a} / \pi\) or \(1 - \theta_{a} / \pi\), and the estimate of \(a\) is \(\tilde{a} = \sin^{2}(\pi y / M)\). The phase \(y / M\) of the most probable outcome is given by
qibo.quantum_info.estimate_phase(). With probability of at least \(8 / \pi^{2}\),\[|\tilde{a} - a| \leq \frac{2 \pi \sqrt{a (1 - a)}}{M} + \frac{\pi^{2}}{M^{2}} \, .\]Note
\(\mathbf{Q}\) is applied \(2^{t} - 1\) times in total.
Example
import math from qibo import Circuit, gates from qibo.models import QAE from qibo.quantum_info import estimate_phase # state cos(theta) |0> + sin(theta) |1> with theta = pi / 8, and good state |1> theta = math.pi / 8 algorithm = Circuit(1) algorithm.add(gates.RY(0, theta=2 * theta)) oracle = Circuit(1) oracle.add(gates.Z(0)) # amplitude estimation with 3 counting qubits circuit = QAE(algorithm, oracle, 3) result = circuit(nshots=100) print(round(math.sin(math.pi * estimate_phase(result)) ** 2, 4))
0.1464
- Parameters:
algorithm (
qibo.models.circuit.Circuit) – circuit \(\mathcal{A}\). It cannot contain measurements.oracle (
qibo.models.circuit.Circuit) – circuit that multiplies the good states by \(-1\), e.g. a multi-controlledqibo.gates.Zgate. It must act on the same number of qubits asalgorithm, and it cannot contain measurements.nqubits_counting (int) – number of counting qubits \(t\), which sets the resolution \(2^{-t}\) of the estimate of \(\theta_{a} / \pi\).
measure (bool, optional) – If
True, adds a measurement of the counting qubits at the end of the circuit. Defaults toTrue.kwargs (dict, optional) – Additional arguments used to initialize
qibo.models.circuit.Circuit, e.g.density_matrix=True. For details, see the documentation ofqibo.models.circuit.Circuit.
- Returns:
implementation of the Quantum Amplitude Estimation.
- Return type:
References
1. G. Brassard, P. Høyer, M. Mosca, and A. Tapp, Quantum Amplitude Amplification and Estimation, Contemporary Mathematics 305, 53 (2002).
2. R. Cleve, A. Ekert, C. Macchiavello, and M. Mosca, Quantum algorithms revisited, Proc. R. Soc. Lond. A 454, 339 (1998).
Quantum Counting#
- qibo.models.Counting(oracle, nqubits_counting, measure=True, **kwargs)[source]#
Creates a circuit that implements the Quantum Counting algorithm.
Given a Boolean function \(\chi\) over the \(N = 2^{n}\) computational basis states of \(n\) qubits, the circuit estimates the number \(M\) of states that \(\chi\) marks with \(1\). It is the
qibo.models.QAE()of the uniform superposition of the \(N\) states, i.e. with Hadamard gates on every qubit as the circuit that prepares the state, in which the probability of measuring a marked state is \(M / N = \sin^{2}(\theta)\). The circuit acts on \(t + n\) qubits, with \(t\) being the number of counting qubits. If \(y\) is the integer represented by the bitstring of the counting qubits, and \(L = 2^{t}\), then the estimate of \(M\) is\[\tilde{M} = N \sin^{2}\left( \frac{\pi y}{L} \right) \, .\]The phase \(y / L\) of the most probable outcome is given by
qibo.quantum_info.estimate_phase(). With probability of at least \(8 / \pi^{2}\),\[|\tilde{M} - M| \leq \frac{2 \pi \sqrt{M (N - M)}}{L} + \frac{\pi^{2} N}{L^{2}} \, .\]For \(M = 0\), the estimate is exact, which decides if there are any marked states.
Example
import math from qibo import Circuit, gates from qibo.models import Counting from qibo.quantum_info import estimate_phase # oracle that marks the states 01 and 11 of 2 qubits oracle = Circuit(2) oracle.add(gates.Z(0)) # counting with 3 counting qubits circuit = Counting(oracle, 3) result = circuit(nshots=100) print(round(4 * math.sin(math.pi * estimate_phase(result)) ** 2))
2
- Parameters:
oracle (
qibo.models.circuit.Circuit) – circuit that multiplies the marked states by \(-1\), e.g. a multi-controlledqibo.gates.Zgate. It cannot contain measurements.nqubits_counting (int) – number of counting qubits \(t\), which sets the resolution \(2^{-t}\) of the estimate of \(\theta / \pi\).
measure (bool, optional) – If
True, adds a measurement of the counting qubits at the end of the circuit. Defaults toTrue.kwargs (dict, optional) – Additional arguments used to initialize
qibo.models.circuit.Circuit, e.g.density_matrix=True. For details, see the documentation ofqibo.models.circuit.Circuit.
- Returns:
implementation of the Quantum Counting.
- Return type:
References
1. G. Brassard, P. Høyer, and A. Tapp, Quantum Counting, Automata, Languages and Programming, LNCS 1443, 820 (1998).
2. G. Brassard, P. Høyer, M. Mosca, and A. Tapp, Quantum Amplitude Amplification and Estimation, Contemporary Mathematics 305, 53 (2002).
Maximum-likelihood Quantum Amplitude Estimation (MLQAE)#
- qibo.models.MLQAE(algorithm, oracle, check, nlevels=5, nshots=100, backend=None)[source]#
Estimates an amplitude with the Maximum-likelihood Quantum Amplitude Estimation.
Let \(a\) be the probability of measuring a good state in \(\mathcal{A}|0\rangle\), where \(\mathcal{A}\) is the circuit
algorithm, \(|0\rangle\) is the all-zero state, and the good states are marked by the oracle. Let \(\theta_{a} \in [0, \, \pi / 2]\) be such that \(a = \sin^{2}(\theta_{a})\). After \(m\) applications of the operator \(\mathbf{Q}\) ofqibo.models.amplification_operator(), the probability of measuring a good state is \(\sin^{2}((2m + 1)\theta_{a})\). Differently fromqibo.models.QAE(), there are no counting qubits nor controlled operations. Instead, the circuit \(\mathbf{Q}^{m}\mathcal{A}\) is measurednshotstimes for each \(m\) in \(\{0, \, 1, \, 2, \, 4, \, \dots, \, 2^{L - 1}\}\), where \(L\) isnlevels. If \(h_{m}\) of the outcomes are good for a given \(m\), the estimate is \(\sin^{2}(\hat{\theta})\), where \(\hat{\theta}\) maximizes the likelihood\[\prod_{m} \sin^{2}\left((2m + 1)\theta\right)^{h_{m}} \, \cos^{2}\left((2m + 1)\theta\right)^{N - h_{m}} \, ,\]with \(N\) being
nshots. The maximum is found with a grid search on \([0, \, \pi / 2]\), which is refined around the best point. The number of applications of \(\mathcal{A}\) and \(\mathcal{A}^{-1}\) is \(N \sum_{m} (2m + 1)\). With this exponential schedule of \(m\), the error is reported to approach the Heisenberg limit, which is inversely proportional to that number (Ref. [1]).Example
import math from qibo import Circuit, gates from qibo.models import MLQAE # state cos(theta) |0> + sin(theta) |1> with theta = 0.5, and good state |1> algorithm = Circuit(1) algorithm.add(gates.RY(0, theta=2 * 0.5)) oracle = Circuit(1) oracle.add(gates.Z(0)) estimate = MLQAE(algorithm, oracle, check=lambda bitstring: bitstring == "1") # the exact amplitude is sin(0.5)^2, which is approximately 0.23 print(round(estimate, 1))
0.2
- Parameters:
algorithm (
qibo.models.circuit.Circuit) – circuit \(\mathcal{A}\) without measurements.oracle (
qibo.models.circuit.Circuit) – circuit \(\mathbf{S}_{\chi}\) that multiplies the good states by \(-1\), without measurements and with the same number of qubits asalgorithm. Seeqibo.models.amplification_operator().check (Callable) – function that receives a measured bitstring, e.g.
"101", and returnsTrueif the state is good.nlevels (int, optional) – number \(L\) of levels of the schedule of the numbers of iterations, which are \(0\) and \(2^{k}\), for \(k = 0, \dots, L - 1\). Defaults to \(5\).
nshots (int, optional) – number of shots of each circuit. Defaults to \(100\).
backend (
qibo.backends.abstract.Backend, optional) – backend to be used in the execution of the circuits and in the maximization. IfNone, it uses the current backend. Defaults toNone.
- Returns:
estimate of \(a\), which belongs to the interval \([0, \, 1]\).
- Return type:
References
1. Y. Suzuki, S. Uno, R. Raymond, T. Tanaka, T. Onodera, and N. Yamamoto, Amplitude estimation without phase estimation, Quantum Inf. Process. 19, 75 (2020).
2. G. Brassard, P. Høyer, M. Mosca, and A. Tapp, Quantum Amplitude Amplification and Estimation, Contemporary Mathematics 305, 53 (2002).
Iterative Quantum Amplitude Estimation (IQAE)#
- class qibo.models.IQAE(circuit_a, circuit_q, alpha=0.05, epsilon=0.005, n_shots=1024, method='chernoff')[source]#
Model that performs the Iterative Quantum Amplitude Estimation algorithm.
The implemented class in this code utilizes the Iterative Quantum Amplitude Estimation (IQAE) algorithm, which was proposed in arxiv:1912.05559. The algorithm provides an estimated output that, with a probability
alpha, differs from the target value byepsilon. Bothalphaandepsiloncan be specified.Unlike Brassard’s original QAE algorithm arxiv:quant-ph/0005055, this implementation does not rely on Quantum Phase Estimation but instead is based solely on Grover’s algorithm. The IQAE algorithm employs a series of carefully selected Grover iterations to determine an estimate for the target amplitude.
- Parameters:
circuit_a (
qibo.models.circuit.Circuit) – quantum circuit that specifies the QAE problem.circuit_q (
qibo.models.circuit.Circuit) – quantum circuit of the Grover/Amplification operator.alpha (float) – confidence level, the target probability is 1 -
alpha, has values between 0 and 1.epsilon (float) – target precision for estimation target a, has values between 0 and 0.5.
method (str) – statistical method used to estimate the confidence intervals in each iteration, can be either chernoff (default) for the Chernoff intervals or beta for the Clopper-Pearson intervals.
n_shots (int) – number of shots.
- Raises:
ValueError – If
epsilonis not in (0, 0.5].ValueError – If
alphais not in (0, 1).ValueError – If
methodis not supported.ValueError – If the number of qubits in
circuit_ais greater than incircuit_q.
Example
from qibo import Circuit, gates from qibo.models import IQAE # Defining circuit A to integrate sin(x)^2 from [0,1] a_circuit = Circuit(2) a_circuit.add(gates.H(0)) a_circuit.add(gates.RY(q = 1, theta = 1 / 2)) a_circuit.add(gates.CU3(0, 1, 1, 0, 0)) # Defining circuit Q = -A S_0 A^-1 S_X q_circuit = Circuit(2) # S_X q_circuit.add(gates.Z(q = 1)) # A^-1 q_circuit = q_circuit + a_circuit.invert() # S_0 q_circuit.add(gates.X(0)) q_circuit.add(gates.X(1)) q_circuit.add(gates.CZ(0, 1)) # A q_circuit = q_circuit + a_circuit # Executing IQAE and obtaining the result iae = IQAE(a_circuit, q_circuit) results = iae.execute() integral_value = results.estimation integral_error = results.epsilon_estimated
- construct_qae_circuit(k)[source]#
Generates quantum circuit for QAE.
- Parameters:
k (int) – number of times the amplification operator
circuit_qis applied.- Returns:
The quantum circuit of the QAE algorithm.
- clopper_pearson(count, n, alpha)[source]#
Calculates the confidence interval for the quantity to estimate a.
- calc_L_range_CP(n_shots, upper_bound_t)[source]#
Calculate the confidence interval for the Clopper-Pearson method.
- calc_L_range_CH(n_shots, upper_bound_t)[source]#
Calculate the confidence interval for the Chernoff method.
- find_next_k(uppercase_k_i, up_i, theta_l, theta_u, r=2)[source]#
Find the largest integer
uppercase_ksuch that the intervaluppercase_k* [theta_l,theta_u] lies completely in [0, pi] or [pi, 2 pi].- Parameters:
uppercase_k_i (int) – the current
uppercase_ksuchuppercase_k= 4k+ 2, wherekis the power of the operatorcircuit_q.up_i (bool) – boolean flag of whether theta_interval lies in the upper half-circle [0, pi] or in the lower one [pi, 2 pi].
theta_l (float) – the current lower limit of the confidence interval for the angle theta.
theta_u (float) – the current upper limit of the confidence interval for the angle theta.
r (int) – lower bound for
uppercase_k.
- Returns:
The next power K_i, and boolean flag for the extrapolated interval.
- execute(backend=None)[source]#
Execute IQAE algorithm.
- Parameters:
backend – the qibo backend.
- Returns:
A
qibo.models.IterativeAmplitudeEstimationResultresults object.
Oracle algorithms#
Deutsch-Jozsa#
- qibo.models.DeutschJozsa(oracle, measure=True, **kwargs)[source]#
Creates a circuit that implements the Deutsch-Jozsa algorithm.
Given a Boolean function \(f : \{0, \, 1\}^{n} \to \{0, \, 1\}\) that is promised to be either constant or balanced, i.e. equal to \(1\) for exactly half of the inputs, the algorithm decides which one it is with a single query to the oracle \(U_{f} \ket{x} \ket{y} = \ket{x} \ket{y \oplus f(x)}\), where \(\oplus\) is the sum modulo \(2\). The circuit acts on \(n + 1\) qubits, with the first \(n\) being the input qubits and the last one the output qubit of the oracle, and it is composed of the following steps:
a
qibo.gates.Xgate on the output qubit, and a Hadamard gate on every qubit;the oracle \(U_{f}\);
a Hadamard gate on each of the input qubits;
the measurement of the input qubits, if
measure=True.
The output qubit is in the state \(\ket{-}\), so that the oracle only multiplies \(\ket{x}\) by \((-1)^{f(x)}\). Then, the probability of measuring the input qubits in the state \(\ket{0}^{\otimes \, n}\) is \(1\) if \(f\) is constant, and \(0\) if it is balanced.
Example
from qibo import Circuit, gates from qibo.models import DeutschJozsa # oracle of the balanced function that is equal to the first input bit oracle = Circuit(4) oracle.add(gates.CNOT(0, 3)) circuit = DeutschJozsa(oracle) result = circuit(nshots=10) # the outcome is not 000, so the function is balanced print(result.frequencies())
Counter({'100': 10})- Parameters:
oracle (
qibo.models.circuit.Circuit) – circuit that implements \(U_{f}\), which has \(n + 1\) qubits, with the output qubit being the last one. It cannot contain measurements.measure (bool, optional) – If
True, adds a measurement of the input qubits at the end of the circuit. Defaults toTrue.kwargs (dict, optional) – Additional arguments used to initialize
qibo.models.circuit.Circuit, e.g.density_matrix=True. For details, see the documentation ofqibo.models.circuit.Circuit.
- Returns:
implementation of the Deutsch-Jozsa algorithm.
- Return type:
References
1. D. Deutsch and R. Jozsa, Rapid solution of problems by quantum computation, Proc. R. Soc. Lond. A 439, 553 (1992).
2. R. Cleve, A. Ekert, C. Macchiavello, and M. Mosca, Quantum algorithms revisited, Proc. R. Soc. Lond. A 454, 339 (1998).
Bernstein-Vazirani#
- qibo.models.BernsteinVazirani(oracle, measure=True, **kwargs)[source]#
Creates a circuit that implements the Bernstein-Vazirani algorithm.
Given a Boolean function \(f(x) = s \cdot x \oplus c\), where \(s \in \{0, \, 1\}^{n}\) is a hidden string, \(\cdot\) is the bitwise inner product modulo \(2\), and \(c \in \{0, \, 1\}\), the algorithm finds \(s\) with a single query to the oracle \(U_{f} \ket{x} \ket{y} = \ket{x} \ket{y \oplus f(x)}\), where \(\oplus\) is the sum modulo \(2\). The circuit acts on \(n + 1\) qubits, with the first \(n\) being the input qubits and the last one the output qubit of the oracle. It is the same circuit as the one of
qibo.models.DeutschJozsa(): the output qubit is in the state \(\ket{-}\), so that the oracle multiplies \(\ket{x}\) by \((-1)^{s \cdot x}\), which is undone by the Hadamard gates on the input qubits, that are left in the state \(\ket{s}\). Ifmeasure=True, the qubit \(k\) of the measured bitstring is the bit \(s_{k}\).Example
from qibo import Circuit, gates from qibo.models import BernsteinVazirani # oracle of the function with the hidden string s = 101 oracle = Circuit(4) oracle.add(gates.CNOT(0, 3)) oracle.add(gates.CNOT(2, 3)) circuit = BernsteinVazirani(oracle) result = circuit(nshots=10) print(result.frequencies())
Counter({'101': 10})- Parameters:
oracle (
qibo.models.circuit.Circuit) – circuit that implements \(U_{f}\), which has \(n + 1\) qubits, with the output qubit being the last one. It cannot contain measurements.measure (bool, optional) – If
True, adds a measurement of the input qubits at the end of the circuit. Defaults toTrue.kwargs (dict, optional) – Additional arguments used to initialize
qibo.models.circuit.Circuit, e.g.density_matrix=True. For details, see the documentation ofqibo.models.circuit.Circuit.
- Returns:
implementation of the Bernstein-Vazirani algorithm.
- Return type:
References
1. E. Bernstein and U. Vazirani, Quantum complexity theory, SIAM J. Comput. 26, 1411 (1997).
2. R. Cleve, A. Ekert, C. Macchiavello, and M. Mosca, Quantum algorithms revisited, Proc. R. Soc. Lond. A 454, 339 (1998).
Quantum arithmetic#
Quantum Adders#
- qibo.models.Adder(nbits, method='Cuccaro', **kwargs)[source]#
Creates a circuit that adds two integers with the adder chosen by
method.Given two \(n\)-bit non-negative integers \(a\) and \(b\), where \(n\) is
nbits, all of the adders perform\[\ket{a} \, \ket{b} \, \ket{0} \mapsto \ket{a} \, \ket{a + b} \, \ket{0} \, ,\]where the last register holds the auxiliary qubits, if the adder has any. The first \(n\) qubits hold \(a\), and the next \(n + 1\) qubits hold \(b\), with the overflow bit being the last one, which must be in the state \(\ket{0}\) at the beginning. In every register, the least significant bit comes first. The adders differ in the number of auxiliary qubits and of gates:
"Cuccaro":qibo.models.Cuccaro(), ripple-carry adder with one auxiliary qubit;"DKRS":qibo.models.DKRS(), carry-lookahead adder with logarithmic depth and a linear number of auxiliary qubits;"Draper":qibo.models.Draper(), adder in the Fourier basis, without auxiliary qubits;"Gidney":qibo.models.Gidney(), ripple-carry adder that uses measurements to uncompute the carries, with \(n - 1\) auxiliary qubits;"TTK":qibo.models.TTK(), ripple-carry adder ofqibo.gates.TOFFOLIandqibo.gates.CNOTgates, without auxiliary qubits;"VBE":qibo.models.VBE(), ripple-carry adder with \(n\) auxiliary qubits.
Example
from qibo import Circuit, gates from qibo.models import Adder nbits = 2 adder = Adder(nbits, method="TTK") # a = 3 in the qubits 0 and 1, and b = 1 in the qubits 2, 3 and 4 circuit = Circuit(adder.nqubits) circuit.add(gates.X(0)) circuit.add(gates.X(1)) circuit.add(gates.X(2)) circuit.add(adder) circuit.add(gates.M(*range(nbits, 2 * nbits + 1))) result = circuit(nshots=1) bitstring = next(iter(result.frequencies(binary=True))) # the least significant bit comes first print(int(bitstring[::-1], 2))
4
- Parameters:
nbits (int) – number of bits \(n\) of each of the integers to be added.
method (str, optional) – adder to be used. Either
"Cuccaro","DKRS","Draper","Gidney","TTK"or"VBE". Defaults to"Cuccaro".kwargs (dict, optional) – Additional arguments used to initialize
qibo.models.circuit.Circuit, e.g.density_matrix=True. For details, see the documentation ofqibo.models.circuit.Circuit.
- Returns:
implementation of the chosen adder.
- Return type:
References
1. S. A. Cuccaro, T. G. Draper, S. A. Kutin, and D. P. Moulton, A new quantum ripple-carry addition circuit, arXiv:quant-ph/0410184.
2. T. G. Draper, S. A. Kutin, E. M. Rains, and K. M. Svore, A logarithmic-depth quantum carry-lookahead adder, Quantum Inf. Comput. 6, 351 (2006).
3. T. G. Draper, Addition on a Quantum Computer, arXiv:quant-ph/0008033.
4. C. Gidney, Halving the cost of quantum addition, Quantum 2, 74 (2018).
5. Y. Takahashi, S. Tani, and N. Kunihiro, Quantum addition circuits and unbounded fan-out, Quantum Inf. Comput. 10, 872 (2010).
6. V. Vedral, A. Barenco, and A. Ekert, Quantum networks for elementary arithmetic operations, Phys. Rev. A 54, 147 (1996).
- qibo.models.Cuccaro(nbits, **kwargs)[source]#
Creates a circuit that implements the Cuccaro-Draper-Kutin-Moulton ripple-carry adder.
Given two \(n\)-bit non-negative integers \(a\) and \(b\), where \(n\) is
nbits, the circuit performs\[\ket{a} \, \ket{b} \, \ket{0} \mapsto \ket{a} \, \ket{a + b \bmod 2^{n + 1}} \, \ket{0} \, .\]It acts on \(2n + 2\) qubits, which are split into three registers:
the first \(n\) qubits hold \(a\), which is left unchanged;
the next \(n + 1\) qubits hold \(b\), which is replaced by \(a + b\). The last qubit of this register is the overflow bit, which is in the state \(\ket{0}\) at the beginning if \(b < 2^{n}\), so that the sum is exact;
the last qubit is a single auxiliary qubit, the carry-in. It must be in the state \(\ket{0}\) at the beginning, and it is returned to it at the end.
In every register, the \(k\)-th qubit holds the bit \(2^{k}\), i.e. the least significant bit comes first. The circuit is composed of \(n\) majority (MAJ) blocks, which compute the carries in place, a
qibo.gates.CNOTthat copies the last carry into the overflow qubit, and \(n\) unmajority-and-add (UMA) blocks, which uncompute the carries and write the sum bits, in reverse order. It has \(2n\)qibo.gates.TOFFOLIgates and \(4n + 1\)qibo.gates.CNOTgates.Example
from qibo import Circuit, gates from qibo.models import Cuccaro nbits = 2 adder = Cuccaro(nbits) # a = 3 in the qubits 0 and 1, and b = 1 in the qubits 2, 3 and 4 circuit = Circuit(adder.nqubits) circuit.add(gates.X(0)) circuit.add(gates.X(1)) circuit.add(gates.X(2)) circuit.add(adder) circuit.add(gates.M(*range(nbits, 2 * nbits + 1))) result = circuit(nshots=1) bitstring = next(iter(result.frequencies(binary=True))) # the least significant bit comes first print(int(bitstring[::-1], 2))
4
- Parameters:
nbits (int) – number of bits \(n\) of each of the integers to be added.
kwargs (dict, optional) – Additional arguments used to initialize
qibo.models.circuit.Circuit, e.g.density_matrix=True. For details, see the documentation ofqibo.models.circuit.Circuit.
- Returns:
implementation of the Cuccaro ripple-carry adder.
- Return type:
References
1. S. A. Cuccaro, T. G. Draper, S. A. Kutin, and D. P. Moulton, A new quantum ripple-carry addition circuit, arXiv:quant-ph/0410184.
- qibo.models.DKRS(nbits, **kwargs)[source]#
Creates a circuit that implements the Draper-Kutin-Rains-Svore (DKRS) carry-lookahead adder.
Given two \(n\)-bit non-negative integers \(a\) and \(b\), where \(n\) is
nbits, the circuit performs\[\ket{a} \, \ket{b} \, \ket{0} \mapsto \ket{a} \, \ket{a + b} \, \ket{0} \, .\]It acts on \(3n + 2 + m\) qubits, with \(m = n - w(n) - \lfloor \log_{2} n \rfloor\) and \(w(n)\) being the number of ones in the binary representation of \(n\). The qubits are split into three registers:
the first \(n\) qubits hold \(a\), which is left unchanged;
the next \(n + 1\) qubits hold \(b\), which is replaced by \(a + b\). The last qubit of this register is the overflow bit, which must be in the state \(\ket{0}\) at the beginning;
the last \(n + 1 + m\) qubits are auxiliary qubits. They must be in the state \(\ket{0}\) at the beginning, and they are returned to it at the end.
In every register, the \(k\)-th qubit holds the bit \(2^{k}\), i.e. the least significant bit comes first. The carries are computed with a tree of
qibo.gates.TOFFOLIgates, so that the depth of the circuit is logarithmic in \(n\). The sum is first written in the auxiliary qubits by an out-of-place adder. Then, the inverse of the same adder, applied to the complement of the sum, erases \(b\), and the registers are swapped.Example
from qibo import Circuit, gates from qibo.models import DKRS nbits = 2 adder = DKRS(nbits) # a = 3 in the qubits 0 and 1, and b = 1 in the qubits 2, 3 and 4 circuit = Circuit(adder.nqubits) circuit.add(gates.X(0)) circuit.add(gates.X(1)) circuit.add(gates.X(2)) circuit.add(adder) circuit.add(gates.M(*range(nbits, 2 * nbits + 1))) result = circuit(nshots=1) bitstring = next(iter(result.frequencies(binary=True))) # the least significant bit comes first print(int(bitstring[::-1], 2))
4
- Parameters:
nbits (int) – number of bits \(n\) of each of the integers to be added.
kwargs (dict, optional) – Additional arguments used to initialize
qibo.models.circuit.Circuit, e.g.density_matrix=True. For details, see the documentation ofqibo.models.circuit.Circuit.
- Returns:
implementation of the DKRS adder.
- Return type:
References
1. T. G. Draper, S. A. Kutin, E. M. Rains, and K. M. Svore, A logarithmic-depth quantum carry-lookahead adder, Quantum Inf. Comput. 6, 351 (2006).
- qibo.models.Draper(nbits, **kwargs)[source]#
Creates a circuit that implements the Draper quantum Fourier transform (QFT) adder.
Given two \(n\)-bit non-negative integers \(a\) and \(b\), where \(n\) is
nbits, the circuit performs\[\ket{a} \, \ket{b} \mapsto \ket{a} \, \ket{a + b \bmod 2^{n + 1}} \, .\]It acts on \(2n + 1\) qubits, and it does not need auxiliary qubits. The first \(n\) qubits hold \(a\), which is left unchanged, and the last \(n + 1\) qubits hold \(b\), which is replaced by \(a + b\). The last qubit of the second register is the overflow bit, which is in the state \(\ket{0}\) at the beginning if \(b < 2^{n}\), so that the sum is exact.
In every register, the \(k\)-th qubit holds the bit \(2^{k}\), i.e. the least significant bit comes first. The circuit is composed of the following steps:
the
qibo.models.QFTon the register of \(b\), without swaps;qibo.gates.CU1gates, controlled by the qubits of \(a\), which add \(a\) to \(b\) in the Fourier basis, by rotating the phases of the qubits of \(b\);the inverse
qibo.models.QFTon the register of \(b\), without swaps.
The smallest rotation angle is \(2 \pi / 2^{n + 1}\).
Example
from qibo import Circuit, gates from qibo.models import Draper nbits = 2 adder = Draper(nbits) # a = 3 in the qubits 0 and 1, and b = 1 in the qubits 2, 3 and 4 circuit = Circuit(adder.nqubits) circuit.add(gates.X(0)) circuit.add(gates.X(1)) circuit.add(gates.X(2)) circuit.add(adder) circuit.add(gates.M(*range(nbits, 2 * nbits + 1))) result = circuit(nshots=1) bitstring = next(iter(result.frequencies(binary=True))) # the least significant bit comes first print(int(bitstring[::-1], 2))
4
- Parameters:
nbits (int) – number of bits \(n\) of each of the integers to be added.
kwargs (dict, optional) – Additional arguments used to initialize
qibo.models.circuit.Circuit, e.g.density_matrix=True. For details, see the documentation ofqibo.models.circuit.Circuit.
- Returns:
implementation of the Draper adder.
- Return type:
References
1. T. G. Draper, Addition on a Quantum Computer, arXiv:quant-ph/0008033.
- qibo.models.Gidney(nbits, **kwargs)[source]#
Creates a circuit that implements the Gidney adder.
Given two \(n\)-bit non-negative integers \(a\) and \(b\), where \(n\) is
nbits, the circuit performs\[\ket{a} \, \ket{b} \, \ket{0} \mapsto \ket{a} \, \ket{a + b} \, \ket{0} \, .\]It acts on \(3n\) qubits, which are split into three registers:
the first \(n\) qubits hold \(a\), which is left unchanged;
the next \(n + 1\) qubits hold \(b\), which is replaced by \(a + b\). The last qubit of this register is the overflow bit, which must be in the state \(\ket{0}\) at the beginning;
the last \(n - 1\) qubits are auxiliary qubits that store the carries. They must be in the state \(\ket{0}\) at the beginning, and they are returned to it at the end.
In every register, the \(k\)-th qubit holds the bit \(2^{k}\), i.e. the least significant bit comes first. Each carry is computed in a qubit in the state \(\ket{0}\) with a temporary logical-AND, which has four
qibo.gates.Torqibo.gates.TDGgates. Then, it is erased without them: the qubit is measured in the \(X\) basis, and, if the outcome is \(1\), aqibo.gates.CZgate, which is applied with aqibo.gates.CU1conditioned on the outcome, fixes the phase. Hence, the circuit has \(4n\) of these gates, and \(n - 1\) measurements withcollapseset toTrue. Because of them, each shot has to be simulated separately, and the circuit cannot be inverted.Example
from qibo import Circuit, gates from qibo.models import Gidney nbits = 2 adder = Gidney(nbits) # a = 3 in the qubits 0 and 1, and b = 1 in the qubits 2, 3 and 4 circuit = Circuit(adder.nqubits) circuit.add(gates.X(0)) circuit.add(gates.X(1)) circuit.add(gates.X(2)) circuit.add(adder) circuit.add(gates.M(*range(nbits, 2 * nbits + 1))) result = circuit(nshots=1) bitstring = next(iter(result.frequencies(binary=True))) # the least significant bit comes first print(int(bitstring[::-1], 2))
4
- Parameters:
nbits (int) – number of bits \(n\) of each of the integers to be added.
kwargs (dict, optional) – Additional arguments used to initialize
qibo.models.circuit.Circuit, e.g.density_matrix=True. For details, see the documentation ofqibo.models.circuit.Circuit.
- Returns:
implementation of the Gidney adder.
- Return type:
References
1. C. Gidney, Halving the cost of quantum addition, Quantum 2, 74 (2018).
- qibo.models.TTK(nbits, **kwargs)[source]#
Creates a circuit that implements the Takahashi-Tani-Kunihiro (TTK) adder.
Given two \(n\)-bit non-negative integers \(a\) and \(b\), where \(n\) is
nbits, the circuit performs\[\ket{a} \, \ket{b} \mapsto \ket{a} \, \ket{a + b \bmod 2^{n + 1}} \, .\]It acts on \(2n + 1\) qubits, and it does not need auxiliary qubits. The first \(n\) qubits hold \(a\), which is left unchanged, and the last \(n + 1\) qubits hold \(b\), which is replaced by \(a + b\). The last qubit of the second register is the overflow bit, which is in the state \(\ket{0}\) at the beginning if \(b < 2^{n}\), so that the sum is exact.
In every register, the \(k\)-th qubit holds the bit \(2^{k}\), i.e. the least significant bit comes first. The circuit only has
qibo.gates.TOFFOLIandqibo.gates.CNOTgates. The carries are computed in place, using the qubits of \(a\), and then uncomputed while the sum bits are written in \(b\). For \(n \geq 2\), it has \(2n - 1\)qibo.gates.TOFFOLIgates and \(5n - 5\)qibo.gates.CNOTgates. For \(n = 1\), it is a half adder, with one of each.Example
from qibo import Circuit, gates from qibo.models import TTK nbits = 2 adder = TTK(nbits) # a = 3 in the qubits 0 and 1, and b = 1 in the qubits 2, 3 and 4 circuit = Circuit(adder.nqubits) circuit.add(gates.X(0)) circuit.add(gates.X(1)) circuit.add(gates.X(2)) circuit.add(adder) circuit.add(gates.M(*range(nbits, 2 * nbits + 1))) result = circuit(nshots=1) bitstring = next(iter(result.frequencies(binary=True))) # the least significant bit comes first print(int(bitstring[::-1], 2))
4
- Parameters:
nbits (int) – number of bits \(n\) of each of the integers to be added.
kwargs (dict, optional) – Additional arguments used to initialize
qibo.models.circuit.Circuit, e.g.density_matrix=True. For details, see the documentation ofqibo.models.circuit.Circuit.
- Returns:
implementation of the TTK adder.
- Return type:
References
1. Y. Takahashi, S. Tani, and N. Kunihiro, Quantum addition circuits and unbounded fan-out, Quantum Inf. Comput. 10, 872 (2010).
- qibo.models.VBE(nbits, **kwargs)[source]#
Creates a circuit that implements the Vedral-Barenco-Ekert (VBE) plain adder.
Given two \(n\)-bit non-negative integers \(a\) and \(b\), where \(n\) is
nbits, the circuit performs\[\ket{a} \, \ket{b} \, \ket{0} \mapsto \ket{a} \, \ket{a + b} \, \ket{0} \, .\]It acts on \(3n + 1\) qubits, which are split into three registers:
the first \(n\) qubits hold \(a\), which is left unchanged;
the next \(n + 1\) qubits hold \(b\), which is replaced by \(a + b\). The last qubit of this register is the overflow bit, and it must be in the state \(\ket{0}\) at the beginning;
the last \(n\) qubits are auxiliary qubits that store the carries. They must be in the state \(\ket{0}\) at the beginning, and they are returned to it at the end.
In every register, the \(k\)-th qubit holds the bit \(2^{k}\), i.e. the least significant bit comes first. The circuit is composed of \(n\) blocks that compute the carries, followed by blocks that compute the sum bits while the carries are uncomputed, in reverse order. It has \(4n - 2\)
qibo.gates.TOFFOLIgates and \(4n\)qibo.gates.CNOTgates.Example
from qibo import Circuit, gates from qibo.models import VBE nbits = 2 adder = VBE(nbits) # a = 3 in the qubits 0 and 1, and b = 1 in the qubits 2, 3 and 4 circuit = Circuit(adder.nqubits) circuit.add(gates.X(0)) circuit.add(gates.X(1)) circuit.add(gates.X(2)) circuit.add(adder) circuit.add(gates.M(*range(nbits, 2 * nbits + 1))) result = circuit(nshots=1) bitstring = next(iter(result.frequencies(binary=True))) # the least significant bit comes first print(int(bitstring[::-1], 2))
4
- Parameters:
nbits (int) – number of bits \(n\) of each of the integers to be added.
kwargs (dict, optional) – Additional arguments used to initialize
qibo.models.circuit.Circuit, e.g.density_matrix=True. For details, see the documentation ofqibo.models.circuit.Circuit.
- Returns:
implementation of the VBE plain adder.
- Return type:
References
1. V. Vedral, A. Barenco, and A. Ekert, Quantum networks for elementary arithmetic operations, Phys. Rev. A 54, 147 (1996).
Block encodings and signal processing#
Block Encoding#
- qibo.models.block_encoding_circuit(matrix, method='dense', alpha=None, backend=None)[source]#
Creates a block encoding of a matrix.
Let \(A\) be
matrix, a square matrix that is padded with zeros up to dimension \(2^{n}\) if needed, with \(n \ge 1\). The circuit acts on \(a\) auxiliary qubits, followed by \(n\) system qubits, and the block of its unitary in which the auxiliary qubits start and end in \(|0\rangle\) is \(A / \alpha\), where \(\alpha\) is a normalization. Both methods have a cost that grows exponentially with \(n\).method="dense": \(a = 1\). With \(B = A / \alpha\), whose singular values are at most one, the circuit is a single gate for the unitary dilation\[\begin{split}U = \begin{pmatrix} B & \sqrt{\mathbb{1} - B B^{\dagger}} \\ \sqrt{\mathbb{1} - B^{\dagger} B} & -B^{\dagger} \end{pmatrix},\end{split}\]where \(\mathbb{1}\) is the identity and \(B^{\dagger}\) the conjugate transpose of \(B\). The matrix square roots are computed from the singular value decomposition of \(B\).
method="lcu": the matrix is decomposed as a sum of Pauli strings, \(A = \sum_{i} c_{i} P_{i}\), with complex coefficients \(c_{i}\), and the circuit is the one ofqibo.models.lcu_circuit(). The normalization is \(\alpha = \sum_{i} |c_{i}|\), and \(a = \max(1, \lceil \log_{2} L \rceil)\), with \(L\) the number of non-zero coefficients.
- Parameters:
matrix (ArrayLike) – square matrix \(A\).
method (str, optional) –
"dense"for the unitary dilation or"lcu"for the linear combination of unitaries of the Pauli strings. Defaults to"dense".alpha (float, optional) – normalization \(\alpha\) if
method="dense", which has to be at least the spectral norm ofmatrix. IfNone, it is the spectral norm if this is larger than one, and one otherwise. It is not used bymethod="lcu", for which it has to beNone. Defaults toNone.backend (
qibo.backends.abstract.Backend, optional) – backend to be used in the calculation. IfNone, it uses the current backend. Defaults toNone.
- Returns:
circuit on \(a + n\) qubits, with the auxiliary qubits at the first qubits, the normalization \(\alpha\), and the number \(a\) of auxiliary qubits. The circuit and the number of auxiliary qubits are the arguments of
qibo.models.qsvt_circuit().- Return type:
Example
Encode \(X / 2\), with \(X\) the Pauli-\(X\) matrix. The amplitudes with the auxiliary qubits in \(|0\rangle\) are those of \(|1\rangle / 2\) for the dense method, and those of \(|1\rangle\) for the LCU method, whose normalization is \(1 / 2\).
from qibo import get_backend from qibo.models import block_encoding_circuit backend = get_backend() matrix = 0.5 * backend.matrices.X circuit, alpha, nauxiliary = block_encoding_circuit(matrix) state = circuit().state()[:2] print(backend.allclose(state, backend.cast([0.0, 0.5])), alpha, nauxiliary) circuit, alpha, nauxiliary = block_encoding_circuit(matrix, method="lcu") state = circuit().state()[:2] print(backend.allclose(state, backend.cast([0.0, 1.0])), alpha, nauxiliary)
True 1.0 1 True 0.5 1
References
1. A. Gilyén, Y. Su, G. H. Low, and N. Wiebe, Quantum singular value transformation and beyond: exponential improvements for quantum matrix arithmetics, Proceedings of the 51st Annual ACM SIGACT Symposium on Theory of Computing (STOC ‘19), 193-204 (2019).
Linear Combination of Unitaries#
- qibo.models.lcu_circuit(unitaries, coefficients, backend=None)[source]#
Creates a linear combination of unitaries (LCU) circuit.
Let \(U_{i}\) be the unitary of the \(i\)-th circuit of
unitaries, with \(i = 0, \dots, L - 1\), let \(c_{i}\) be its complex coefficient, and let \(\alpha = \sum_{i} |c_{i}|\). The circuit acts on \(a = \max(1, \lceil \log_{2} L \rceil)\) auxiliary qubits, followed by the qubits of the unitaries, and block-encodes the operator \(A / \alpha\), with \(A = \sum_{i} c_{i} U_{i}\). That is, the block of the circuit unitary in which the auxiliary qubits start and end in \(|0\rangle\) is \(A / \alpha\). The circuit is \(\mathrm{PREPARE}_{L}^{\dagger} \, \mathrm{SELECT} \, \mathrm{PREPARE}_{R}\), where \(\mathrm{PREPARE}_{L}\) and \(\mathrm{PREPARE}_{R}\) are created withqibo.models.lcu_prepare(), and \(\mathrm{SELECT}\) is created withqibo.models.lcu_select().- Parameters:
unitaries (list[
qibo.models.circuit.Circuit]) – circuits on the same number of qubits that implement \(U_{i}\). They have to be exact, including their global phase, since they are applied under control.coefficients (ArrayLike) – one-dimensional array of the (complex) coefficients \(c_{i}\), with at least one non-zero element.
backend (
qibo.backends.abstract.Backend, optional) – backend to be used in the calculation. IfNone, it uses the current backend. Defaults toNone.
- Returns:
the circuit, with the auxiliary qubits at the first qubits, the normalization \(\alpha\), and the number \(a\) of auxiliary qubits. The last two are the arguments of
qibo.models.qsvt_circuit()for which the circuit is a block encoding of \(A / \alpha\).- Return type:
Example
Apply \((X + Z) / 2\) to \(|0\rangle\), where \(X\) and \(Z\) are Pauli matrices. The amplitudes with the auxiliary qubit in \(|0\rangle\) are those of \(|+\rangle / \sqrt{2}\).
from qibo import Circuit, gates, get_backend from qibo.models import lcu_circuit backend = get_backend() pauli_x = Circuit(1) pauli_x.add(gates.X(0)) pauli_z = Circuit(1) pauli_z.add(gates.Z(0)) circuit, alpha, nauxiliary = lcu_circuit([pauli_x, pauli_z], [0.5, 0.5]) target = Circuit(1) target.add(gates.H(0)) state = circuit().state()[:2] print( backend.allclose(state, target().state() / backend.sqrt(2)), alpha, nauxiliary, )
True 1.0 1
References
1. A. M. Childs and N. Wiebe, Hamiltonian simulation using linear combinations of unitary operations, Quantum Information & Computation 12, 901-924 (2012).
- qibo.models.lcu_prepare(coefficients, backend=None)[source]#
Creates the \(\mathrm{PREPARE}\) oracles of a linear combination of unitaries (LCU).
Let \(c_{i}\) be the \(i\)-th (complex) element of
coefficients, with \(i = 0, \dots, L - 1\), and let \(\alpha = \sum_{i} |c_{i}|\). The oracles act on \(a = \max(1, \lceil \log_{2} L \rceil)\) auxiliary qubits. When applied to \(|0\rangle\), \(\mathrm{PREPARE}_{L}\) and \(\mathrm{PREPARE}_{R}\) load the amplitudes\[\mathrm{PREPARE}_{L} |0\rangle = \sum_{i} \sqrt{\frac{|c_{i}|}{\alpha}} \, |i\rangle \quad \text{and} \quad \mathrm{PREPARE}_{R} |0\rangle = \sum_{i} \sqrt{\frac{|c_{i}|}{\alpha}} \, \frac{c_{i}}{|c_{i}|} \, |i\rangle \, ,\]respectively, with the amplitudes of \(|i\rangle\), for \(i \geq L\), set to zero. For real and non-negative coefficients, they are the same oracle. The oracles are built with
qibo.models.encodings.binary_encoder(), with the Mottonen parametrization, since the resulting circuits have an exact inverse. Together withqibo.models.lcu_select(), they build the block encoding \(\mathrm{PREPARE}_{L}^{\dagger} \, \mathrm{SELECT} \, \mathrm{PREPARE}_{R}\) of \(\sum_{i} c_{i} U_{i} / \alpha\).- Parameters:
coefficients (ArrayLike) – one-dimensional array of the (complex) coefficients \(c_{i}\), with at least one non-zero element.
backend (
qibo.backends.abstract.Backend, optional) – backend to be used in the calculation. IfNone, it uses the current backend. Defaults toNone.
- Returns:
the circuits of \(\mathrm{PREPARE}_{L}\) and \(\mathrm{PREPARE}_{R}\), both on \(a\) qubits, the normalization \(\alpha\), and the number \(a\) of auxiliary qubits.
- Return type:
Example
Prepare the amplitudes of the coefficients \(3\) and \(-1\), for which \(\alpha = 4\).
from qibo import get_backend from qibo.models import lcu_prepare backend = get_backend() prepare_left, prepare_right, alpha, nauxiliary = lcu_prepare([3.0, -1.0]) left = backend.cast([0.75**0.5, 0.25**0.5], dtype="complex128") right = backend.cast([0.75**0.5, -(0.25**0.5)], dtype="complex128") print( backend.allclose(prepare_left().state(), left), backend.allclose(prepare_right().state(), right), alpha, nauxiliary, )
True True 4.0 1
References
1. A. M. Childs and N. Wiebe, Hamiltonian simulation using linear combinations of unitary operations, Quantum Information & Computation 12, 901-924 (2012).
- qibo.models.lcu_select(unitaries, nauxiliary=None, backend=None)[source]#
Creates the \(\mathrm{SELECT}\) oracle of a linear combination of unitaries (LCU).
Let \(U_{i}\) be the unitary of the \(i\)-th circuit of
unitaries, with \(i = 0, \dots, L - 1\). The oracle acts on \(a\) auxiliary qubits, followed by the qubits of the unitaries, and applies \(U_{i}\) to the latter when the auxiliary qubits are in the computational basis state \(|i\rangle\),\[\mathrm{SELECT} = \sum_{i = 0}^{L - 1} |i\rangle\langle i| \otimes U_{i} + \sum_{i = L}^{2^{a} - 1} |i\rangle\langle i| \otimes I \, .\]Each unitary is applied under the control of all the auxiliary qubits, with \(X\) gates that map \(|i\rangle\) into \(|1 \dots 1\rangle\). Gates that are already controlled are supported. A unitary with no gates is the identity, and is skipped.
- Parameters:
unitaries (list[
qibo.models.circuit.Circuit]) – circuits on the same number of qubits that implement \(U_{i}\). They have to be exact, including their global phase, since they are applied under control.nauxiliary (int, optional) – number \(a\) of auxiliary qubits. It has to satisfy \(2^{a} \geq L\). If
None, it is \(\max(1, \lceil \log_{2} L \rceil)\). Defaults toNone.backend (
qibo.backends.abstract.Backend, optional) – backend to be used in the calculation. IfNone, it uses the current backend. Defaults toNone.
- Returns:
circuit of \(\mathrm{SELECT}\), with the auxiliary qubits at the first qubits.
- Return type:
Example
Apply the Pauli matrices \(X\) and \(Z\) to \(|0\rangle\), selected by an auxiliary qubit in \(|+\rangle\). The state is \((|0\rangle|1\rangle + |1\rangle|0\rangle) / \sqrt{2}\).
from qibo import Circuit, gates, get_backend from qibo.models import lcu_select backend = get_backend() pauli_x = Circuit(1) pauli_x.add(gates.X(0)) pauli_z = Circuit(1) pauli_z.add(gates.Z(0)) select = lcu_select([pauli_x, pauli_z]) circuit = Circuit(2) circuit.add(gates.H(0)) circuit.add(select.on_qubits(0, 1)) target = backend.cast([0.0, 1.0, 1.0, 0.0], dtype="complex128") print(backend.allclose(circuit().state(), target / backend.sqrt(2)))
True
References
1. A. M. Childs and N. Wiebe, Hamiltonian simulation using linear combinations of unitary operations, Quantum Information & Computation 12, 901-924 (2012).
Quantum Signal Processing#
- qibo.models.qsp_phases(coefficients, sine_coefficients=None, method=None, extraction='phase_sums', backend=None)[source]#
Computes the phases of a quantum signal processing (QSP) circuit.
method=None: QSP of Ref. [1]. Given the series \(A(\theta) = \sum_{k = 0}^{N/2} a_{k} \cos(k \theta)\) and \(C(\theta) = \sum_{k = 1}^{N/2} c_{k} \sin(k \theta)\), with even \(N\), it finds \(N\) phases such that \(\langle + | V(\theta) | + \rangle = A(\theta) + i C(\theta)\). Here, \(V(\theta)\) is the product of the \(N\) single-qubit rotations of angle \(\theta\) about the axes of the \(xy\)-plane given by the phases, and \(|+\rangle\) is the \(+1\) eigenstate of the Pauli- \(X\) operator. Since \(V(0)\) is the identity, the target has to satisfy \(A(0) = 1\). It is rescaled if \(|A + i C| > 1\).method="fourier": Fourier-based QSP of Ref. [2]. Given the coefficients \(c_{m}\) of the Fourier series \(\tilde{g}(x) = \sum_{m = -q/2}^{q/2} c_{m} \, e^{i m x}\), with even \(q\), it finds the angles of \(q + 1\) single-qubit gates whose product has \(\tilde{g}(x)\) as its upper-left matrix element. The series is divided by \(\max_{x} |\tilde{g}(x)|\) if it is larger than one.
- Parameters:
coefficients (ArrayLike) – if
method=None, cosine coefficients \((a_{0}, \dots, a_{N/2})\). Ifmethod="fourier", Fourier coefficients \((c_{-q/2}, \dots, c_{q/2})\).sine_coefficients (ArrayLike, optional) – sine coefficients \((c_{1}, \dots, c_{N/2})\). Required if
method=Noneand not used otherwise. Defaults toNone.method (str, optional) –
Nonefor QSP of Ref. [1] or"fourier"for Fourier-based QSP of Ref. [2]. Defaults toNone.extraction (str, optional) – how the phases are extracted if
method=None."phase_sums"follows Ref. [3] and loses precision for \(N \gtrsim 30\), while"layer_stripping"removes one rotation at a time and stays accurate for larger \(N\). Defaults to"phase_sums".backend (
qibo.backends.abstract.Backend, optional) – backend to be used in the calculation. IfNone, it uses the current backend. Defaults toNone.
- Returns:
phases for
qibo.models.qsp_circuit()with the samemethod. An array of length \(N\) ifmethod=None, or an array of shape \((q + 1, 4)\) ifmethod="fourier".- Return type:
ArrayLike
References
1. G. H. Low and I. L. Chuang, Optimal Hamiltonian Simulation by Quantum Signal Processing, Phys. Rev. Lett. 118, 010501 (2017). 2. T. L. Silva, L. Borges, and L. Aolita, Fourier-based quantum signal processing, arXiv:2206.02826. 3. G. H. Low, T. J. Yoder, and I. L. Chuang, The methodology of resonant equiangular composite quantum gates, Phys. Rev. X 6, 041067 (2016).
- qibo.models.qsp_circuit(oracle, phases, method=None)[source]#
Creates a quantum signal processing (QSP) circuit.
The circuit interleaves queries to
oraclewith rotations of an ancilla qubit, placed at qubit \(0\). The remaining qubits are those oforacle.method=None: QSP of Ref. [1].oracleimplements a unitary \(W\), which is queried \(N\) times. The block of the circuit unitary with the ancilla starting and ending in \(|0\rangle\) applies \(A(\theta) + i C(\theta)\) to each eigenphase \(\theta\) of \(W\), where \(A\) and \(C\) are the trigonometric polynomials encoded inphases.method="fourier": Fourier-based QSP of Ref. [2].oracleimplements \(e^{-i t H}\) for a Hermitian operator \(H\) and a time \(t\), and is queried \(q\) times under control. The same block of the circuit unitary is \(\tilde{g}(H t)\), where \(\tilde{g}\) is the Fourier series encoded inphases.
- Parameters:
oracle (
qibo.models.circuit.Circuit) – circuit on \(n\) qubits that implements \(W\) or \(e^{-i t H}\), depending onmethod. It has to be exact, including its global phase, since it is applied under control.phases (ArrayLike) – output of
qibo.models.qsp_phases()for the samemethod.method (str, optional) –
Nonefor QSP of Ref. [1] or"fourier"for Fourier-based QSP of Ref. [2]. Defaults toNone.
- Returns:
circuit on \(n + 1\) qubits, with the ancilla at qubit \(0\).
- Return type:
Example
Apply \((1 + W) / 2\), with \(W = X\), to \(|0\rangle\). The amplitudes with the ancilla in \(|0\rangle\) are those of \(|+\rangle / \sqrt{2}\).
from qibo import Circuit, gates, get_backend from qibo.models import qsp_circuit, qsp_phases backend = get_backend() walk = Circuit(1) walk.add(gates.X(0)) # cosine and sine series of (1 + exp(i theta)) / 2 phases = qsp_phases([0.5, 0.5], [0.5]) circuit = qsp_circuit(walk, phases) target = Circuit(1) target.add(gates.H(0)) state = circuit().state()[:2] print(backend.allclose(state, target().state() / backend.sqrt(2), atol=1e-4))
True
Invert a rotation with the Fourier series \(\tilde{g}(x) = e^{i x}\). The amplitudes with the ancilla in \(|0\rangle\) are those of the inverse rotation applied to \(|0\rangle\).
from qibo import Circuit, gates, get_backend from qibo.models import qsp_circuit, qsp_phases backend = get_backend() evolution = Circuit(1) evolution.add(gates.RX(0, 0.6)) # coefficients of exp(-i x), 1, and exp(i x) phases = qsp_phases([0.0, 0.0, 1.0], method="fourier") circuit = qsp_circuit(evolution, phases, method="fourier") target = Circuit(1) target.add(gates.RX(0, -0.6)) state = circuit().state()[:2] print(backend.allclose(state, target().state(), atol=1e-6))
True
References
1. G. H. Low and I. L. Chuang, Optimal Hamiltonian Simulation by Quantum Signal Processing, Phys. Rev. Lett. 118, 010501 (2017). 2. T. L. Silva, L. Borges, and L. Aolita, Fourier-based quantum signal processing, arXiv:2206.02826.
Quantum Singular Value Transformation#
- qibo.models.qsvt_phases(coefficients, backend=None)[source]#
Computes the phases of a quantum singular value transformation (QSVT) circuit.
Given the Chebyshev series \(P(x) = \sum_{k = 0}^{d} c_{k} T_{k}(x)\) of a real polynomial of degree \(d \ge 1\) with the parity of \(d\) and \(|P(x)| \le 1\) for \(x \in [-1, 1]\), it finds the phases for which
qibo.models.qsvt_circuit()applies \(P\) to the singular values (Corollary 11 of Ref. [1]). The polynomial is completed into a unitary matrix whose entries are trigonometric polynomials, using the spectral factorization of \(1 - P^{2}\) thatqibo.models.qsp_phases()uses for the Fourier-based QSP, and the phases are then extracted one at a time as in Ref. [2].The coefficients are divided by its (grid-estimated) \(\max_{x} |P(x)|\) if it is larger than one. If \(|P|\) reaches one, the polynomial is implemented with a relative error of about \(10^{-6}\) for degrees up to \(100\) and \(10^{-5}\) up to \(300\), and the error is much smaller for polynomials that stay away from one.
- Parameters:
coefficients (ArrayLike) – Chebyshev coefficients \((c_{0}, \dots, c_{d})\). The degree is that of the last non-zero coefficient, and the coefficients of the opposite parity must vanish. Those with modulus below \(10^{-12}\) times the largest one are taken as zero.
backend (
qibo.backends.abstract.Backend, optional) – backend to be used in the calculation. IfNone, it uses the current backend. Defaults toNone.
- Returns:
\(d + 1\) phases. The first \(d\) are those of the rotations controlled by the projector, in the order that they are applied, and the last one is the final rotation of the signal qubit.
- Return type:
ArrayLike
References
1. A. Gilyén, Y. Su, G. H. Low, and N. Wiebe, Quantum singular value transformation and beyond: exponential improvements for quantum matrix arithmetics, Proceedings of the 51st Annual ACM SIGACT Symposium on Theory of Computing (STOC ‘19), 193-204 (2019). 2. J. Haah, Product decomposition of periodic functions in quantum signal processing, Quantum 3, 190 (2019).
- qibo.models.qsvt_circuit(block_encoding, phases, nancillas)[source]#
Creates a quantum singular value transformation (QSVT) circuit.
Let \(U\) be the unitary of
block_encoding, which acts on \(a\) ancilla qubits and \(n\) system qubits, and let \(A = (\langle 0|^{\otimes a} \otimes \mathbb{1}) \, U \, (|0\rangle^{\otimes a} \otimes \mathbb{1})\) be the matrix that it encodes, with singular value decomposition \(A = \sum_{i} \varsigma_{i} |w_{i}\rangle\langle v_{i}|\). The block of the circuit unitary in which the signal qubit and the ancillas start and end in \(|0\rangle\) applies a polynomial \(P\) of degree \(d\) to the singular values,\[\begin{split}P^{(SV)}(A) = \begin{cases} \sum_{i} P(\varsigma_{i}) \, |w_{i}\rangle\langle v_{i}| & d \text{ odd,} \\ \sum_{i} P(\varsigma_{i}) \, |v_{i}\rangle\langle v_{i}| & d \text{ even.} \end{cases}\end{split}\]The circuit queries \(U\) and \(U^{\dagger}\) alternately \(d\) times (Theorem 2 of Ref. [1]) and uses a single extra qubit, the signal qubit, which controls the sign of the phases of the rotations that are controlled by the projector on the ancillas in \(|0\rangle\).
- Parameters:
block_encoding (
qibo.models.circuit.Circuit) – circuit that implements \(U\). Its firstnancillasqubits are the ancillas.phases (ArrayLike) – phases of the polynomial, e.g. the output of
qibo.models.qsvt_phases().nancillas (int) – number \(a\) of ancilla qubits of
block_encoding.
- Returns:
circuit with the signal qubit at position \(0\), followed by the qubits of
block_encodingin the same order.- Return type:
Example
Apply the cubic Chebyshev polynomial \(T_{3}(x) = 4 x^{3} - 3 x\) to the singular value \(1/2\) of a block-encoding of \(|+\rangle / 2\). Since \(T_{3}(1/2) = -1\), the amplitudes with the signal qubit and the ancilla in \(|0\rangle\) are those of \(-|+\rangle\).
import math from qibo import Circuit, gates, get_backend from qibo.models import qsvt_circuit, qsvt_phases backend = get_backend() # prepares |+> with amplitude 1/2 when the ancilla is in |0> block_encoding = Circuit(2) block_encoding.add(gates.RY(0, 2 * math.pi / 3)) block_encoding.add(gates.H(1)) # Chebyshev series of the polynomial, i.e. only the coefficient of T_3 phases = qsvt_phases([0.0, 0.0, 0.0, 1.0]) circuit = qsvt_circuit(block_encoding, phases, nancillas=1) target = Circuit(1) target.add(gates.H(0)) state = circuit().state()[:2] print(backend.allclose(state, -target().state(), atol=1e-6))
True
References
1. A. Gilyén, Y. Su, G. H. Low, and N. Wiebe, Quantum singular value transformation and beyond: exponential improvements for quantum matrix arithmetics, Proceedings of the 51st Annual ACM SIGACT Symposium on Theory of Computing (STOC ‘19), 193-204 (2019).
Hamiltonian diagonalization#
Double-Bracket Iterations#
- class qibo.models.DoubleBracketIteration(hamiltonian, backend=None)[source]#
Diagonalization double-bracket iteration (DBI) of a Hamiltonian.
Given a Hamiltonian \(H_{0}\), the \(k\)-th recursion step of the DBI is
\[H_{k+1} = e^{s_{k} \, W_{k}} \, H_{k} \, e^{-s_{k} \, W_{k}} \, , \quad W_{k} = [D_{k}, H_{k}] \, ,\]where \(D_{k}\) is a diagonal operator and \(s_{k}\) is the step duration. If \(D_{k}\) is not specified, the dephasing \(\Delta(H_{k})\), i.e. the diagonal restriction of \(H_{k}\), is used. This choice, called canonical bracket, gives rise to the Głazek-Wilson-Wegner (GWW) DBI, which decreases the Hilbert-Schmidt norm of the off-diagonal restriction of \(H_{k}\) for sufficiently short durations.
Two types of rotation are available. In the
"double_bracket"rotation, the exact unitary \(e^{-s_{k} \, W_{k}}\) is applied. In the"group_commutator"rotation, the unitary \(e^{i \sqrt{s_{k}} \, D_{k}} \, e^{i \sqrt{s_{k}} \, H_{k}} \, e^{-i \sqrt{s_{k}} \, D_{k}}\) is applied instead, which is the group commutator iteration (GCI) that can be implemented in a quantum computer throughcircuit(). A negativestep_durationcorresponds to flipping the sign of \(D_{k}\).- Parameters:
hamiltonian (ArrayLike or
qibo.hamiltonians.abstract.AbstractHamiltonian) – Hamiltonian \(H_{0}\) to be diagonalized. Must be hermitian.backend (
qibo.backends.abstract.Backend, optional) – backend to be used in the execution. IfNone, it uses the current backend. Defaults toNone.
Example
from qibo.backends import NumpyBackend from qibo.hamiltonians import TFIM from qibo.models import DoubleBracketIteration backend = NumpyBackend() hamiltonian = TFIM(3, h=1.0, backend=backend) dbi = DoubleBracketIteration(hamiltonian, backend=backend) norms = dbi.run(nsteps=5) print(norms[0] > norms[-1])
True
References
1. M. Gluza, Double-bracket quantum algorithms for diagonalization, Quantum (2024), arXiv:2206.11772.
- property energy_fluctuations: ArrayLike#
sqrt{langle H_{k}^{2} rangle - langle H_{k} rangle^{2}} of the current Hamiltonian \(H_{k}\) in all computational basis states.
Fluctuations vanish for eigenstates of \(H_{k}\).
- Type:
Energy fluctuations
- Type:
math
- property off_diagonal_norm: float#
Hilbert-Schmidt norm \(\|\sigma(H_{k})\|_{\text{HS}}\) of the off-diagonal restriction of the current Hamiltonian \(H_{k}\).
- circuit(backend=None)[source]#
Circuit \(V_{K}\) of the group commutator iteration (GCI) after \(K\) steps.
The circuit is built recursively from the recorded step durations \(s_{k}\) and diagonal operators \(D_{k}\) as
\[V_{k+1} = V_{k} \, e^{i \sqrt{s_{k}} \, D_{k}} \, V_{k}^{\dagger} \, e^{i \sqrt{s_{k}} \, H_{0}} \, V_{k} \, e^{-i \sqrt{s_{k}} \, D_{k}} \, ,\]with \(V_{0} = \mathbb{1}\), so that \(H_{K} = V_{K}^{\dagger} \, H_{0} \, V_{K}\) and \(V_{K} |\mu\rangle\) approximates an eigenstate of \(H_{0}\) for a computational basis state \(|\mu\rangle\). It only contains evolutions under \(H_{0}\) and under the diagonal operators, and its number of evolutions under \(H_{0}\) is \((3^{K} - 1) / 2\). It reproduces the iteration exactly, and therefore is only available when the
"group_commutator"rotation was used in all steps.- Parameters:
backend (
qibo.backends.abstract.Backend, optional) – backend used to build the evolution gates. IfNone, it uses the backend of the iteration. Defaults toNone.- Returns:
Circuit implementing \(V_{K}\).
- Return type:
- Raises:
ValueError – If the dimension of the Hamiltonian is not a power of two, or if any step of the iteration did not use the
"group_commutator"rotation.
- optimize_step(diagonal=None, rotation='double_bracket', step_max=None, nsamples=100)[source]#
Step duration that maximally decreases the off-diagonal norm in one step.
A grid search over \([-s_{\max}, s_{\max}]\) (\([0, s_{\max}]\) for the canonical bracket) is followed by a bounded local refinement around the best point.
- Parameters:
diagonal (ArrayLike, optional) – diagonal operator \(D_{k}\), given either as the vector of its real diagonal entries or as a real diagonal matrix. If
None, the dephasing of the current Hamiltonian is used. Defaults toNone.rotation (str, optional) – either
"double_bracket"or"group_commutator". Defaults to"double_bracket".step_max (float, optional) – upper limit of the search. If
None, it is set to \(\pi / \|[D_{k}, H_{k}]\|\), with the operator norm. Defaults toNone.nsamples (int, optional) – number of points of the grid search. Defaults to \(100\).
- Returns:
Optimal step duration.
- Return type:
- run(nsteps, diagonals=None, rotation='double_bracket', step_max=None, nsamples=100)[source]#
Runs
nstepsgreedy recursion steps of the iteration.In each step, the step duration is optimized for the canonical bracket and for each diagonal operator in
diagonals, and the choice yielding the smallest off-diagonal norm is applied.- Parameters:
nsteps (int) – number of recursion steps.
diagonals (list[ArrayLike], optional) – candidate real diagonal operators \(D_{k}\), e.g. products of Pauli-\(Z\) operators, to be considered in addition to the canonical bracket in every step. Defaults to
None.rotation (str, optional) – either
"double_bracket"or"group_commutator". Defaults to"double_bracket".step_max (float, optional) – see
optimize_step(). Defaults toNone.nsamples (int, optional) – see
optimize_step(). Defaults to \(100\).
- Returns:
Off-diagonal norms before the first step and after each step.
- Return type:
- step(step_duration, diagonal=None, rotation='double_bracket')[source]#
Performs one recursion step and updates the iterated Hamiltonian.
- Parameters:
step_duration (float) – step duration \(s_{k}\).
diagonal (ArrayLike, optional) – diagonal operator \(D_{k}\), given either as the vector of its real diagonal entries or as a real diagonal matrix. If
None, the dephasing of the current Hamiltonian is used. Defaults toNone.rotation (str, optional) – either
"double_bracket"or"group_commutator". Defaults to"double_bracket".
- Returns:
Iterated Hamiltonian \(H_{k+1}\).
- Return type:
ArrayLike