Take a look at deep quantum circuits
The deeper the quantum circuit, the more expressive and complex functions can be represented. Let's do a quick calculation.
Reference
The effect of data encoding on the expressive power of variational quantum machine learning models
Maria Schuld, Ryan Sweke, Johannes Jakob Meyer
Parametrized Quantum Circuits for Reinforcement Learning
Let's get started!
The quantum NN circuit uses a 1-qubit arbitrary rotation and a 2-qubit gate. Data input is done through the RX gate after the NN circuit.
NN Circuit
The NN circuit is made by RX/RY/RZ circuits and CZ, so we will do it that way. First, prepare the parameters at random.
from blueqat import Circuit
import numpy as np
#The number of qubits corresponds to the number of data
data = np.random.rand(3)
n_qubits = len(data)
print("number of qubits", n_qubits)
#Number of times repeated
repeat = 3
#Number of parameters is the number of qubits*6*number of iterations
param = np.random.rand(n_qubits,6,repeat)
print(param)
#qubit number, from 0 to 5 in order from the front, number of iterations
param[1][2][0]
number of qubits 3
[[[0.86747532 0.87337393 0.78706454]
[0.50207327 0.95860909 0.68461434]
[0.6234547 0.36188902 0.4413571 ]
[0.45746388 0.4048643 0.99864912]
[0.03207569 0.4777751 0.71978454]
[0.42979957 0.20525921 0.91062522]]
[[0.33192226 0.7850338 0.47736587]
[0.91545993 0.81443555 0.91230105]
[0.17080158 0.69297854 0.38100002]
[0.09025144 0.88569055 0.14387673]
[0.63281154 0.17495308 0.56863578]
[0.45611514 0.0057784 0.80760631]]
[[0.92011796 0.06499331 0.26326902]
[0.63803015 0.53237185 0.75699485]
[0.50721385 0.16102745 0.42636818]
[0.43183127 0.25507491 0.42088226]
[0.70678276 0.3811046 0.26201077]
[0.44581629 0.71927592 0.55012781]]]
0.1708015764701739
Next we'll build the circuit.
The circuit is implemented as a function, allowing for iterations, and simplified by employing a CZ with no parameters for the two qubits.
#Initialize the quantum circuit
a = Circuit()
for j in range(repeat):
#1qubit arbitrary rotation
for i in range(n_qubits):
a.rx(param[i][0][j])[i].ry(param[i][1][j])[i].rz(param[i][2][j])[i]
#2qubits cluster state
for i in range(n_qubits):
a.cz[i, (i+1)%n_qubits]
#data input and adjustment
for i in range(n_qubits):
a.rx(data[i])[i]
a.rx(param[i][3][j])[i].ry(param[i][4][j])[i].rz(param[i][5][j])[i]
a.run_with_ibmq(returns='draw', output='mpl')
<Figure size 1591.6x565.88 with 1 Axes>
The single layer is
c = Circuit()
for j in range(1):
for i in range(n_qubits):
c.rx(param[i][0][j])[i].ry(param[i][1][j])[i].rz(param[i][2][j])[i]
for i in range(n_qubits):
c.cz[i, (i+1)%n_qubits]
for i in range(n_qubits):
c.rx(data[i])[i]
c.rx(param[i][3][j])[i].ry(param[i][4][j])[i].rz(param[i][5][j])[i]
c.run_with_ibmq(returns='draw', output='mpl')
<Figure size 748.797x264.88 with 1 Axes>
Measurement
Let's take out the results of the calculations. The expectation value calculation. The Hamiltonian takes a tensor product. This time we will take a Z-measure of the value of the zeroth qubit.
#Identity Matrix
I = np.eye(2)
#PauliZ Matrix
Z = np.array([[1,0],[0,-1]])
#Hamiltonian we use
H = np.kron(np.kron(Z,I),I)
print(H)
[[ 1. 0. 0. 0. 0. 0. 0. 0.]
[ 0. 1. 0. 0. 0. 0. 0. 0.]
[ 0. 0. 1. 0. 0. 0. 0. 0.]
[ 0. 0. 0. 1. 0. 0. 0. 0.]
[ 0. 0. 0. 0. -1. -0. -0. -0.]
[ 0. 0. 0. 0. -0. -1. -0. -0.]
[ 0. 0. 0. 0. -0. -0. -1. -0.]
[ 0. 0. 0. 0. -0. -0. -0. -1.]]
The Hamiltonian matrix has been obtained. Let's run the circuit and check the state vector.
result = a.run()
print(result)
[-0.24300611+0.08873021j 0.09195248+0.21631047j 0.19931431+0.04641616j
-0.08824146+0.37091261j 0.202104 -0.13198109j -0.45895405+0.48350374j
0.08714558+0.41709523j 0.07940506-0.00620103j]
Then, the expected value calculation is performed. The state vector and Hamiltonian gave us the expected value.
exptZ0 = result.conj()@H@result
print(exptZ0.real)
-0.38117225108694375
Get the ZZZ expectation value with all qubits measured.
H2 = np.kron(np.kron(Z,Z),Z)
print(H2)
[[ 1 0 0 0 0 0 0 0]
[ 0 -1 0 0 0 0 0 0]
[ 0 0 -1 0 0 0 0 0]
[ 0 0 0 1 0 0 0 0]
[ 0 0 0 0 -1 0 0 0]
[ 0 0 0 0 0 1 0 0]
[ 0 0 0 0 0 0 1 0]
[ 0 0 0 0 0 0 0 -1]]
exptZZZ = result.conj()@H2@result
print(exptZZZ.real)
0.6765304334296488
In this case, I used all three qubits to generate the expected value. We can train a quantum deep circuit by matching this value with a label and optimizing it using a loss function. That's all.