Source code for mindquantum.nn.pqc

# Copyright 2021 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
"""Mindspore quantum simulator operator."""

from mindspore.ops.primitive import PrimitiveWithInfer
from mindspore.ops.primitive import prim_attr_register
from mindspore._checkparam import Validator as validator
from mindspore.common import dtype as mstype
from mindspore.ops._grad.grad_base import bprop_getters
import mindspore.ops as P
from mindquantum.circuit import Circuit
from mindquantum.gate import Hamiltonian
from ._check_qnn_input import _check_type_or_iterable_type
from ._check_qnn_input import _check_circuit
from ._check_qnn_input import _check_parameters_of_circuit


[docs]class PQC(PrimitiveWithInfer): r""" Evaluate a parameterized quantum circuit and calculate the gradient of each parameters. Inputs of this operation is generated by MindQuantum framework. Inputs: - **n_qubits** (int) - The qubit number of quantum simulator. - **encoder_params_names** (list[str]) - The parameters names of encoder circuit. - **ansatz_params_names** (list[str]) - The parameters names of ansatz circuit. - **gate_names** (list[str]) - The name of each gate. - **gate_matrix** (list[list[list[list[float]]]]) - Real part and image part of the matrix of quantum gate. - **gate_obj_qubits** (list[list[int]]) - Object qubits of each gate. - **gate_ctrl_qubits** (list[list[int]]) - Control qubits of each gate. - **gate_params_names** (list[list[str]]) - Parameter names of each gate. - **gate_coeff** (list[list[float]]) - Coefficient of eqch parameter of each gate. - **gate_requires_grad** (list[list[bool]]) - Whether to calculate gradient of parameters of gates. - **hams_pauli_coeff** (list[list[float]]) - Coefficient of pauli words. - **hams_pauli_word** (list[list[list[str]]]) - Pauli words. - **hams_pauli_qubit** (list[list[list[int]]]) - The qubit that pauli matrix act on. - **n_threads** (int) - Thread to evaluate input data. Outputs: - **expected_value** (Tensor) - The expected value of hamiltonian. - **g1** (Tensor) - Gradient of encode circuit parameters. - **g2** (Tensor) - Gradient of ansatz circuit parameters. Supported Platforms: ``CPU`` """ @prim_attr_register def __init__(self, n_qubits, encoder_params_names, ansatz_params_names, gate_names, gate_matrix, gate_obj_qubits, gate_ctrl_qubits, gate_params_names, gate_coeff, gate_requires_grad, hams_pauli_coeff, hams_pauli_word, hams_pauli_qubit, n_threads): """Initialize PQC""" self.init_prim_io_names( inputs=['encoder_data', 'ansatz_data'], outputs=['results', 'encoder_gradient', 'ansatz_gradient']) self.n_hams = len(hams_pauli_coeff) def check_shape_size(self, encoder_data, ansatz_data): if len(encoder_data) != 2: raise ValueError( "PQC input encoder_data should have dimension size \ equal to 2, but got {}.".format(len(encoder_data))) if len(ansatz_data) != 1: raise ValueError( "PQC input ansatz_data should have dimension size \ equal to 1, but got {}.".format(len(ansatz_data))) def infer_shape(self, encoder_data, ansatz_data): self.check_shape_size(encoder_data, ansatz_data) return [encoder_data[0], self.n_hams], [ encoder_data[0], self.n_hams, len(self.encoder_params_names) ], [encoder_data[0], self.n_hams, len(self.ansatz_params_names)] def infer_dtype(self, encoder_data, ansatz_data): args = {'encoder_data': encoder_data, 'ansatz_data': ansatz_data} validator.check_tensors_dtypes_same_and_valid(args, mstype.float_type, self.name) return encoder_data, encoder_data, encoder_data
@bprop_getters.register(PQC) def bprop_pqc(self): """Grad definition for `PQC` operation.""" t = P.Transpose() mul = P.Mul() sum_ = P.ReduceSum() def bprop(encoder_data, ansatz_data, out, dout): dx = t(out[1], (2, 0, 1)) dx = mul(dout[0], dx) dx = sum_(dx, 2) dx = t(dx, (1, 0)) dy = P.tensor_dot(dout[0], out[2], ((0, 1), (0, 1))) return dx, dy return bprop
[docs]def generate_pqc_operator(encoder_params_names, ansatz_params_names, circuit: Circuit, hams, n_threads=1): """ A method to generate a parameterized quantum circuit simulation operator. Args: encoder_params_names (list[str]): The list of parameter names for encoder circuit. ansatz_params_names (list[str]): The list of parameter names for ansatz circuit. circuit (Circuit): The whole circuit combined with encoder circuit and ansatz circuit. hams (Union[Hamiltonian, list[Hamiltonian]]): The measurement hamiltonian. n_threads (int): Number of threads for data parallelize. Returns: PQC, A parameterized quantum circuit simulator operator supported by mindspore framework. Examples: >>> from projectq.ops import QubitOperator >>> from mindquantum import Circuit >>> import mindquantum.gate as G >>> encoder_circ = Circuit([G.RX('a').on(0)]) >>> ansatz_circ = Circuit([G.RY('b').on(0)]) >>> circ = encoder_circ + ansatz_circ >>> ham = G.Hamiltonian(QubitOperator('Z0')) >>> pqc = generate_pqc_operator(['a'], ['b'], circ, ham) """ _check_circuit(circuit, 'Circuit') _check_type_or_iterable_type(hams, Hamiltonian, 'Hamiltonian') _check_parameters_of_circuit(encoder_params_names, ansatz_params_names, circuit) if not isinstance(n_threads, int) or n_threads <= 0: raise TypeError( "n_threads requires a positive int, but get {}".format(n_threads)) if circuit.n_qubits == -1: circuit.summary(False) if isinstance(hams, Hamiltonian): hams = [hams] ham_ms_data = {} for ham in hams: for k, v in ham.mindspore_data().items(): if k not in ham_ms_data: ham_ms_data[k] = [v] else: ham_ms_data[k].append(v) return PQC(circuit.n_qubits, encoder_params_names=encoder_params_names, ansatz_params_names=ansatz_params_names, **circuit.mindspore_data(), **ham_ms_data, n_threads=n_threads)