Probability() usage

According to the documentation, there is a class probability() which will return probabilities of each computational basis state.
Can anybody enligthen me with an example? I cant get it working after some attemps

Hi @Miguel_Fernandez!

There is currently an open PR on our GitHub repo, adding a new prob() measurement function. You can install this branch using pip:

pip install git+https://github.com/XanaduAI/PennyLane.git@prob_fn

Once this branch is installed, you can import this new experimental measurement function and use it in a QNode like so:

import numpy as np
import pennylane as qml
from pennylane.beta import prob

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)
def circuit(x):
    qml.Hadamard(wires=0)
    qml.RY(x, wires=0)
    qml.RX(x, wires=1)
    qml.CNOT(wires=[0, 1])
    return prob(wires=[0])

Note:

  • prob() must accept a wires argument, which specifies for which wires the marginal probability is returned.

  • This feature is experimental, and might change before the next release!

  • Currently, it only supports the default.qubit device, and the PennyLane-qiskit plugin under some modification, but additional device support will be coming soon.

1 Like

Thanks Josh, that made the trick!

1 Like

I am running prob() in a known algorithm, and the results I get are consistent with basis vectors ordering {00,10,01,11}, while I am used to {00,01,10,11}. Is this a desired feature, a bug, or its just by happenstance that I’ve seen this second ordering?

Thanks for the update @Miguel_Fernandez — let us look into this and double check the ordering!

Hi @Miguel_Fernandez, I’ve tried the following minimal example,

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)
def circuit():
    qml.Hadamard(wires=1)
    qml.CNOT(wires=[0, 1])
    return prob(wires=[0, 1])

# expected probability, using [00, 01, 10, 11]
# ordering, is [0.5, 0.5, 0, 0]

res = circuit()
expected = np.array([0.5, 0.5, 0, 0])
assert np.allclose(res, expected, atol=tol, rtol=0)

and it seems to agree with [00, 01, 10, 11] ordering:

>>> import numpy as np
>>> H = np.array([[1, 1], [1, -1]])/np.sqrt(2)
>>> CNOT = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]])
>>> state = CNOT @ np.kron(np.eye(2), H) @ np.array([1, 0, 0, 0])
>>> expected = np.abs(state)**2
>>> expected
array([0.5, 0.5, 0. , 0. ])

Could you share a small example that shows {00,10,01,11}? It might be a edge-case related bug in the code that we are not taking into account.

Thanks for looking into this. When these discrepancies arise, its normally my fault. I am double-debugging my code, but I cant catch it yet. Will let you know in any sense

The first screenshot is a toy Quantum Phase Estimation in Qiskit. The second the same in PennyLane. The only difference being my implementation of the cu1 gate, its matrix definition also included


Hi @Miguel_Fernandez, as odd as it looks, I believe PennyLane and Qiskit are returning the exact same result.

The disagreement results from Qiskit not implementing the same convention as commonly seen in quantum information papers and textbook; typically, the top qubit (labelled 0) in a circuit is the leftmost integer within the ket; |q_0 q_1 \cdots q_{n-1} q_n\rangle.

For example, for a 2-qubit system originally in the ground state |00\rangle, applying an X gate to qubit 0 in this convention gives |10\rangle.

This can be observed in PennyLane:

@qml.qnode(dev)
def func():
     qml.PauliX(wires=0)
     return qml.probs(wires=0)

>>> func()
array([0., 0., 1., 0.])

where we are using the ordering (|00\rangle, |01\rangle,|10\rangle,|11\rangle).

Qiskit instead uses the convention such that the top qubit (qubit 0) is now the rightmost integer within the ket: |q_{n-1}q_{n}\cdots q_1q_0\rangle. In this convention, applying an X gate to qubit 0 gives |01\rangle.

Running the exact same program in Qiskit, we can see this reversal:

>>> q = qiskit.QuantumRegister(2, 'q')
>>> c = qiskit.ClassicalRegister(2, 'c')
>>> qpe = qiskit.QuantumCircuit(q, c)
>>> qpe.x(q[0])
>>> backend = qiskit.BasicAer.get_backend('statevector_simulator')
>>> job = qiskit.execute(qpe, backend)
>>> result = job.result()
>>> result.get_statevector().real
array([0., 1., 0., 0.])

where we are again using the ordering (|00\rangle, |01\rangle,|10\rangle,|11\rangle).

To convert from the Qiskit convention to the more standard/textbook convention (as used by PennyLane), all that needs to be done is reverse the basis state or permute the statevector/probabilities :slightly_smiling_face:

Hi Josh, many thanks!
Quite disturbing, I need to revise all my qiskit work until now

No worries Miguel! Note that I noticed a couple of typos in my comment, and I’ve just updated them to be correct.

Note also that this is why the matrix representation of the CNOT gate in Qiskit is non-standard:

CNOT=\begin{bmatrix}1& 0 & 0& 0\\ 0 & 0& 0& 1\\0& 0 & 1& 0 \\ 0 & 1& 0 & 0\end{bmatrix}

Compare this to the standard CNOT representation using the convention used in PennyLane/textbooks:

CNOT=\begin{bmatrix}1& 0 & 0& 0\\ 0 & 1& 0& 0\\0& 0 & 0& 1\\ 0 & 0& 1 & 0\end{bmatrix}

1 Like