Measurements and output state probabilities in a single circuit

Hello,

I need to know how can we measure and get the probabilities of qubits in the same circuit. For instance, I have 4 qubits, I want to measure q0 and q1 in X-basis and need to know the output state probabilities of all the qubits, if possible or else q0,q2 and q3.

Secondly, Is there any builtin function in pennylane for qubit measurement in X and Y basis or Am I right with the following?

qml.PauliZ(wirenumber) --> measurement in computational basis.
qml.PauliX(wirenumber) --> measurement in X basis.
qml.PauliY(wirenumber) --> measurement in Y basis.

Thanks for the help

Hi @Muhammad_Kashif!

Thank you for the questions :slight_smile:

When specifying measurements in a QNode, multiple types of measurements are possible. Sampling using qml.sample will provide outcomes of a specified observable after running a quantum circuit.

The succinct way of having multiple outputs to a QNode is to have combined measurements in the return statement:

import pennylane as qml

dev = qml.device('default.qubit', wires=4, shots=5)

@qml.qnode(dev)
def circuit():
    return qml.sample(qml.PauliX(0)), qml.sample(qml.PauliX(1)), qml.probs(wires=range(4))

circuit()

In this case, PennyLane will be generating samples once and providing the PauliX measurement outcomes as well as the joint probability distribution based on 5 samples (specified by shots=5). The wires for the probability distribution can be provided when specifying the wires argument for qml.probs.

Secondly, Is there any builtin function in pennylane for qubit measurement in X and Y basis or Am I right with the following?

