Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quantum-kittens
GitHub Repository: quantum-kittens/platypus
Path: blob/main/translations/ja/ch-ex/Solutions/Exercise for 2.4.ipynb
3855 views
Kernel: Python 3
from qiskit import * from qiskit.tools.visualization import plot_histogram import numpy as np

Solution: Basic synthesis of single qubit gates

1

Show that the Hadamard gate can be written in the following two forms

H=X+Z2exp(iπ2X+Z2)H = \frac{X+Z}{\sqrt{2}} \equiv \exp\left(i \frac{\pi}{2} \, \frac{X+Z}{\sqrt{2}}\right)

Here \equiv is used to denote that the equality is valid up to a global phase, and hence that the resulting gates are physically equivalent.

Hint: it might even be easiest to prove that eiπ2MMe^{i\frac{\pi}{2} M} \equiv M for any matrix whose eigenvalues are all ±1\pm 1, and that such matrices uniquely satisfy M2=IM^2=I.

2

The Hadamard can be constructed from rx and rz operations as

Rx(θ)=eiθ2X,   Rz(θ)=eiθ2Z,Hlimn( Rx(θn)  Rz(θn) )nR_x(\theta) = e^{i\frac{\theta}{2} X}, ~~~ R_z(\theta) = e^{i\frac{\theta}{2} Z},\\ H \equiv \lim_{n\rightarrow\infty} \left( ~R_x\left(\frac{\theta}{n}\right) ~~R_z \left(\frac{\theta}{n}\right) ~\right)^n

For some suitably chosen θ\theta. When implemented for finite nn, the resulting gate will be an approximation to the Hadamard whose error decreases with nn.

The following shows an example of this implemented with Qiskit with an incorrectly chosen value of θ\theta (and with the global phase ignored).

  • Determine the correct value of θ\theta.

  • Show that the error (when using the correct value of θ\theta) decreases quadratically with nn.

qr = QuantumRegister(1) cr = ClassicalRegister(1) error = {} for n in range(1,11): # Create a blank circuit qc = QuantumCircuit(qr,cr) # Implement an approximate Hadamard theta = np.pi/np.sqrt(2) # here we correctly choose theta=pi/sqrt(2) for j in range(n): qc.rx(theta/n,qr[0]) qc.rz(theta/n,qr[0]) # We need to measure how good the above approximation is. Here's a simple way to do this. # Step 1: Use a real hadamard to cancel the above approximation. # For a good approximatuon, the qubit will return to state 0. For a bad one, it will end up as some superposition. qc.h(qr[0]) # Step 2: Run the circuit, and see how many times we get the outcome 1. # Since it should return 0 with certainty, the fraction of 1s is a measure of the error. qc.measure(qr,cr) shots = 20000 job = execute(qc, Aer.get_backend('qasm_simulator'),shots=shots) try: error[n] = (job.result().get_counts()['1']/shots) except: pass plot_histogram(error)
Image in a Jupyter notebook
# The linear nature of error^(-1/2) shows that the error has a quadratic decay. inverse_square_of_error = {} for n in error: inverse_square_of_error[n] = (error[n])**(-1/2) plot_histogram(inverse_square_of_error)
Image in a Jupyter notebook

3

An improved version of the approximation can be found from,

Hlimn( Rz(θ2n)  Rx(θn)  Rz(θ2n) )nH \equiv \lim_{n\rightarrow\infty} \left( ~ R_z \left(\frac{\theta}{2n}\right)~~ R_x\left(\frac{\theta}{n}\right) ~~ R_z \left(\frac{\theta}{2n}\right) ~\right)^n

Implement this, and investigate the scaling of the error.

qr = QuantumRegister(1) cr = ClassicalRegister(1) error = {} for n in range(1,11): # Create a blank circuit qc = QuantumCircuit(qr,cr) # Implement an approximate Hadamard theta = np.pi/np.sqrt(2) # here we correctly use theta=pi/sqrt(2) for j in range(n): qc.rz(theta/(2*n),qr[0]) qc.rx(theta/n,qr[0]) qc.rz(theta/(2*n),qr[0]) # We need to measure how good the above approximation is. Here's a simple way to do this. # Step 1: Use a real hadamard to cancel the above approximation. # For a good approximatuon, the qubit will return to state 0. For a bad one, it will end up as some superposition. qc.h(qr[0]) # Step 2: Run the circuit, and see how many times we get the outcome 1. # Since it should return 0 with certainty, the fraction of 1s is a measure of the error. qc.measure(qr,cr) shots = 100000 job = execute(qc, Aer.get_backend('qasm_simulator'),shots=shots) try: error[n] = (job.result().get_counts()['1']/shots) except: pass plot_histogram(error)
Image in a Jupyter notebook
# The linear nature of error^(-1/3) shows that the error has a cubic decay. # Note: this needs loads of shots to get a good result. inverse_cube_of_error = {} for n in error: error[n] inverse_cube_of_error[n] = (error[n])**(-1/3) plot_histogram(inverse_cube_of_error)
Image in a Jupyter notebook