Estimating QBER

In this example the two nodes Alice and Bob will estimate the QBER (qubit error rate) of their produced entangled pairs. To make the below example more interesting you should try to turn on the probabilistic noise option in SimulaQron. You can do this be setting the entry noisy-qubits to True by:

./cli/SimulaQron set noisy-qubits on

You can also tune the coherence time t1 of the qubits (lower means more noisy).

Note

This probabilistic noise in SimulaQron is not intended and should not be used to benchmark the performence of protocols in noisy settings, since noise is applied in a rate related to the wall clock time of your computer. Thus, if your computer or network is slower, more noise will be applied to the qubits! However you can use this example to tune the t1-parameter to a realistic value for your setup. A realistic QBER is around 5 -10 %.

The protocol

Alice and Bob will produce EPR pairs between them and measure their qubits in either the \(X\)-, \(Y\)- or \(Z\)-basis, where \(X=\begin{pmatrix}0 & 1 \\ 1 & 0\end{pmatrix}\), \(Y=\begin{pmatrix}0 & -i \\ i & 0\end{pmatrix}\) or \(Z=\begin{pmatrix}1 & 0 \\ 0 & -1\end{pmatrix}\). If there is no noise Alice’s and Bob’s measurement will be perfectly correlated if they both measure in the \(Z\)-basis and the same for the \(X\)-basis but perfectly anti-correlated for the \(Y\)-basis. The QBER (qubit error rate) is then the number of rounds where this is not the case, i.e. when the nodes measurement outcomes are anti-correlated for the \(Z\) and \(X\) bases and correlated for the \(Y\)-basis.

Alice and Bob have beforehand agreed that they will measure the the first EPR pair in the \(Z\)-basis, the second in the \(X\)-basis, the third in the \(Y\)-basis and then back to \(Z\)-basis and so on. However, the qubits received from the entanglement generation process are not necessarily ordered. They therefore need to use the entanglement identifier that is attached to any entangled qubit. In particular the entanglement identifier contains a sequence number which is guaranteed to be consistent between the two nodes. This sequence number can be accessed from an entangled qubit as:

q.get_entInfo().id_AB

Alice and Bob will therefore make use of the following decision rules for the measurement basis:

  • Measure in the \(Z\)-basis if the sequence number modulus 3 is 0.

  • Measure in the \(X\)-basis if the sequence number modulus 3 is 1.

  • Measure in the \(Y\)-basis if the sequence number modulus 3 is 2.

Note

More details on the explicit entanglement generation protocol and the generation of the entanglement identifiers will soon be available in a paper which is under construction.

Setting up

We will run everything locally (localhost) using two nodes, Alice and Bob. Start up the backend of the simulation by running (to make this example more interesting you should before turn on the noise on the qubits as described above):

./cli/SimulaQron start --nodes Alice,Bob

The below example can then be executed when in the folder examples/pythonLib/QBER in the repo pythonLib by typing:

sh run.sh

which will execute the Python scripts aliceTest.py and bobTest.py containing the code below. By default 500 EPR pairs are produced to estimate the QBER, see above. You can choose to produce a different number of pairs by passing this as an argument. For example:

sh run.sh 300

When running this example the estimated QBER will be printed. If the noise in SimulaQron is off the QBER should be 0.

Programming Alice

Here we program what Alice should do using the python library:

meas_outcomes = {}

print("Estimating QBER by measuring {} produced EPR pairs.".format(nr_runs))

# Initialize the connection
with CQCConnection("Alice") as Alice:

        for _ in range(nr_runs):

                # Create an EPR pair
                q = Alice.createEPR("Bob")

                # Get the identifier of this EPR pair such that we can relate our measurement outcomes to Bobs
                sequence_nr = q.get_entInfo().id_AB

                print("Generated EPR pair number {}.".format(sequence_nr))

                if (sequence_nr % 3) == 0:
                        # Measure in Z
                        basis = 'Z'
                elif (sequence_nr % 3) == 1:
                        # Measure in X
                        q.H()
                        basis = 'X'
                else:
                        # Measure in Y
                        q.K()
                        basis = 'Y'

                m = q.measure()
                # We save both the measurement outcome and the measurement basis
                meas_outcomes[sequence_nr] = (m, basis)

# Get the measurement outcomes from Bob
msg = Alice.recvClassical(msg_size=10000)

# Decode the message
bob_meas_outcomes = json.loads(msg.decode('utf-8'))

# Check the measurement outcomes
errors = []
for (sequence_nr, mB) in bob_meas_outcomes.items():
        mA, basis = meas_outcomes[int(sequence_nr)]
        if basis == 'Y':
                if mA == mB:
                        errors.append(True)
                else:
                        errors.append(False)
        else:
                if mA != mB:
                        errors.append(True)
                else:
                        errors.append(False)

nr_data_points = len(errors)
avg_QBER = errors.count(True) / nr_data_points
to_print="Estimated QBER is {} (from {} data-points.".format(avg_QBER, nr_data_points)
print("|"+"-"*(len(to_print)+2)+"|")
print("| "+to_print+" |")
print("|"+"-"*(len(to_print)+2)+"|")

Programming Bob

Here we program what Bob should do using the python library:

meas_outcomes = {}

# Initialize the connection
with CQCConnection("Bob") as Bob:

        for _ in range(nr_runs):

                # Create an EPR pair
                q = Bob.recvEPR()

                # Get the identifier of this EPR pair such that Alice can relate the measuement outcomes to hers
                sequence_nr = q.get_entInfo().id_AB

                if (sequence_nr % 3) == 0:
                        # Measure in Z
                        pass
                elif (sequence_nr % 3) == 1:
                        # Measure in X
                        q.H()
                else:
                        # Measure in Y
                        q.K()

                m = q.measure()
                meas_outcomes[sequence_nr] = m

# Encode the measurement outcomes to bytes, such that we can send them
msg = json.dumps(meas_outcomes).encode('utf-8')

# Send the measurement outcomes to Alice
Bob.sendClassical(name="Alice", msg=msg)