Indeed, using qml.PauliX or qml.PauliY, the PauliX and PauliY observables are used when providing measurement statistics. That’s the same for qml.PauliZ, the PauliZ observable is used. The subtle difference between computational basis state measurements and using the PauliZ observable to obtain statistics is that in the latter case samples are the eigenvalues of the PauliZ operator. Therefore, 1 is the outcome for sampling the |0> basis state and 1is the outcome for sampling the|1>` state.

import pennylane as qml

dev = qml.device('default.qubit', wires=1, shots=5)

@qml.qnode(dev)
def circuit():
    return qml.sample(qml.PauliZ(0))

circuit()
array([1, 1, 1, 1, 1])

The |1> case can be checked by flipping the first qubit using qml.PauliX(0).

Hope this clears up things, let us know if you have further questions! :slightly_smiling_face:

Hi @antalszava,

Thanks for the answer, However I am still a little confused on how to interpret the output. For instance for the below circuit:

import pennylane as qml
dev1 = qml.device(“default.qubit”, wires=4, shots =10)
@qml.qnode(dev1)
def circuit():
qml.PauliX(wires=0)
qml.Hadamard(wires=1)
qml.Hadamard(wires=2)
qml.CZ(wires=[0,1])
qml.CZ(wires=[1, 2])
qml.CZ(wires=[1, 3])
return qml.sample(qml.PauliX(0)), qml.sample(qml.PauliX(1)), qml.probs(wires=range(4))

output:

(array([ 1, -1, 1, -1, -1, 1, 1, -1, -1, 1], dtype=int64),
array([ 1, 1, 1, 1, -1, -1, -1, -1, 1, 1], dtype=int64),
array([0. , 0. , 0.3, 0. , 0.2, 0. , 0. , 0. , 0. , 0. , 0.3, 0. , 0.2,
0. , 0. , 0. ]))

How does I read the output?
I have 4 qubit system (q0=1, q1=q2=superposition, q3=0).

It is a CNOT gate with q3 as control and q0 and q2 are target_in and target_out respectively? Since I have initialized q0 in state |1> and q3 in state |0>, the output should be q2=|1> and q3=|0> for the above case. Is the output mentioned above indicating the same thing? It is literally confusingto read the outputs even in simple circuits here.

q0 and q1 are measured in X-basis and q3 and q4 are not measured at all. The same circuit works fine in Qiskit. I am not sure about here or may be I am interpreting the output wrong?
Any help would be appreciated.

Thanks

Hey @Muhammad_Kashif!

(array([ 1, -1, 1, -1, -1, 1, 1, -1, -1, 1], dtype=int64),
array([ 1, 1, 1, 1, -1, -1, -1, -1, 1, 1], dtype=int64),
array([0. , 0. , 0.3, 0. , 0.2, 0. , 0. , 0. , 0. , 0. , 0.3, 0. , 0.2,
0. , 0. , 0. ]))

How does I read the output?

Let’s first look at the output corresponding to qml.probs(wires=range(4)), i.e., the last term in the tuple. This is a probability vector of dimension 2 ** 4. The first element corresponds to the probability of the |0000> state, the next to the |0001> state and so forth, with the last element giving the probability of |1111>.

Now let’s look at the output corresponding to qml.sample(qml.PauliX(0)), i.e., the first term in the tuple. We have array([ 1, -1, 1, -1, -1, 1, 1, -1, -1, 1], dtype=int64) which is an array of length specified by the number of shots (in this case 10). Each entry gives an output sample from the circuit.

When measuring an observable, we expect the results to be the eigenvalues of that observable. Hence, since PauliX has eigenvalues +1 and -1, we expect to sample these eigenvalues. The eigenvectors of PauliX are |+> = (|0> + |1>) / root(2) (corresponding to the +1 eigenvalue) and |-> = (|0> - |1>) / root(2) (corresponding to the -1 eigenvalue). Whenever you see +1 being sampled, we know that the system is then in the |+> state in the corresponding qubit.

It is a CNOT gate with q3 as control and q0 and q2 are target_in and target_out respectively? Since I have initialized q0 in state |1> and q3 in state |0>, the output should be q2=|1> and q3=|0> for the above case. Is the output mentioned above indicating the same thing? It is literally confusingto read the outputs even in simple circuits here.

It looks like q3 is initialized in state |+> due to the Hadamard gate, which is likely why you are getting the the random samples when measuring q1 and q2. You could try skipping the Hadamard gates to get a deterministic output.

Hope this helps, and let us know if you still need a hand with interpreting the output!

Hi @Tom_Bromley

Thanks for the help, I now have a good idea of output interpretation. Just a simple follow-up question, qml.sample and qml.expval are used when we need to measure certain qubit in eigenbasis of sigma X, Y and Z(computational), right?

In the code above, I have not applied Hadmard gate on q3. What I am actually trying to do is to implement the CNOT gate using Measurement-based quantum computation approach. For that I am creating a cluster state of 4 qubits by applying Hadamard gates on qubits (other than the ones acting as inputs) and then apply the entangling CZ gate. This is explained in here - page 14 (Figure 4a)

Afterwards, measuring q0 and q1 in X-basis applies the CNOT gate between q3 (control) and q0(target) and the output can be read from q2 (flipped version of q0’s initial state). The final states of q0 and q1 are not relevant in this regard.
I have tried the same circuit IBM quantum composer online and it works fine. The same circuit should have the same output here as well but its not, can you please help with that?

Hey @Muhammad_Kashif!

Just a simple follow-up question, qml.sample and qml.expval are used when we need to measure certain qubit in eigenbasis of sigma X, Y and Z(computational), right?

Right! qml.sample returns actual samples (i.e., a list of the sampled eigenvalues of our observable) and qml.expval gives the expectation value, which is just the average over those samples (when shots=None, the expectation value is exact). Note that both return types can accept any PennyLane Observable, including the Pauli operators.

The same circuit should have the same output here as well but its not, can you please help with that?

Would you be able to share the Qiskit code you are using and your expected output? This will help us debug and spot where the difference may be arising.

Hi @Tom_Bromley

Thanks…

Yes sure I can share the Qiskit code, I am using IBM Quantum Composer, below is the translated Qiskit code:

from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
from numpy import pi

qreg_q = QuantumRegister(4, 'q')
creg_c = ClassicalRegister(4, 'c')
circuit = QuantumCircuit(qreg_q, creg_c)

circuit.h(qreg_q[1])
circuit.h(qreg_q[2])
circuit.x(qreg_q[3])
circuit.cz(qreg_q[0], qreg_q[1])
circuit.h(qreg_q[0])
circuit.cz(qreg_q[1], qreg_q[2])
circuit.cz(qreg_q[1], qreg_q[3])
circuit.measure(qreg_q[0], creg_c[0])
circuit.h(qreg_q[1])
circuit.measure(qreg_q[1], creg_c[1])

Output:
583e9bc84afe9bc4dbc6e9bb4353248c_histogram

just to elaborate a little following my previous message in this thread, q0 = 0 (target_in), q3 = 1 (control), the target_out(q2) is in |1> state (flipped version of q0 since the control is |1>). Hope it will help you better understand my query.

Thanks for the help.

Hey @Muhammad_Kashif!

The following PennyLane circuit should give you similar results to Qiskit:

import pennylane as qml

dev = qml.device("default.qubit", wires=4, shots=10)

@qml.qnode(dev)
def circuit():
    qml.Hadamard(1)
    qml.Hadamard(2)
    qml.PauliX(3)
    qml.CZ(wires=[0, 1])
    qml.Hadamard(0)
    qml.CZ(wires=[1, 2])
    qml.CZ(wires=[1, 3])
    qml.Hadamard(1)
    return [qml.sample(qml.PauliZ(i)) for i in range(4)]

samples = circuit().T
samples = (samples + 1) / 2
samples

This circuit is sampling in the standard basis and follows the same set of gates as in Qiskit. Note that Qiskit uses a reversed convention for ordering qubits.