In our previous article Java quantum program to entanglement, we used the java Strange API to bring a pair of qubits to entanglement. By running our program on a quantum simulator over 1000 runs, we also confirmed the expected measurement outputs: every time the first qubit was measured in the |0> state then the second bit was measured in the state |1> and vice-versa. Never did we see appearing in the output the states |00> or |11>.

In this article, we would like to do exactly the same by using Cirq, the Google python software library for writing, manipulating, and optimizing quantum circuits and then running them against quantum computers and simulators.

Quick start

You can first have a quick overview of our program by going to our github code repository here

1) If you have no Python environment installed, simply click here. You will be able to open a jupyter python notebook in an online executable environment, making the code immediately reproducible.

Once the environment is built, navigate to teleportation/cirq_teleportation.ipynb, click on Cell -> Run All.

It will first install the Cirq API (first cell), then build the quantum entanglement circuit (second cell) and finally print the results (third cell).

To replay the program, you don't need to re-install the Cirq API. Just place yourself into the second cell and then click on Cell -> Run All Below.

2) If you have Python installed locally, you can directly clone our project and run either the Jupyter Notebook cirq_teleportation.ipynb or the Python program cirq_entanglement.py.

 

 Our Cirq program to entanglement

Once the installation done and checked, it's time to write our small program.

Just as a quick reminder, our aim here is to bring our two qubits to the following entangled state:

 

Remark : what this entanglement means: the qubit held by Alice (left-side qubit) can be 0 as well as 1. If Alice measured her qubit in the standard basis, the outcome would be perfectly random, either possibility 0 or 1 having probability 1/2. But if Bob (right-side qubit) then measured his qubit, the outcome would be the opposite as the one Alice got. Equivalently, if Bob measured, he would also get a random outcome on first sight, but if Alice and Bob communicated, they would find out that, although their outcomes seemed random, they are perfectly anti-correlated.

We remember that to bring our two qubits to the |β11> Bell state, we have to go through the following steps, assuming we are starting from the the two-qubit state |00>:

- apply the X-Pauli gate to both qubits hence we get |11>

- apply the Hadamard gate to the first qubit  H|11>

- apply the CNOT gate with our two qubits as input.

 

With Cirq, everything starts with the Circuit object, which is used to create our two qubits q0 and q1

    # Create a circuit
    circuit = cirq.Circuit()
    (q0, q1) = cirq.LineQubit.range(2)

 

 Then we apply the X-Pauli gate to both qubits, via the cirq.X object. You can have an overview of an impressive list of available gates via the Cirq API here: https://cirq.readthedocs.io/en/stable/api.html

    # Apply the X-Pauli gate to each qubit
    circuit.append([cirq.X(q0), cirq.X(q1)])

 At this step we need to apply the Hadamard gate to the first qubit, and the CNOT gate to both via respectively the cirq.H and cirq.CNOT instances

        # Apply the Hadamard gate to first qubit and CNOT gate to both qubits
     circuit.append([cirq.H(q0), cirq.CNOT(q0, q1)])

And that's all! We are done with building our quantum circuit!

It could be nice to be able to visualise this circuit, as we did with the Strange FX API of our previous article.

Luckily, this is possible via the Cirq API as well, just by calling the print method on our cirq.Circuit instance

         print("Circuit:")
     print(circuit)

 Once we run this program, tha's what we get;

 How cool is that!

 That's looking good but we still want have our measurements, don't we?

Nothing is easier. We append the measure operation on both qubit to the circuit and via the simulator object obtained via cirq.Simulator(), we call the method run(circuit, number_of_occurences) and that's it!

           circuit.append([cirq.measure(q0), cirq.measure(q1)])

     # Simulate the circuit several times.
     simulator = cirq.Simulator()
     result = simulator.run(circuit, repetitions=20)
     print("Results:")
     print(result)

 Running again our program, we can see as output:

   

Two remarks here

Remark 1: we can see at the end of each qubit line the apparition of the M (measurement) operation.

Remark 2: as expected we only see the states |01> and |01> (each of the twenty vertical pairs displayed as a result in the console). Even more, we are very close to the 50% probability for each state as we measure nine times the state |01> and eleven times the state|10>. On a twenty run iteration, that's remarkable!