The Bloch sphere¶
Visualization tools are important for understanding what is happening in a quantum circuit. A standard one is the Bloch sphere, as it represents a qubit as a three-dimensional object. We caution the reader that this tool will not help you think about multiple qubits, as it fails to demonstrate entanglement. This being said, it is very useful for understanding single qubits.
As mentioned in the last section, a single-qubit state can be written as , where and are defined in the picture. We see that there is a one-to-one correspondence between pure qubit states () and the points on the surface of a unit sphere (). We can reconstruct an arbitrary unknown qubit state by measuring the Bloch vector, whose vector components are the expectation values of the three Pauli operators, given by , , and . The state is given by .
Each expectation value can be obtained experimentally by first preparing the state, rotating the standard basis frame to lie along the corresponding axis , and making a measurement in the standard basis. The probabilities of obtaining the two possible outcomes 0 and 1 are used to evaluate the desired expectation value via . As an example, let’s look at measuring the expectation value of , , depicted in the circuit below. Once is prepared, we implement the gate that exchanges to , then we make a measurement in the standard basis. The desired expectation value is given by . Similarly, we can use the gate to measure .
As you can see, a series of measurements is required to reconstruct the full Bloch vector, which then can be combined. This type of reconstruction is often referred to as state tomography. Efficiently running routines for tomography requires running batches of quantum scores at a time, and can be set up by more advanced users through Qiskit.
# quantum_phase_bloch.py import numpy as np from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, execute, Aer from qiskit.tools.visualization import plot_bloch_vector # Define the Quantum and Classical Registers q = QuantumRegister(1) c = ClassicalRegister(1) # Build the circuits pre = QuantumCircuit(q, c) pre.h(q) pre.barrier() meas_x = QuantumCircuit(q, c) meas_x.barrier() meas_x.h(q) meas_x.measure(q, c) meas_y = QuantumCircuit(q, c) meas_y.barrier() meas_y.s(q).inverse() meas_y.h(q) meas_y.measure(q, c) meas_z = QuantumCircuit(q, c) meas_z.barrier() meas_z.measure(q, c) bloch_vector = ['x', 'y', 'z'] exp_vector = range(0, 21) circuits =  for exp_index in exp_vector: middle = QuantumCircuit(q, c) phase = 2*np.pi*exp_index/(len(exp_vector)-1) middle.u1(phase, q) circuits.append(pre + middle + meas_x) circuits.append(pre + middle + meas_y) circuits.append(pre + middle + meas_z) # Execute the circuit job = execute(circuits, backend = Aer.get_backend('qasm_simulator'), shots=1024) result = job.result() # Plot the result for exp_index in exp_vector: bloch = [0, 0, 0] for bloch_index in range(len(bloch_vector)): data = result.get_counts(circuits[3*exp_index+bloch_index]) try: p0 = data['0']/1024.0 except KeyError: p0 = 0 try: p1 = data['1']/1024.0 except KeyError: p1 = 0 bloch[bloch_index] = p0-p1 plot_bloch_vector(bloch)