diff --git a/docs/programming_guide/source_en/parameterized _quantum_circuit.md b/docs/programming_guide/source_en/parameterized _quantum_circuit.md new file mode 100644 index 0000000000000000000000000000000000000000..9e25656de5d23da6dd8cf4b510ecc466b635c20c --- /dev/null +++ b/docs/programming_guide/source_en/parameterized _quantum_circuit.md @@ -0,0 +1,253 @@ +###**Parametric quantum circuit** + +#### **Overview** + +​ Parameterized quantum circuit (PQC) are a way to perform quantum machine learning. The quantum-classical hybrid machine learning architecture, MindQuantum, can process quantum circuits with parameters, and use the reversibility of quantum neural networks to automatically differentiate the circuits, and obtain observations for each The derivative of the parameter. + +​ The general process of constructing a parameterized quantum circuit and using the parameterized simulator operator for circuit evolution is as follows: + +1. Initialize the quantum circuit. +2. According to requirements, add parameterized quantum gates or non-parametric quantum gates to the quantum circuit. +3. Use PQC simulator operator to perform state evolution or gradient solution. + +#### **Environmental preparation** + +Import the modules that this tutorial depends on. + +```python +import numpy as np +import mindquantum as mq +from mindquantum.gate import H, X, Y, RY, RX +``` + +#### **Quantum gate** + +​ Quantum gates are the basic logical units for operating qubits. For classical circuits, any logic circuit can be composed of some basic logic gates. Similarly, any quantum circuit can be composed of some basic quantum gates, such as gates and controlled NOT gates acting on a single bit. Commonly used quantum gates include X gates, Y gates, Z gates, Hadamard gates, CNOT gates and some revolving gates. For example, the form of Y gate is as follows: + +```python +print('Gate name: ', Y) +print('Gate matrix: \n', Y.matrix()) +``` + +``` +Gate name: Y +Gate matrix: + [[ 0.+0.j -0.-1.j] + [ 0.+1.j 0.+0.j]] +``` + +​ The above Z gate is a non-parametric gate, while some revolving gates (such as RY gates) are parametric gates. By giving different rotation angles θ, the revolving gate will have different effects on the qubit, such as the expression of the RY gate matrix, for: + + +$$ +RY(θ)=e^{−iθY/2}= +\left\{ +\begin{matrix} +cos(θ/2) & −sin(θ/2) \\ +sin(θ/2) & cos(θ/2) +\end{matrix} +\right\} +$$ +​ Among them, "i" is the basic unit of imaginary number. This kind of parameter-containing quantum gate is an important component of the subsequent construction of a quantum neural network. Below, we print the matrix form of the RY gate when the rotation angle is 0.5. + +```python +ry = RY('a') +ry.matrix({'a': 0.5}) +``` + +``` +array([[ 0.96891242, -0.24740396], + [ 0.24740396, 0.96891242]]) +``` + +#### **Quantum circuit** + +​ Quantum circuit is a structure used to effectively organize various quantum logic gates. We can initialize quantum circuits through the list of quantum gates, or expand quantum circuits by adding a quantum gate or circuit through addition(`+`), and multiplying(`*`) by an integer. Here we will construct the following quantum circuit and print the relevant information of the quantum circuit. In the figure below, q0, q1, and q2 represent three qubits respectively. The quantum circuit is composed of three quantum gates. They are Hadamard gates acting on q0 bits, CNOT gates acting on q1 bits and controlled by q0 bits and acting on RY revolving door on the q2 bit. + +![图片](https://gitee.com/mindspore/docs/raw/master/tutorials/training/source_zh_cn/advanced_use/images/quantum_circuit.png) + +##### **HiQsimulator compatible quantum circuit construction format** + +1. Use `CircuitEngine` circuit engine to build quantum circuits. + + We use the operator "|" to act the quantum gate on the corresponding qubit. + +```python +eng = mq.engine.CircuitEngine() +qubits = eng.allocate_qureg(3) +H | qubits[0] +X | (qubits[0], qubits[1]) +RY('p1') | qubits[2] +encoder = eng.circuit +print(encoder) +encoder.summary() +``` + +``` +H(0) +X(1 <-: 0) +RY(p1|2) +========Circuit Summary======== +|Total number of gates : 3. | +|Parameter gates : 1. | +|with 1 parameters are : p1. | +|Number qubit of circuit: 3 | +=============================== +``` + + + +​ Here `X(1 <-: 0)` represents the `X` gate controlled by 0 bit and acting on 1 bit, that is, the CNOT gate. `RY(p1|2)` represents the revolving door around the Y axis acting on 2 bits, and `p1` is the rotation angle. From the summary information printed out, we can find that the quantum circuit is composed of three quantum gates, one of which is a parametric quantum gate, and the entire quantum circuit uses three qubits. + +2. Use decorators to build quantum circuits + + Using decorators to build quantum circuits can save some repeated engine declaration steps. + +```python +from mindquantum.engine import circuit_generator + +@circuit_generator(3) +def encoder(qubits): + H | qubits[0] + X | (qubits[0], qubits[1]) + RY('p1') | qubits[2] + +print(encoder) +encoder.summary() +``` + +``` +H(0) +X(1 <-: 0) +RY(p1|2) +========Circuit Summary======== +|Total number of gates : 3. | +|Parameter gates : 1. | +|with 1 parameters are : p1. | +|Number qubit of circuit: 3 | +=============================== +``` + +​ We can also pass in more parameters to the decorator for use in line generation. For example, you can pass in a character string, and when building a quantum circuit, you can use this character string to add a prefix to each parameter, which is helpful for generating quantum circuits with the same structure but different parameter names. + +```python +@circuit_generator(3, prefix='encoder') +def encoder(qubits, prefix): + H | qubits[0] + X | (qubits[0], qubits[1]) + RY(prefix + '_1') | qubits[2] + +print(encoder) +encoder.summary() +``` + +``` +H(0) +X(1 <-: 0) +RY(encoder_1|2) +===========Circuit Summary=========== +|Total number of gates : 3. | +|Parameter gates : 1. | +|with 1 parameters are : encoder_1.| +|Number qubit of circuit: 3 | +===================================== +``` + +#### **More convenient route generation method** + +​ By continuously adding quantum gates acting on different bits to the quantum circuit, the construction of the quantum circuit can be completed quickly. + +```python +from mindquantum import Circuit + +encoder = Circuit() +encoder += H.on(0) +encoder += X.on(1,0) +encoder += RY('p1').on(2) +print(encoder) +encoder.summary() +``` + +``` +H(0) +X(1 <-: 0) +RY(p1|2) +========Circuit Summary======== +|Total number of gates : 3. | +|Parameter gates : 1. | +|with 1 parameters are : p1. | +|Number qubit of circuit: 3 | +=============================== +``` + +#### **Using MindSpore operators to simulate quantum circuits** + +A common quantum neural network usually consists of the following three parts: + +* One (or more) encoding lines for encoding classical data into quantum data +* One (or more) lines to be trained (usually called Ansatz) +* One (or more) physical quantities to be measured + +​ Now we build the following quantum neural network. The encoding part of the quantum neural network is composed of two RY gates, and the Ansatz circuit is composed of a CNOT gate and two RX gates. The physical quantity to be measured is the Z calculation acting on the 1st bit. symbol. + +```python +from projectq.ops import QubitOperator + +@circuit_generator(2) +def encoder(qubits): + RY('a') | qubits[0] + RY('b') | qubits[1] + +@circuit_generator(2) +def ansatz(qubits): + X | (qubits[0],qubits[1]) + RX('p1') | qubits[0] + RX('p2') | qubits[1] + +ham = mq.Hamiltonian(QubitOperator('Z1')) +encoder_names = ['a', 'b'] +ansatz_names = ['p1', 'p2'] +``` + +​ Here we have generated Encoder circuit and Ansatz circuit by means of decorator. And use the `generate_pqc_operator` method to generate a circuit simulation operator, perform simulation calculation on the quantum circuit, and obtain the gradient value of the output of the quantum neural network to each parameter. In the `generate_pqc_operator` method, we need to provide the parameter name of the Encoder circuit, the parameter name of the Ansatz circuit, the entire quantum circuit and the physical quantity to be measured. + +```python +from mindquantum.nn import generate_pqc_operator +from mindspore import Tensor +from mindspore import context +context.set_context(mode=context.GRAPH_MODE, device_target="CPU") + +pqc = generate_pqc_operator(encoder_names, ansatz_names, encoder+ansatz, ham) +encoder_data = Tensor(np.array([[0.1,0.2]]).astype(np.float32)) +ansatz_data = Tensor(np.array([0.3,0.4]).astype(np.float32)) +measure_result, encoder_grad, ansatz_grad = pqc(encoder_data, ansatz_data) +print('Measurement result: ', measure_result.asnumpy()) +print('Gradient of encoder parameters: ', encoder_grad.asnumpy()) +print('Gradient of ansatz parameters: ', ansatz_grad.asnumpy()) +``` + +``` +Measurement result: [[0.89819133]] +Gradient of encoder parameters: [[[-0.09011973 -0.1820724 ]]] +Gradient of ansatz parameters: [[[-2.7755576e-17 -3.7974921e-01]]] +``` + +​ The above three results respectively represent the output value of the quantum neural network, the gradient value of the parameter in the encoding circuit, and the gradient value of the parameter in the Ansatz circuit with training. Sometimes, the quantum neural network is the first layer of the entire quantum classical hybrid neural network, so we don’t need to take the derivative of the gradient in the coding circuit. For this kind of circuit that does not need to find the gradient, we can specify that no calculation is required through the `no_grad` method The gradient of the quantum circuit is not derivable. + +```python +encoder.no_grad() +pqc = generate_pqc_operator(encoder_names, ansatz_names, encoder+ansatz, ham) +measure_result, encoder_grad, ansatz_grad = pqc(encoder_data, ansatz_data) +print('Measurement result: ', measure_result.asnumpy()) +print('Gradient of encoder parameters: ', encoder_grad.asnumpy()) +print('Gradient of ansatz parameters: ', ansatz_grad.asnumpy()) +``` + +``` +Measurement result: [[0.89819133]] +Gradient of encoder parameters: [[[0. 0.]]] +Gradient of ansatz parameters: [[[-2.7755576e-17 -3.7974921e-01]]] +``` + +​ As can be seen from the above, the derivatives of the coding line parameters in the quantum neural network are all zero, and they are not derived in the actual simulation calculation process. +