Utility Functions#
Functions that can be used to calculate metrics and distance measures on classical probability arrays, and to convert classical bitstrings and measurement outcomes into phases.
Bitstring to phase#
- qibo.quantum_info.bitstring_to_phase(bitstring)[source]#
Converts a bitstring into the phase it encodes as a binary fraction.
The bitstring \(b_{1} b_{2} \cdots b_{t}\), with \(b_{1}\) being the most significant bit, is mapped to
\[\varphi = 0.b_{1} b_{2} \cdots b_{t} = \sum_{j=1}^{t} \, b_{j} \, 2^{-j} \, ,\]which belongs to the interval \([0, \, 1)\) (for \(t > 53\), the result can be rounded to \(1\), as it is a
float). This is the outcome of measuring the \(t\) counting qubits at the end of quantum phase estimation, where the eigenvalue of the unitary is :math:`e^{2 pi i- arphi}`. The corresponding angle is
:math:`2 pi
- arphi`. In the keys of
qibo.result.MeasurementOutcomes.frequencies() with
binary=True, the first bit is the outcome of the first measured qubit, which must then be the most significant one.- Args:
- bitstring (str or list or tuple or ndarray): sequence of bits, e.g.
"0101"or [0, 1, 0, 1], with the most significant bit first. It cannot be an integer, since the leading zeros of a bitstring are part of the phase and are lost in the integer representation. ATypeErroris raised for integers and for any other object that is not a sequence.
- bitstring (str or list or tuple or ndarray): sequence of bits, e.g.
- Returns:
float: phase encoded in
bitstring.
Example:
from qibo.quantum_info import bitstring_to_phase # 0.0101 in binary is 1/4 + 1/16 print(bitstring_to_phase("0101"))
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.
Estimate phase#
- qibo.quantum_info.estimate_phase(outcomes)[source]#
Estimates the phase from the outcomes of the counting qubits of quantum phase estimation.
The estimate is the phase encoded in the most probable outcome, as given by
qibo.quantum_info.bitstring_to_phase(). If several outcomes are equally probable, the first one is used. The outcomes can be given asthe result of the execution of a circuit that measures the counting qubits, e.g. a
qibo.models.QPEcircuit withmeasure=True, which must have been executed with a finite number of shots, or the result of joining, withqibo.measurements.MeasurementResult.join(), the outcomes of the measurements of aqibo.models.IQPE()circuit;a mapping from bitstrings to their frequencies or probabilities, e.g. the output of
qibo.result.MeasurementOutcomes.frequencies()withbinary=True;a one-dimensional array with the probabilities, or frequencies, of the \(2^{t}\) outcomes of \(t\) counting qubits, e.g. the output of
qibo.result.MeasurementOutcomes.probabilities(), in which the index of each element is the integer represented by the bitstring.
- :param outcomes (
qibo.result.MeasurementOutcomesor:qibo.measurements.MeasurementResultor dict or ndarray): measurement outcomes of the counting qubits. If it is a mapping, the bitstrings must all have the same length.
- Returns:
estimate of the phase, which belongs to the interval \([0, \, 1)\).
- Return type:
- Parameters:
outcomes (Mapping[str, float] | ArrayLike | MeasurementOutcomes | MeasurementResult) –
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) unitary = Circuit(1) unitary.add(gates.U1(0, theta=2 * math.pi * 5 / 16)) 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)) print(estimate_phase(result.frequencies()))
0.3125 0.3125
References
1. M. A. Nielsen and I. L. Chuang, Quantum Computation and Quantum Information, Cambridge University Press (2010), Sec. 5.2.1.
Hamming weight#
- qibo.quantum_info.hamming_weight(bitstring, return_indexes=False)[source]#
Calculates the Hamming weight of a bitstring.
The Hamming weight of a bitstring is the number of \(1\)’s that the bitstring contains.
- Parameters:
- Returns:
Hamming weight of bitstring or list of indexes of non-zero elements.
- Return type:
Hamming distance#
- qibo.quantum_info.hamming_distance(bitstring_1, bitstring_2, return_indexes=False)[source]#
Calculates the Hamming distance between two bitstrings.
This is done by calculating the Hamming weight (
qibo.quantum_info.utils.hamming_weight()) of| bitstring_1 - bitstring_2 |.- Parameters:
- Returns:
Hamming distance or list of indexes of non-zero elements.
- Return type:
Hadamard Transform#
- qibo.quantum_info.hadamard_transform(array, implementation='fast', backend=None)[source]#
Calculates the (fast) Hadamard Transform \(\text{HT}\) of a \(2^{n}\)-dimensional vector or \(2^{n} \times 2^{n}\) matrix \(A\), where \(n\) is the number of qubits in the system. If \(A\) is a vector, then
\[\text{HT}(A) = \frac{1}{2^{n / 2}} \, H^{\otimes n} \, A \,\]where \(H\) is the
qibo.gates.Hgate. If \(A\) is a matrix, then\[\text{HT}(A) = \frac{1}{2^{n}} \, H^{\otimes n} \, A \, H^{\otimes n} \, .\]- Parameters:
array (ArrayLike) – array or matrix.
implementation (str, optional) – if
"regular", it uses the straightforward implementation of the algorithm with computational complexity of \(\mathcal{O}(2^{2n})\) for vectors and \(\mathcal{O}(2^{3n})\) for matrices. If"fast", computational complexity is \(\mathcal{O}(n \, 2^{n})\) in both cases.backend (
qibo.backends.abstract.Backend, optional) – backend to be used in the execution. IfNone, it uses the current backend. Defaults toNone.
- Returns:
(Fast) Hadamard Transform of
array.- Return type:
ArrayLike
Hellinger distance#
- qibo.quantum_info.hellinger_distance(prob_dist_p, prob_dist_q, validate=False, backend=None)[source]#
Calculates the Hellinger distance \(H\) between two discrete probability distributions.
For probabilities \(\mathbf{p}\) and \(\mathbf{q}\), it is defined as
\[H(\mathbf{p} \, , \, \mathbf{q}) = \frac{1}{\sqrt{2}} \, \| \sqrt{\mathbf{p}} - \sqrt{\mathbf{q}} \|_{2}\]where \(\|\cdot\|_{2}\) is the Euclidean norm.
- Parameters:
prob_dist_p (ArrayLike or list) – discrete probability distribution \(p\).
prob_dist_q (ArrayLike or list) – discrete probability distribution \(q\).
validate (bool, optional) – If
True, checks if \(p\) and \(q\) are proper probability distributions. Defaults toFalse.backend (
qibo.backends.abstract.Backend, optional) – backend to be used in the execution. IfNone, it uses the current backend. Defaults toNone.
- Returns:
Hellinger distance \(H(p, q)\).
- Return type:
Hellinger fidelity#
- qibo.quantum_info.hellinger_fidelity(prob_dist_p, prob_dist_q, validate=False, backend=None)[source]#
Calculates the Hellinger fidelity between two discrete probability distributions.
For probabilities \(p\) and \(q\), the fidelity is defined as
\[(1 - H^{2}(p, q))^{2} \, ,\]where \(H(p, q)\) is the
qibo.quantum_info.hellinger_distance().- Parameters:
prob_dist_p (ArrayLike or list) – discrete probability distribution \(p\).
prob_dist_q (ArrayLike or list) – discrete probability distribution \(q\).
validate (bool, optional) – if
True, checks if \(p\) and \(q\) are proper probability distributions. Defaults toFalse.backend (
qibo.backends.abstract.Backend, optional) – backend to be used in the execution. IfNone, it uses the current backend. Defaults toNone.
- Returns:
Hellinger fidelity.
- Return type:
Hellinger shot error#
- qibo.quantum_info.hellinger_shot_error(prob_dist_p, prob_dist_q, nshots, validate=False, backend=None)[source]#
Calculates the Hellinger fidelity error between two discrete probability distributions estimated from finite statistics.
It is calculated propagating the probability error of each state of the system. The complete formula is:
\[\frac{1 - H^{2}(p, q)}{\sqrt{nshots}} \, \sum_{k} \, \left(\sqrt{p_{k} \, (1 - q_{k})} + \sqrt{q_{k} \, (1 - p_{k})}\right)\]where \(H(p, q)\) is the
qibo.quantum_info.hellinger_distance(), and \(1 - H^{2}(p, q)\) is the square root of theqibo.quantum_info.hellinger_fidelity().- Parameters:
prob_dist_p (ArrayLike or list) – discrete probability distribution \(p\).
prob_dist_q (ArrayLike or list) – discrete probability distribution \(q\).
nshots (int) – number of shots we used to run the circuit to obtain \(p\) and \(q\).
validate (bool, optional) – if
True, checks if \(p\) and \(q\) are proper probability distributions. Defaults toFalse.backend (
qibo.backends.abstract.Backend, optional) – backend to be used in the execution. IfNone, it uses the current backend. Defaults toNone.
- Returns:
Hellinger fidelity error.
- Return type:
Total variation distance#
- qibo.quantum_info.total_variation_distance(prob_dist_p, prob_dist_q, validate=False, backend=None)[source]#
Calculate the total variation distance between two discrete probability distributions.
For probabilities \(p\) and \(q\), the total variation distance is defined as
\[\operatorname{TVD}(p, \, q) = \frac{1}{2} \, \|p - q\|_{1} = \frac{1}{2} \, \sum_{x} \, \left|p(x) - q(x)\right| \, ,\]where \(\|\cdot\|_{1}\) denotes the \(\ell_{1}\)-norm.
- Parameters:
prob_dist_p (ArrayLike or list) – discrete probability distribution \(p\).
prob_dist_q (ArrayLike or list) – discrete probability distribution \(q\).
validate (bool, optional) – if
True, checks if \(p\) and \(q\) are proper probability distributions. Defaults toFalse.backend (
qibo.backends.abstract.Backend, optional) – backend to be used in the execution. IfNone, it uses the current backend. Defaults toNone.
- Returns:
Total variation distance measure.
- Return type:
Haar integral#
- qibo.quantum_info.haar_integral(nqubits, power_t, samples=None, backend=None)[source]#
Returns the integral over pure states over the Haar measure.
\[\int_{\text{Haar}} d\psi \, \left(|\psi\rangle\right.\left. \langle\psi|\right)^{\otimes t}\]- Parameters:
nqubits (int) – Number of qubits.
power_t (int) – power that defines the \(t\)-design.
samples (int, optional) – If
None, estimated the integral exactly. Otherwise, number of samples to estimate the integral via sampling. Defaults toNone.backend (
qibo.backends.abstract.Backend, optional) – backend to be used in the execution. IfNone, it uses the current backend. Defaults toNone.
- Returns:
Estimation of the Haar integral.
- Return type:
ArrayLike
Note
The exact method (
samples=None) is implemented using Lemma 34 of Kliesch and Roth (2020).
Parameterized quantum circuit integral#
- qibo.quantum_info.pqc_integral(circuit, power_t, samples, backend=None)[source]#
Returns the integral over pure states generated by uniformly sampling in the parameter space described by a parameterized circuit.
\[\int_{\Theta} d\psi \, \left(|\psi_{\theta}\rangle\right.\left. \langle\psi_{\theta}|\right)^{\otimes t}\]- Parameters:
circuit (
qibo.models.Circuit) – Parametrized circuit.power_t (int) – power that defines the \(t\)-design.
samples (int) – number of samples to estimate the integral.
backend (
qibo.backends.abstract.Backend, optional) – backend to be used in the execution. IfNone, it uses the current backend. Defaults toNone.
- Returns:
Estimation of the integral.
- Return type:
ArrayLike
Decompose permutation into the fewest pairwise transpositions#
- qibo.quantum_info.decompose_permutation(sigma, m, backend=None)[source]#
Given permutation
sigmaon \(\{0, \, 1, \, \dots, \, d-1\}\) and a power‑of‑two budgetm, this function factorssigmainto the fewest layers \(\sigma_{1}, \, \sigma_{2}, \, \cdots, \, \sigma_{t}\) such that: - each layer has at most \(m\) disjoint transpositions - each layer moves a power‑of‑two number of indices.We do this as follows: 1) Cycle extraction – split sigma into disjoint cycles. 2) Star factorisation – a k‑cycle becomes (k-1) hub–spoke swaps. 3) Greedy packing – merge swaps into layers while keeping rules.
- Parameters:
- Returns:
\(t\) layers of pairwise transpositions.
- Return type: