Quantum Machine Learning API using QPanda2¶
警告
The quantum computing part of the following interface uses pyQPanda2 https://pyqpanda-toturial.readthedocs.io/zh/latest/.
Due to the compatibility issues between pyQPanda2 and pyqpanda3, you need to install pyqpnda2 yourself, pip install pyqpanda
Quantum Computing Layer¶
QuantumLayer¶
QuantumLayer is a package class of autograd module that supports ariational quantum circuits. You can define a function as an argument, such as qprog_with_measure, This function needs to contain the quantum circuit defined by pyQPanda: It generally contains coding-circuit, evolution-circuit and measurement-operation.
This QuantumLayer class can be embedded into the hybrid quantum classical machine learning model and minimize the objective function or loss function of the hybrid quantum classical model through the classical gradient descent method.
You can specify the gradient calculation method of quantum circuit parameters in QuantumLayer by change the parameter diff_method. QuantumLayer currently supports two methods, one is finite_diff and the other is parameter-shift methods.
The finite_diff method is one of the most traditional and common numerical methods for estimating function gradient.The main idea is to replace partial derivatives with differences:
For the parameter-shift method we use the objective function, such as:
It is theoretically possible to calculate the gradient of parameters about Hamiltonian in a quantum circuit by the more precise method: parameter-shift.
- class pyvqnet.qnn.quantumlayer.QuantumLayer(qprog_with_measure, para_num, machine_type_or_cloud_token, num_of_qubits: int, num_of_cbits: int = 1, diff_method: str = 'parameter_shift', delta: float = 0.01, dtype=None, name='')¶
Abstract calculation module for variational quantum circuits. It simulates a parameterized quantum circuit and gets the measurement result. QuantumLayer inherits from Module ,so that it can calculate gradients of circuits parameters,and train variational quantum circuits model or embed variational quantum circuits into hybird quantum and classic model.
This class dos not need you to initialize virtual machine in the
qprog_with_measurefunction.- 参数:
qprog_with_measure – callable quantum circuits functions ,cosntructed by pyQPanda2
para_num – int - Number of parameter
machine_type_or_cloud_token – qpanda machine type or pyQPanda2 QCLOUD token : https://pyqpanda-toturial.readthedocs.io/zh/latest/Realchip.html
num_of_qubits – num of qubits
num_of_cbits – num of classic bits
diff_method – ‘parameter_shift’ or ‘finite_diff’
delta – delta for diff
dtype – The data type of the parameter, defaults: None, use the default data type kfloat32, which represents a 32-bit floating point number.
name – name of the output layer
- 返回:
a module can calculate quantum circuits .
备注
qprog_with_measure is quantum circuits function defined in pyQPanda2 :https://pyqpanda-toturial.readthedocs.io/zh/latest/QCircuit.html.
This function should contain following parameters,otherwise it can not run properly in QuantumLayer.
qprog_with_measure (input,param,qubits,cbits,m_machine)
input: array_like input 1-dim classic data
param: array_like input 1-dim quantum circuit’s parameters
qubits: qubits allocated by QuantumLayer
cbits: cbits allocated by QuantumLayer.if your circuits does not use cbits,you should also reserve this parameter.
m_machine: simulator created by QuantumLayer
Use the
m_paraattribute of QuantumLayer to get the training parameters of the variable quantum circuit. The parameter is aQTensorclass, which can be converted into a numpy array using theto_numpy()interface.备注
The class have alias: QpandaQCircuitVQCLayer .
Example:
import pyqpanda as pq from pyvqnet.qnn.measure import ProbsMeasure from pyvqnet.qnn.quantumlayer import QuantumLayer import numpy as np from pyvqnet.tensor import QTensor def pqctest (input,param,qubits,cbits,m_machine): circuit = pq.QCircuit() circuit.insert(pq.H(qubits[0])) circuit.insert(pq.H(qubits[1])) circuit.insert(pq.H(qubits[2])) circuit.insert(pq.H(qubits[3])) circuit.insert(pq.RZ(qubits[0],input[0])) circuit.insert(pq.RZ(qubits[1],input[1])) circuit.insert(pq.RZ(qubits[2],input[2])) circuit.insert(pq.RZ(qubits[3],input[3])) circuit.insert(pq.CNOT(qubits[0],qubits[1])) circuit.insert(pq.RZ(qubits[1],param[0])) circuit.insert(pq.CNOT(qubits[0],qubits[1])) circuit.insert(pq.CNOT(qubits[1],qubits[2])) circuit.insert(pq.RZ(qubits[2],param[1])) circuit.insert(pq.CNOT(qubits[1],qubits[2])) circuit.insert(pq.CNOT(qubits[2],qubits[3])) circuit.insert(pq.RZ(qubits[3],param[2])) circuit.insert(pq.CNOT(qubits[2],qubits[3])) prog = pq.QProg() prog.insert(circuit) # pauli_dict = {'Z0 X1':10,'Y2':-0.543} rlt_prob = ProbsMeasure([0,2],prog,m_machine,qubits) return rlt_prob pqc = QuantumLayer(pqctest,3,"cpu",4,1) #classic data as input input = QTensor([[1,2,3,4],[40,22,2,3],[33,3,25,2.0]] ) #forward circuits rlt = pqc(input) grad = QTensor(np.ones(rlt.data.shape)*1000) #backward circuits rlt.backward(grad) print(rlt) # [ # [0.2500000, 0.2500000, 0.2500000, 0.2500000], # [0.2500000, 0.2500000, 0.2500000, 0.2500000], # [0.2500000, 0.2500000, 0.2500000, 0.2500000] # ]
QuantumLayerV2¶
If you are more familiar with pyQPanda2 syntax, please using QuantumLayerV2 class, you can define the quantum circuits function by using qubits, cbits and machine, then take it as a argument qprog_with_measure of QuantumLayerV2.
- class pyvqnet.qnn.quantumlayer.QuantumLayerV2(qprog_with_measure, para_num, diff_method: str = 'parameter_shift', delta: float = 0.01, dtype=None, name='')¶
Abstract calculation module for variational quantum circuits. It simulates a parameterized quantum circuit and gets the measurement result. QuantumLayer inherits from Module ,so that it can calculate gradients of circuits parameters,and train variational quantum circuits model or embed variational quantum circuits into hybird quantum and classic model.
To use this module, you need to create your quantum virtual machine and allocate qubits and cbits.
- 参数:
qprog_with_measure – callable quantum circuits functions ,cosntructed by pyQPanda2
para_num – int - Number of parameter
diff_method – ‘parameter_shift’ or ‘finite_diff’
delta – delta for diff
dtype – The data type of the parameter, defaults: None, use the default data type kfloat32, which represents a 32-bit floating point number.
name – name of the output layer
- 返回:
a module can calculate quantum circuits .
备注
qprog_with_measure is quantum circuits function defined in pyQPanda :https://pyqpanda-toturial.readthedocs.io/zh/latest/QCircuit.html.
This function should contains following parameters,otherwise it can not run properly in QuantumLayerV2.
Compare to QuantumLayer.you should allocate qubits and simulator: https://pyqpanda-toturial.readthedocs.io/zh/latest/QuantumMachine.html,
you may also need to allocate cbits if qprog_with_measure needs quantum measure: https://pyqpanda-toturial.readthedocs.io/zh/latest/Measure.html
qprog_with_measure (input,param)
input: array_like input 1-dim classic data
param: array_like input 1-dim quantum circuit’s parameters
备注
The class have alias: QpandaQCircuitVQCLayerLite .
Example:
import pyqpanda as pq from pyvqnet.qnn.measure import ProbsMeasure from pyvqnet.qnn.quantumlayer import QuantumLayerV2 import numpy as np from pyvqnet.tensor import QTensor def pqctest (input,param): num_of_qubits = 4 m_machine = pq.CPUQVM()# outside m_machine.init_qvm()# outside qubits = m_machine.qAlloc_many(num_of_qubits) circuit = pq.QCircuit() circuit.insert(pq.H(qubits[0])) circuit.insert(pq.H(qubits[1])) circuit.insert(pq.H(qubits[2])) circuit.insert(pq.H(qubits[3])) circuit.insert(pq.RZ(qubits[0],input[0])) circuit.insert(pq.RZ(qubits[1],input[1])) circuit.insert(pq.RZ(qubits[2],input[2])) circuit.insert(pq.RZ(qubits[3],input[3])) circuit.insert(pq.CNOT(qubits[0],qubits[1])) circuit.insert(pq.RZ(qubits[1],param[0])) circuit.insert(pq.CNOT(qubits[0],qubits[1])) circuit.insert(pq.CNOT(qubits[1],qubits[2])) circuit.insert(pq.RZ(qubits[2],param[1])) circuit.insert(pq.CNOT(qubits[1],qubits[2])) circuit.insert(pq.CNOT(qubits[2],qubits[3])) circuit.insert(pq.RZ(qubits[3],param[2])) circuit.insert(pq.CNOT(qubits[2],qubits[3])) prog = pq.QProg() prog.insert(circuit) rlt_prob = ProbsMeasure([0,2],prog,m_machine,qubits) return rlt_prob pqc = QuantumLayerV2(pqctest,3) #classic data as input input = QTensor([[1,2,3,4],[4,2,2,3],[3,3,2,2.0]] ) #forward circuits rlt = pqc(input) grad = QTensor(np.ones(rlt.data.shape)*1000) #backward circuits rlt.backward(grad) print(rlt) # [ # [0.2500000, 0.2500000, 0.2500000, 0.2500000], # [0.2500000, 0.2500000, 0.2500000, 0.2500000], # [0.2500000, 0.2500000, 0.2500000, 0.2500000] # ]
QuantumBatchAsyncQcloudLayer¶
When you install the latest version of pyqpanda, you can use this interface to define a variational circuit and submit it to originqc for running on the real chip.
- class pyvqnet.qnn.quantumlayer.QuantumBatchAsyncQcloudLayer(origin_qprog_func, qcloud_token, para_num, num_qubits, num_cubits, pauli_str_dict=None, shots=1000, initializer=None, dtype=None, name='', diff_method='parameter_shift ', submit_kwargs={}, query_kwargs={})¶
Abstract computing module for originqc real chips using pyqpanda QCLOUD starting with version 3.8.2.2. It submits parameterized quantum circuits to real chips and obtains measurement results. If diff_method == “random_coordinate_descent” , we will randomly select a single parameter to compute the gradient, and the other parameters will remain zero. Ref: https://arxiv.org/abs/2311.00088 .
备注
qcloud_token is the API token you applied for at https://qcloud.originqc.com.cn/. origin_qprog_func needs to return data of type pypqanda.QProg. If pauli_str_dict is not set, you need to ensure that measure has been inserted into the QProg. The form of origin_qprog_func must be as follows:
origin_qprog_func(input,param,qubits,cbits,machine)
input: Input 1~2-dimensional classic data. In the case of two-dimensional data, the first dimension is the batch size.
param: Enter the parameters to be trained for the one-dimensional variational quantum circuit.
machine: The simulator QCloud created by QuantumBatchAsyncQcloudLayer does not require users to define it in additional functions.
qubits: Qubits created by the simulator QCloud created by QuantumBatchAsyncQcloudLayer, the number is num_qubits, the type is pyQpanda.Qubits, no need for the user to define it in the function.
cbits: Classic bits allocated by QuantumBatchAsyncQcloudLayer, the number is num_cubits, the type is pyQpanda.ClassicalCondition, no need for the user to define it in the function. .
- 参数:
origin_qprog_func – The variational quantum circuit function built by pyQPanda2 must return type of QProg.
qcloud_token – str - The type of quantum machine or cloud token used for execution.
para_num – int - Number of parameters, the parameter is a QTensor of size [para_num].
num_qubits – int - Number of qubits in the quantum circuit.
num_cubits – int - The number of classical bits used for measurement in quantum circuits.
pauli_str_dict – dict|list - A dictionary or list of dictionaries representing Pauli operators in quantum circuits. The default is “none”, and the measurement operation is performed. If a dictionary of Pauli operators is entered, a single expectation or multiple expectations will be calculated.
shot – int - Number of measurements. The default value is 1000.
initializer – Initializer for parameter values. The default is “None”, using 0~2*pi normal distribution.
dtype – The data type of the parameter. The default value is None, which uses the default data type pyvqnet.kfloat32.
name – The name of the module. Defaults to empty string.
diff_method – Differentiation method for gradient computation. Default is “parameter_shift”. If diff_method == “random_coordinate_descent” , we will randomly select a single parameter to compute the gradient, and the other parameters will remain zero. Ref: https://arxiv.org/abs/2311.00088 .
submit_kwargs – Additional keyword parameters for submitting quantum circuits, default: {“chip_id”:pyqpanda.real_chip_type.origin_72,”is_amend”:True,”is_mapping”:True,”is_optimization”:True,”compile_level”:3, “default_task_group_size”:200, “test_qcloud_fake”:False}, when test_qcloud_fake is set to True, the local CPUQVM is simulated.
query_kwargs – Additional keyword parameters for querying quantum results, default: {“timeout”:2,”print_query_info”:True,”sub_circuits_split_size”:1}.
- 返回:
A module that can calculate quantum circuits.
Example:
import numpy as np import pyqpanda as pq import pyvqnet from pyvqnet.qnn import QuantumLayer,QuantumBatchAsyncQcloudLayer from pyvqnet.qnn import expval_qcloud #set_test_qcloud_fake(False) #uncomments this code to use realchip def qfun(input,param, m_machine, m_qlist,cubits): measure_qubits = [0,2] m_prog = pq.QProg() cir = pq.QCircuit() cir.insert(pq.RZ(m_qlist[0],input[0])) cir.insert(pq.CNOT(m_qlist[0],m_qlist[1])) cir.insert(pq.RY(m_qlist[1],param[0])) cir.insert(pq.CNOT(m_qlist[0],m_qlist[2])) cir.insert(pq.RZ(m_qlist[1],input[1])) cir.insert(pq.RY(m_qlist[2],param[1])) cir.insert(pq.H(m_qlist[2])) m_prog.insert(cir) for idx, ele in enumerate(measure_qubits): m_prog << pq.Measure(m_qlist[ele], cubits[idx]) # pylint: disable=expression-not-assigned return m_prog l = QuantumBatchAsyncQcloudLayer(qfun, "3047DE8A59764BEDAC9C3282093B16AF1", 2, 6, 6, pauli_str_dict=None, shots = 1000, initializer=None, dtype=None, name="", diff_method="parameter_shift", submit_kwargs={}, query_kwargs={}) x = pyvqnet.tensor.QTensor([[0.56,1.2],[0.56,1.2],[0.56,1.2],[0.56,1.2],[0.56,1.2]],requires_grad= True) y = l(x) print(y) y.backward() print(l.m_para.grad) print(x.grad) def qfun2(input,param, m_machine, m_qlist,cubits): measure_qubits = [0,2] m_prog = pq.QProg() cir = pq.QCircuit() cir.insert(pq.RZ(m_qlist[0],input[0])) cir.insert(pq.CNOT(m_qlist[0],m_qlist[1])) cir.insert(pq.RY(m_qlist[1],param[0])) cir.insert(pq.CNOT(m_qlist[0],m_qlist[2])) cir.insert(pq.RZ(m_qlist[1],input[1])) cir.insert(pq.RY(m_qlist[2],param[1])) cir.insert(pq.H(m_qlist[2])) m_prog.insert(cir) return m_prog l = QuantumBatchAsyncQcloudLayer(qfun2, "3047DE8A59764BEDAC9C3282093B16AF", 2, 6, 6, pauli_str_dict={'Z0 X1':10,'':-0.5,'Y2':-0.543}, shots = 1000, initializer=None, dtype=None, name="", diff_method="parameter_shift", submit_kwargs={}, query_kwargs={}) x = pyvqnet.tensor.QTensor([[0.56,1.2],[0.56,1.2],[0.56,1.2],[0.56,1.2]],requires_grad= True) y = l(x) print(y) y.backward() print(l.m_para.grad) print(x.grad)
QuantumLayerMultiProcess¶
If you are more familiar with pyQPanda syntax, please using QuantumLayerMultiProcess class, you can define the quantum circuits function by using qubits, cbits and machine, then take it as a argument qprog_with_measure of QuantumLayerMultiProcess.
- class pyvqnet.qnn.quantumlayer.QuantumLayerMultiProcess(qprog_with_measure, para_num, machine_type_or_cloud_token, num_of_qubits: int, num_of_cbits: int = 1, diff_method: str = 'parameter_shift', delta: float = 0.01, dtype=None, name='')¶
Abstract calculation module for variational quantum circuits. This class uses multiprocess to accelerate quantum circuit simulation.
It simulates a parameterized quantum circuit and gets the measurement result. QuantumLayer inherits from Module ,so that it can calculate gradients of circuits parameters,and train variational quantum circuits model or embed variational quantum circuits into hybird quantum and classic model.
To use this module, you need to create your quantum virtual machine and allocate qubits and cbits.
- 参数:
qprog_with_measure – callable quantum circuits functions ,cosntructed by pyQPanda2.
para_num – int - Number of parameter
num_of_qubits – num of qubits.
num_of_cbits – num of classic bits.
diff_method – ‘parameter_shift’ or ‘finite_diff’.
delta – delta for diff.
dtype – The data type of the parameter, defaults: None, use the default data type kfloat32, which represents a 32-bit floating point number.
name – name of the output layer
- 返回:
a module can calculate quantum circuits .
备注
qprog_with_measure is quantum circuits function defined in pyQPanda : https://github.com/OriginQ/QPanda-2.
This function should contains following parameters,otherwise it can not run properly in QuantumLayerMultiProcess.
Compare to QuantumLayer.you should allocate qubits and simulator,
you may also need to allocate cbits if qprog_with_measure needs quantum Measure.
qprog_with_measure (input,param)
input: array_like input 1-dim classic data
param: array_like input 1-dim quantum circuit’s parameters
Example:
import pyqpanda as pq from pyvqnet.qnn.measure import ProbsMeasure from pyvqnet.qnn.quantumlayer import QuantumLayerMultiProcess import numpy as np from pyvqnet.tensor import QTensor def pqctest (input,param,nqubits,ncubits): machine = pq.CPUQVM() machine.init_qvm() qubits = machine.qAlloc_many(nqubits) circuit = pq.QCircuit() circuit.insert(pq.H(qubits[0])) circuit.insert(pq.H(qubits[1])) circuit.insert(pq.H(qubits[2])) circuit.insert(pq.H(qubits[3])) circuit.insert(pq.RZ(qubits[0],input[0])) circuit.insert(pq.RZ(qubits[1],input[1])) circuit.insert(pq.RZ(qubits[2],input[2])) circuit.insert(pq.RZ(qubits[3],input[3])) circuit.insert(pq.CNOT(qubits[0],qubits[1])) circuit.insert(pq.RZ(qubits[1],param[0])) circuit.insert(pq.CNOT(qubits[0],qubits[1])) circuit.insert(pq.CNOT(qubits[1],qubits[2])) circuit.insert(pq.RZ(qubits[2],param[1])) circuit.insert(pq.CNOT(qubits[1],qubits[2])) circuit.insert(pq.CNOT(qubits[2],qubits[3])) circuit.insert(pq.RZ(qubits[3],param[2])) circuit.insert(pq.CNOT(qubits[2],qubits[3])) prog = pq.QProg() prog.insert(circuit) rlt_prob = ProbsMeasure([0,2],prog,machine,qubits) return rlt_prob pqc = QuantumLayerMultiProcess(pqctest,3,4,1) #classic data as input input = QTensor([[1.0,2,3,4],[4,2,2,3],[3,3,2,2]] ) #forward circuits rlt = pqc(input) grad = QTensor(np.ones(rlt.data.shape)*1000) #backward circuits rlt.backward(grad) print(rlt) # [ # [0.2500000, 0.2500000, 0.2500000, 0.2500000], # [0.2500000, 0.2500000, 0.2500000, 0.2500000], # [0.2500000, 0.2500000, 0.2500000, 0.2500000] # ]
NoiseQuantumLayer¶
In the real quantum computer, due to the physical characteristics of the quantum bit, there is always inevitable calculation error. In order to better simulate this error in quantum virtual machine, VQNet also supports quantum virtual machine with noise. The simulation of quantum virtual machine with noise is closer to the real quantum computer. We can customize the supported logic gate type and the noise model supported by the logic gate. The existing supported quantum noise model is defined in pyQPanda2 NoiseQVM .
We can use NoiseQuantumLayer to define an automatic microclassification of quantum circuits. NoiseQuantumLayer supports pyQPanda2 quantum virtual machine with noise. You can define a function as an argument qprog_with_measure. This function needs to contain the quantum circuit defined by pyQPanda, as also you need to pass in a argument noise_set_config, by using the pyQPanda interface to set up the noise model.
- class pyvqnet.qnn.quantumlayer.NoiseQuantumLayer(qprog_with_measure, para_num, machine_type, num_of_qubits: int, num_of_cbits: int = 1, diff_method: str = 'parameter_shift', delta: float = 0.01, noise_set_config=None, dtype=None, name='')¶
Abstract calculation module for variational quantum circuits. It simulates a parameterized quantum circuit and gets the measurement result. QuantumLayer inherits from Module ,so that it can calculate gradients of circuits parameters,and train variational quantum circuits model or embed variational quantum circuits into hybird quantum and classic model.
This module should be initialized with noise model by
noise_set_config.- 参数:
qprog_with_measure – callable quantum circuits functions ,cosntructed by pyQPanda2
para_num – int - Number of para_num
machine_type – pyQPanda2 machine type
num_of_qubits – num of qubits
num_of_cbits – num of cbits
diff_method – ‘parameter_shift’ or ‘finite_diff’
delta – delta for diff
noise_set_config – noise set function
dtype – The data type of the parameter, defaults: None, use the default data type kfloat32, which represents a 32-bit floating point number.
name – name of the output layer
- 返回:
a module can calculate quantum circuits with noise model.
备注
qprog_with_measure is quantum circuits function defined in pyQPanda :https://pyqpanda-toturial.readthedocs.io/zh/latest/QCircuit.html.
This function should contains following parameters,otherwise it can not run properly in NoiseQuantumLayer.
qprog_with_measure (input,param,qubits,cbits,m_machine)
input: array_like input 1-dim classic data
param: array_like input 1-dim quantum circuit’s parameters
qubits: qubits allocated by NoiseQuantumLayer
cbits: cbits allocated by NoiseQuantumLayer.if your circuits does not use cbits,you should also reserve this parameter.
m_machine: simulator created by NoiseQuantumLayer
Example:
import pyqpanda as pq from pyvqnet.qnn.measure import ProbsMeasure from pyvqnet.qnn.quantumlayer import NoiseQuantumLayer import numpy as np from pyqpanda import * from pyvqnet.tensor import QTensor def circuit(weights, param, qubits, cbits, machine): circuit = pq.QCircuit() circuit.insert(pq.H(qubits[0])) circuit.insert(pq.RY(qubits[0], weights[0])) circuit.insert(pq.RY(qubits[0], param[0])) prog = pq.QProg() prog.insert(circuit) prog << measure_all(qubits, cbits) result = machine.run_with_configuration(prog, cbits, 100) counts = np.array(list(result.values())) states = np.array(list(result.keys())).astype(float) # Compute probabilities for each state probabilities = counts / 100 # Get state expectation expectation = np.sum(states * probabilities) return expectation def default_noise_config(qvm, q): p = 0.01 qvm.set_noise_model(NoiseModel.BITFLIP_KRAUS_OPERATOR, GateType.PAULI_X_GATE, p) qvm.set_noise_model(NoiseModel.BITFLIP_KRAUS_OPERATOR, GateType.PAULI_Y_GATE, p) qvm.set_noise_model(NoiseModel.BITFLIP_KRAUS_OPERATOR, GateType.PAULI_Z_GATE, p) qvm.set_noise_model(NoiseModel.BITFLIP_KRAUS_OPERATOR, GateType.RX_GATE, p) qvm.set_noise_model(NoiseModel.BITFLIP_KRAUS_OPERATOR, GateType.RY_GATE, p) qvm.set_noise_model(NoiseModel.BITFLIP_KRAUS_OPERATOR, GateType.RZ_GATE, p) qvm.set_noise_model(NoiseModel.BITFLIP_KRAUS_OPERATOR, GateType.RY_GATE, p) qvm.set_noise_model(NoiseModel.BITFLIP_KRAUS_OPERATOR, GateType.HADAMARD_GATE, p) qves = [] for i in range(len(q) - 1): qves.append([q[i], q[i + 1]]) # qves.append([q[len(q) - 1], q[0]]) qvm.set_noise_model(NoiseModel.DAMPING_KRAUS_OPERATOR, GateType.CNOT_GATE, p, qves) return qvm qvc = NoiseQuantumLayer(circuit, 24, "noise", 1, 1, diff_method="parameter_shift", delta=0.01, noise_set_config=default_noise_config) input = QTensor([[0., 1., 1., 1.], [0., 0., 1., 1.], [1., 0., 1., 1.]]) rlt = qvc(input) grad = QTensor(np.ones(rlt.data.shape) * 1000) rlt.backward(grad) print(qvc.m_para.grad) #[1195., 105., 70., 0., # 45., -45., 50., 15., # -80., 50., 10., -30., # 10., 60., 75., -110., # 55., 45., 25., 5., # 5., 50., -25., -15.]
Here is an example of noise_set_config, here we add the noise model BITFLIP_KRAUS_OPERATOR where the noise argument p=0.01 to the quantum gate RX , RY , RZ , X , Y , Z , H, etc.
def noise_set_config(qvm,q):
p = 0.01
qvm.set_noise_model(NoiseModel.BITFLIP_KRAUS_OPERATOR, GateType.PAULI_X_GATE, p)
qvm.set_noise_model(NoiseModel.BITFLIP_KRAUS_OPERATOR, GateType.PAULI_Y_GATE, p)
qvm.set_noise_model(NoiseModel.BITFLIP_KRAUS_OPERATOR, GateType.PAULI_Z_GATE, p)
qvm.set_noise_model(NoiseModel.BITFLIP_KRAUS_OPERATOR, GateType.RX_GATE, p)
qvm.set_noise_model(NoiseModel.BITFLIP_KRAUS_OPERATOR, GateType.RY_GATE, p)
qvm.set_noise_model(NoiseModel.BITFLIP_KRAUS_OPERATOR, GateType.RZ_GATE, p)
qvm.set_noise_model(NoiseModel.BITFLIP_KRAUS_OPERATOR, GateType.RY_GATE, p)
qvm.set_noise_model(NoiseModel.BITFLIP_KRAUS_OPERATOR, GateType.HADAMARD_GATE, p)
qves =[]
for i in range(len(q)-1):
qves.append([q[i],q[i+1]])#
qves.append([q[len(q)-1],q[0]])
qvm.set_noise_model(NoiseModel.DAMPING_KRAUS_OPERATOR, GateType.CNOT_GATE, p, qves)
return qvm
DataParallelHybirdVQCQpandaQVMLayer¶
- class pyvqnet.qnn.DataParallelHybirdVQCQpandaQVMLayer(vqc_module: Module, qcloud_token: str, num_qubits: int, num_cubits: int, pauli_str_dict: List[Dict] | Dict | None = None, shots: int = 1000, dtype: int | None = None, name: str = '', submit_kwargs: Dict = {}, query_kwargs: Dict = {})¶
A data parallel version of
HybirdVQCQpandaQVMLayer, wherevqc_moduleis a user-defined quantum variational circuit model, and the QMachine settingsave_ir= True. Use data parallelism to batch the first dimension of the input data The number of processes is divided according to the number of processes allocated in CommController, and data parallelism is performed in multiple processes based on mpi or nccl. Please note that one process corresponds to a GPU device on one node. This module in each process Submit the quantum circuit generated by batch processing number/node number data in forward calculation, calculate the gradient contributed by batch processing number/node number data in reverse calculation, and calculate the average gradient of parameters on multiple nodes through all_reduce.备注
This module splits the input internally and moves the data to the corresponding device. The 0th process calculates [0, batch number/node number] data, and the kth process calculates [(k-1) batch number/node number, k*batch number/node number]
- 参数:
vqc_module – with forward() of vqc_module.
qcloud_token – str - Type of quantum machine or cloud token to use for execution.
num_qubits – int - Number of qubits in the quantum circuit.
num_cubits – int - The number of classical bits used for measurement in the quantum circuit.
pauli_str_dict – dict|list - A dictionary or list of dictionaries representing the Pauli operators in the quantum circuit. Default is None.
shots – int - The number of shots in the quantum circuit. Number of line measurements. The default value is 1000.
name – Module name. The default value is an empty string.
submit_kwargs – Additional keyword parameters for submitting quantum circuits, default value:{“chip_id”:pyqpanda.real_chip_type.origin_72,”is_amend”:True,”is_mapping”:True,”is_optimization”:True,”default_task_group_size”:200 ,”test_qcloud_fake”:True}.
query_kwargs – Additional keyword parameters for querying quantum results, default value: {“timeout”:2,”print_query_info”:True,”sub_circuits_split_size”:1}.
The following is calculated using cpu For example, the command for a single node and dual processes is as follows: mpirun -n 2 python xxx.py
Example:
from pyvqnet.distributed import * Comm_OP = CommController("mpi") from pyvqnet.qnn import * from pyvqnet.qnn.vqc import * import pyvqnet from pyvqnet.nn import Module, Linear from pyvqnet.device import DEV_GPU_0 pyvqnet.utils.set_random_seed(42) class Hybird(Module): def __init__(self): self.cl1 = Linear(3, 3) self.ql = QModel(num_wires=6, dtype=pyvqnet.kcomplex64) self.cl2 = Linear(1, 2) def forward(self, x): x = self.cl1(x) x = self.ql(x) x = self.cl2(x) return x class QModel(Module): def __init__(self, num_wires, dtype, grad_mode=""): super(QModel, self).__init__() self._num_wires = num_wires self._dtype = dtype self.qm = QMachine(num_wires, dtype=dtype, grad_mode=grad_mode, save_ir=True) self.rx_layer = RX(has_params=True, trainable=False, wires=0) self.ry_layer = RY(has_params=True, trainable=False, wires=1) self.rz_layer = RZ(has_params=True, trainable=False, wires=1) self.u1 = U1(has_params=True, trainable=True, wires=[2]) self.u2 = U2(has_params=True, trainable=True, wires=[3]) self.u3 = U3(has_params=True, trainable=True, wires=[1]) self.i = I(wires=[3]) self.s = S(wires=[3]) self.x1 = X1(wires=[3]) self.y1 = Y1(wires=[3]) self.z1 = Z1(wires=[3]) self.x = PauliX(wires=[3]) self.y = PauliY(wires=[3]) self.z = PauliZ(wires=[3]) self.swap = SWAP(wires=[2, 3]) self.cz = CZ(wires=[2, 3]) self.cr = CR(has_params=True, trainable=True, wires=[2, 3]) self.rxx = RXX(has_params=True, trainable=True, wires=[2, 3]) self.rzz = RYY(has_params=True, trainable=True, wires=[2, 3]) self.ryy = RZZ(has_params=True, trainable=True, wires=[2, 3]) self.rzx = RZX(has_params=True, trainable=False, wires=[2, 3]) self.toffoli = Toffoli(wires=[2, 3, 4], use_dagger=True) self.h = Hadamard(wires=[1]) self.iSWAP = iSWAP(True, True, wires=[0, 2]) self.tlayer = T(wires=1) self.cnot = CNOT(wires=[0, 1]) self.measure = MeasureAll(obs={'Z0': 2, 'Y3': 3}) def forward(self, x, *args, **kwargs): self.qm.reset_states(x.shape[0]) self.i(q_machine=self.qm) self.s(q_machine=self.qm) self.swap(q_machine=self.qm) self.cz(q_machine=self.qm) self.x(q_machine=self.qm) self.x1(q_machine=self.qm) self.y(q_machine=self.qm) self.y1(q_machine=self.qm) self.z(q_machine=self.qm) self.z1(q_machine=self.qm) self.ryy(q_machine=self.qm) self.rxx(q_machine=self.qm) self.rzz(q_machine=self.qm) self.rzx(q_machine=self.qm, params=x[:, [1]]) self.cr(q_machine=self.qm) self.u1(q_machine=self.qm) self.u2(q_machine=self.qm) self.u3(q_machine=self.qm) self.rx_layer(params=x[:, [0]], q_machine=self.qm) self.cnot(q_machine=self.qm) self.h(q_machine=self.qm) self.iSWAP(q_machine=self.qm) self.ry_layer(params=x[:, [1]], q_machine=self.qm) self.tlayer(q_machine=self.qm) self.rz_layer(params=x[:, [2]], q_machine=self.qm) self.toffoli(q_machine=self.qm) rlt = self.measure(q_machine=self.qm) return rlt device = Comm_OP.get_rank input_x = tensor.QTensor([[0.1, 0.2, 0.3]]) input_x = tensor.broadcast_to(input_x, [20, 3]) input_x.requires_grad = True qunatum_model = QModel(num_wires=6, dtype=pyvqnet.kcomplex64) l = DataParallelHybirdVQCQpandaQVMLayer( Comm_OP, qunatum_model, "3047DE8A59764BEDAC9C3282093B16AF1", num_qubits=6, num_cubits=6, pauli_str_dict={ 'Z0': 2, 'Y3': 3 }, shots=1000, name="", submit_kwargs={"test_qcloud_fake": True}, query_kwargs={}) y = l(input_x) print(y) y.backward() for p in qunatum_model.parameters(): print(p.grad)
The following is an example of nccl calculation using gpu. The command for single node dual process is as follows: mpirun -n 2 python xxx.py
Example:
from pyvqnet.distributed import * Comm_OP = CommController("nccl") #rest code not changed
The following is an example of multi-node multi-process parallel calculation. Please ensure that the script is run in the same path and the same python environment on different nodes, and write the ip address mapping file hosts on each node. The format refers to hostfile, f, hostfile.
Example:
#hosts example 10.10.7.107 slots=2 10.10.7.109 slots=2
To use mpi for 2 nodes, 2 processes per node, and 4 processes in total, you can run vqnetrun -np 4 -f hosts python xxx.py
Example:
from pyvqnet.distributed import * Comm_OP = CommController("mpi") #rest code not changed
To use nccl for 2 nodes, 2 processes per node, and 4 processes in total, you can run vqnetrun -np 4 -f hosts python xxx.py
Example:
from pyvqnet.distributed import * Comm_OP = CommController("nccl") #rest code not changed
Quantum Gates¶
The way to deal with qubits is called quantum gates. Using quantum gates, we consciously evolve quantum states. Quantum gates are the basis of quantum algorithms.
Basic quantum gates¶
In VQNet, we use each logic gate of pyQPanda developed by the original quantum to build quantum circuit and conduct quantum simulation. The gates currently supported by pyQPanda can be defined in pyQPanda’s quantum gate section. In addition, VQNet also encapsulates some quantum gate combinations commonly used in quantum machine learning.
AmplitudeEmbeddingCircuit¶
- pyvqnet.qnn.template.AmplitudeEmbeddingCircuit(input_feat, qubits)¶
Encodes \(2^n\) features into the amplitude vector of \(n\) qubits. To represent a valid quantum state vector, the L2-norm of
featuresmust be one.- 参数:
input_feat – numpy array which represents paramters
qubits – qubits allocated by pyQPanda
- 返回:
quantum circuits
Example:
import numpy as np import pyqpanda as pq from pyvqnet.qnn.template import AmplitudeEmbeddingCircuit input_feat = np.array([2.2, 1, 4.5, 3.7]) m_machine = pq.init_quantum_machine(pq.QMachineType.CPU) m_qlist = m_machine.qAlloc_many(2) m_clist = m_machine.cAlloc_many(2) m_prog = pq.QProg() cir = AmplitudeEmbeddingCircuit(input_feat,m_qlist) print(cir) pq.destroy_quantum_machine(m_machine) # ┌────────────┐ ┌────────────┐ # q_0: |0>─────────────── ─── ┤RY(0.853255)├ ─── ┤RY(1.376290)├ # ┌────────────┐ ┌─┐ └──────┬─────┘ ┌─┐ └──────┬─────┘ # q_1: |0>─┤RY(2.355174)├ ┤X├ ───────■────── ┤X├ ───────■────── # └────────────┘ └─┘ └─┘
Quantum Machine Learning APIs using pyQPanda2¶
Quantum Generative Adversarial Networks for learning and loading random distributions¶
Quantum Generative Adversarial Networks(QGAN )algorithm uses pure quantum variational circuits to prepare the generated quantum states with specific random distribution, which can reduce the logic gates required to generate specific quantum states and reduce the complexity of quantum circuits.It uses the classical GAN model structure, which has two sub-models: Generator and Discriminator. The Generator generates a specific distribution for the quantum circuit.And the Discriminator discriminates the generated data samples generated by the Generator and the real randomly distributed training data samples. Here is an example of VQNet implementing QGAN learning and loading random distributions based on the paper Quantum Generative Adversarial Networks for learning and loading random distributions of Christa Zoufal.
In order to realize the construction of QGANAPI class of quantum generative adversarial network by VQNet, the quantum generator is used to prepare the initial state of the real distributed data. The number of quantum bits is 3, and the repetition times of the internal parametric circuit module of the quantum generator is 1. Meanwhile, KL is used as the metric for the QGAN loading random distribution.
import pickle
import os
import pyqpanda as pq
from pyvqnet.qnn.qgan.qgan_utils import QGANAPI
import numpy as np
num_of_qubits = 3 # paper config
rep = 1
number_of_data = 10000
# Load data samples from different distributions
mu = 1
sigma = 1
real_data = np.random.lognormal(mean=mu, sigma=sigma, size=number_of_data)
# intial
save_dir = None
qgan_model = QGANAPI(
real_data,
# numpy generated data distribution, 1 - dim.
num_of_qubits,
batch_size=2000,
num_epochs=2000,
q_g_cir=None,
bounds = [0.0,2**num_of_qubits -1],
reps=rep,
metric="kl",
tol_rel_ent=0.01,
if_save_param_dir=save_dir
)
The following is the train module of QGAN.
# train
qgan_model.train() # train qgan
The eval module of QGAN is designed to draw the loss function curve and probability distribution diagram between the random distribution prepared by QGAN and the real distribution.
# show probability distribution function of generated distribution and real distribution
qgan_model.eval(real_data) #draw pdf
The get_trained_quantum_parameters module of QGAN is used to get training parameters and output them as a numpy array. If save_DIR is not empty, the training parameters are saved to a file.The Load_param_and_eval module of QGAN loads training parameters, and the get_circuits_with_trained_param module obtains pyQPanda circuit generated by quantum generator after training.
# get trained quantum parameters
param = qgan_model.get_trained_quantum_parameters()
print(f" trained param {param}")
#load saved parameters files
if save_dir is not None:
path = os.path.join(
save_dir, qgan_model._start_time + "trained_qgan_param.pickle")
with open(path, "rb") as file:
t3 = pickle.load(file)
param = t3["quantum_parameters"]
print(f" trained param {param}")
#show probability distribution function of generated distribution and real distribution
qgan_model.load_param_and_eval(param)
#calculate metric
print(qgan_model.eval_metric(param, "kl"))
#get generator quantum circuit
m_machine = pq.CPUQVM()
m_machine.init_qvm()
qubits = m_machine.qAlloc_many(num_of_qubits)
qpanda_cir = qgan_model.get_circuits_with_trained_param(qubits)
print(qpanda_cir)
In general, QGAN learning and loading random distribution requires multiple training models with different random seeds to obtain the expected results. For example, the following is the graph of the probability distribution function between the lognormal distribution implemented by QGAN and the real lognormal distribution, and the loss function curve between QGAN’s generator and discriminator.
quantum kernal SVM¶
In machine learning tasks, data often cannot be separated by a hyperplane in the original space. A common technique for finding such hyperplanes is to apply a nonlinear transformation function to the data. This function is called a feature map, through which we can calculate how close the data points are in this new feature space for the classification task of machine learning.
This example refers to the thesis: Supervised learning with quantum enhanced feature spaces . The first method constructs variational circuits for data classification tasks.
gen_vqc_qsvm_data is the data needed to generate this example. vqc_qsvm is a variable sub-circuit class used to classify the input data.
The vqc_qsvm.plot() function visualizes the distribution of the data.
""" VQC QSVM """ from pyvqnet.qnn.svm import vqc_qsvm, gen_vqc_qsvm_data import matplotlib.pyplot as plt import numpy as np batch_size = 40 maxiter = 40 training_size = 20 test_size = 10 gap = 0.3 #sub-circuits repeat times rep = 3 #defines QSVM class VQC_QSVM = vqc_qsvm(batch_size, maxiter, rep) #randomly generates data from thesis. train_features, test_features, train_labels, test_labels, samples = \ gen_vqc_qsvm_data(training_size=training_size, test_size=test_size, gap=gap) VQC_QSVM.plot(train_features, test_features, train_labels, test_labels, samples) #train VQC_QSVM.train(train_features, train_labels) #test rlt, acc_1 = VQC_QSVM.predict(test_features, test_labels) print(f"testing_accuracy {acc_1}")
In addition to the above-mentioned direct use of variational quantum circuits to map classical data features to quantum feature spaces, in the paper Supervised learning with quantum enhanced feature spaces, the method of directly estimating kernel functions using quantum circuits and classifying them using classical support vector machines is also introduced. Analogy to various kernel functions in classical SVM \(K(i,j)\) , use quantum kernel function to define the inner product of classical data in quantum feature space \(\phi(\mathbf{x}_i)\) :
Using VQNet and pyQPanda, we define a QuantumKernel_VQNet to generate a quantum kernel function and use sklearn for classification:
import numpy as np
import pyqpanda as pq
from sklearn.svm import SVC
from pyqpanda import *
from pyqpanda.Visualization.circuit_draw import *
from pyvqnet.qnn.svm import QuantumKernel_VQNet, gen_vqc_qsvm_data
import matplotlib
try:
matplotlib.use('TkAgg')
except:
pass
import matplotlib.pyplot as plt
train_features, test_features,train_labels, test_labels, samples = gen_vqc_qsvm_data(20,5,0.3)
quantum_kernel = QuantumKernel_VQNet(n_qbits=2)
quantum_svc = SVC(kernel=quantum_kernel.evaluate)
quantum_svc.fit(train_features, train_labels)
score = quantum_svc.score(test_features, test_labels)
print(f"quantum kernel classification test score: {score}")
Simultaneous Perturbation Stochastic Approximation optimizers¶
- pyvqnet.qnn.SPSA(maxiter: int = 1000, save_steps: int = 1, last_avg: int = 1, c0: float = _C0, c1: float = 0.2, c2: float = 0.602, c3: float = 0.101, c4: float = 0, init_para=None, model=None, calibrate_flag=False)¶
Simultaneous Perturbation Stochastic Approximation (SPSA) optimizer.
SPSA provides a stochastic method for approximating the gradient of a multivariate differentiable cost function. To achieve this, the cost function is evaluated twice using a perturbed parameter vector: each component of the original parameter vector is simultaneously shifted by a randomly generated value. Further information is available on the SPSA website.
- 参数:
maxiter – The maximum number of iterations to perform. Default value: 1000.
save_steps – Save the intermediate information of each save_steps step. Default value: 1.
last_avg – Averaging parameter for last_avg iterations. If last_avg = 1, only the last iteration is considered. Default value: 1.
c0 – initial a. Step size for updating parameters. Default value: 0.2*pi
c1 – initial c. The step size used to approximate the gradient. Default: 0.1.
c2 – alpha from the paper, used to adjust a(c0) at each iteration. Default value: 0.602.
c3 – gamma in the paper, used to adjust c(c1) at each iteration. Default value: 0.101.
c4 – Also used to control the parameters of a. Default value: 0.
init_para – Initialization parameters. Default: None.
model – Parametric model: model. Default: None.
calibrate_flag – whether to calibrate hpyer parameters a and c, default value: False.
- 返回:
an SPSA optimizer instance
警告
SPSA only supports 1-dim paramters.
Example:
import numpy as np import pyqpanda as pq import sys sys.path.insert(0, "../") import pyvqnet from pyvqnet.nn.module import Module from pyvqnet.qnn import SPSA from pyvqnet.tensor.tensor import QTensor from pyvqnet.qnn import AngleEmbeddingCircuit, expval, QuantumLayerV2, expval from pyvqnet.qnn.template import BasicEntanglerTemplate class Model_spsa(Module): def __init__(self): super(Model_spsa, self).__init__() self.qvc = QuantumLayerV2(layer_fn_spsa_pq, 3) def forward(self, x): y = self.qvc(x) return y def layer_fn_spsa_pq(input, weights): num_of_qubits = 1 machine = pq.CPUQVM() machine.init_qvm() qubits = machine.qAlloc_many(num_of_qubits) c1 = AngleEmbeddingCircuit(input, qubits) weights =weights.reshape([4,1]) bc_class = BasicEntanglerTemplate(weights, 1) c2 = bc_class.create_circuit(qubits) m_prog = pq.QProg() m_prog.insert(c1) m_prog.insert(c2) pauli_dict = {'Z0': 1} exp2 = expval(machine, m_prog, pauli_dict, qubits) return exp2 model = Model_spsa() optimizer = SPSA(maxiter=20, init_para=model.parameters(), model=model, )
- pyvqnet.qnn.SPSA._step(input_data)¶
use SPSA to optimize input data.
- 参数:
input_data – input data
- 返回:
train_para: final parameter
theta_best: The average parameters of after last last_avg.
Example:
import numpy as np import pyqpanda as pq import sys sys.path.insert(0, "../") import pyvqnet from pyvqnet.nn.module import Module from pyvqnet.qnn import SPSA from pyvqnet.tensor.tensor import QTensor from pyvqnet.qnn import AngleEmbeddingCircuit, expval, QuantumLayerV2, expval from pyvqnet.qnn.template import BasicEntanglerTemplate class Model_spsa(Module): def __init__(self): super(Model_spsa, self).__init__() self.qvc = QuantumLayerV2(layer_fn_spsa_pq, 3) def forward(self, x): y = self.qvc(x) return y def layer_fn_spsa_pq(input, weights): num_of_qubits = 1 machine = pq.CPUQVM() machine.init_qvm() qubits = machine.qAlloc_many(num_of_qubits) c1 = AngleEmbeddingCircuit(input, qubits) weights =weights.reshape([4,1]) bc_class = BasicEntanglerTemplate(weights, 1) c2 = bc_class.create_circuit(qubits) m_prog = pq.QProg() m_prog.insert(c1) m_prog.insert(c2) pauli_dict = {'Z0': 1} exp2 = expval(machine, m_prog, pauli_dict, qubits) return exp2 model = Model_spsa() optimizer = SPSA(maxiter=20, init_para=model.parameters(), model=model, ) data = QTensor(np.array([[0.27507603]])) p = model.parameters() p[0].data = pyvqnet._core.Tensor( np.array([3.97507603, 3.12950603, 1.00854038, 1.25907603])) optimizer._step(input_data=data) y = model(data) print(y)
Quantum fisher information computation matrix¶
- class pyvqnet.qnn.opt.quantum_fisher(py_qpanda_config, params, target_gate_type_lists, target_gate_bits_lists, qcir_lists, wires)¶
Returns the quantum fisher information matrix for a quantum circuit.
\[\mathrm{QFIM}_{i, j}=4 \operatorname{Re}\left[\left\langle\partial_i \psi(\boldsymbol{\theta}) \mid \partial_j \psi(\boldsymbol{\theta})\right\rangle-\left\langle\partial_i \psi(\boldsymbol{\theta}) \mid \psi(\boldsymbol{\theta})\right\rangle\left\langle\psi(\boldsymbol{\theta}) \mid \partial_j \psi(\boldsymbol{\theta})\right\rangle\right]\]The short version is :math:\(\left|\partial_j \psi(\boldsymbol{\theta})\right\rangle:=\frac{\partial}{\partial \theta_j}|\psi(\boldsymbol{\theta})\rangle\).
备注
Currently only RX,RY,RZ are supported.
- 参数:
params – Variable parameters in circuits.
target_gate_type_lists – Supports “RX”, “RY”, “RZ” or lists.
target_gate_bits_lists – Which quantum bit or bits the parameterised gate acts on .
qcir_lists – The list of quantum circles before the target parameterised gate to compute the metric tensor, see the following example.
wires – Total Quantum Bit Index for Quantum Circuits.
Example:
import pyqpanda as pq from pyvqnet import * from pyvqnet.qnn.opt import pyqpanda_config_wrapper, insert_pauli_for_mt, quantum_fisher from pyvqnet.qnn import ProbsMeasure import numpy as np import pennylane as qml import pennylane.numpy as pnp n_wires = 4 def layer_subcircuit_new(config: pyqpanda_config_wrapper, params): qcir = pq.QCircuit() qcir.insert(pq.RX(config._qubits[0], params[0])) qcir.insert(pq.RY(config._qubits[1], params[1])) qcir.insert(pq.CNOT(config._qubits[0], config._qubits[1])) qcir.insert(pq.RZ(config._qubits[2], params[2])) qcir.insert(pq.RZ(config._qubits[3], params[3])) return qcir def get_p1_diagonal_new(config, params, target_gate_type, target_gate_bits, wires): qcir = layer_subcircuit_new(config, params) qcir2 = insert_pauli_for_mt(config._qubits, target_gate_type, target_gate_bits) qcir3 = pq.QCircuit() qcir3.insert(qcir) qcir3.insert(qcir2) m_prog = pq.QProg() m_prog.insert(qcir3) return ProbsMeasure(wires, m_prog, config._machine, config._qubits) config = pyqpanda_config_wrapper(n_wires) qcir = [] qcir.append(get_p1_diagonal_new) params2 = QTensor([0.5, 0.5, 0.5, 0.25], requires_grad=True) mt = quantum_fisher(config, params2, [['RX', 'RY', 'RZ', 'RZ']], [[0, 1, 2, 3]], qcir, [0, 1, 2, 3]) # The above example shows that there are no identical gates in the same layer, # but in the same layer you need to modify the logic gates according to the following example. n_wires = 3 def layer_subcircuit_01(config: pyqpanda_config_wrapper, params): qcir = pq.QCircuit() qcir.insert(pq.RX(config._qubits[0], params[0])) qcir.insert(pq.RY(config._qubits[1], params[1])) qcir.insert(pq.CNOT(config._qubits[0], config._qubits[1])) return qcir def layer_subcircuit_02(config: pyqpanda_config_wrapper, params): qcir = pq.QCircuit() qcir.insert(pq.RX(config._qubits[0], params[0])) qcir.insert(pq.RY(config._qubits[1], params[1])) qcir.insert(pq.CNOT(config._qubits[0], config._qubits[1])) qcir.insert(pq.RZ(config._qubits[1], params[2])) return qcir def layer_subcircuit_03(config: pyqpanda_config_wrapper, params): qcir = pq.QCircuit() qcir.insert(pq.RX(config._qubits[0], params[0])) qcir.insert(pq.RY(config._qubits[1], params[1])) qcir.insert(pq.CNOT(config._qubits[0], config._qubits[1])) # 01 part qcir.insert(pq.RZ(config._qubits[1], params[2])) # 02 part qcir.insert(pq.RZ(config._qubits[1], params[3])) return qcir def get_p1_diagonal_01(config, params, target_gate_type, target_gate_bits, wires): qcir = layer_subcircuit_01(config, params) qcir2 = insert_pauli_for_mt(config._qubits, target_gate_type, target_gate_bits) qcir3 = pq.QCircuit() qcir3.insert(qcir) qcir3.insert(qcir2) m_prog = pq.QProg() m_prog.insert(qcir3) return ProbsMeasure(wires, m_prog, config._machine, config._qubits) def get_p1_diagonal_02(config, params, target_gate_type, target_gate_bits, wires): qcir = layer_subcircuit_02(config, params) qcir2 = insert_pauli_for_mt(config._qubits, target_gate_type, target_gate_bits) qcir3 = pq.QCircuit() qcir3.insert(qcir) qcir3.insert(qcir2) m_prog = pq.QProg() m_prog.insert(qcir3) return ProbsMeasure(wires, m_prog, config._machine, config._qubits) def get_p1_diagonal_03(config, params, target_gate_type, target_gate_bits, wires): qcir = layer_subcircuit_03(config, params) qcir2 = insert_pauli_for_mt(config._qubits, target_gate_type, target_gate_bits) qcir3 = pq.QCircuit() qcir3.insert(qcir) qcir3.insert(qcir2) m_prog = pq.QProg() m_prog.insert(qcir3) return ProbsMeasure(wires, m_prog, config._machine, config._qubits) config = pyqpanda_config_wrapper(n_wires) qcir = [] qcir.append(get_p1_diagonal_01) qcir.append(get_p1_diagonal_02) qcir.append(get_p1_diagonal_03) params2 = QTensor([0.5, 0.5, 0.5, 0.25], requires_grad=True) mt = quantum_fisher(config, params2, [['RX', 'RY'], ['RZ'], ['RZ']], # rx,ry counts as layer one, first rz as layer two, second rz as layer three. [[0, 1], [1], [1]], qcir, [0, 1])