Source code for mindquantum.nn.mindquantumlayer

# 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.
# ============================================================================
"""Basic mindquanutm neural layer."""

import numpy as np
from mindspore import Tensor
import mindspore.nn as nn
from mindspore.common.parameter import Parameter
from mindspore.common.initializer import initializer
from .pqc import generate_pqc_operator
from .evolution import generate_evolution_operator


[docs]class MindQuantumLayer(nn.Cell): """ A trainable Mindquantum layer. A mindquantum layer simulate a parameterized quantum circuit and get the measurement result. The quantum circuit is construct by a encode circuit and a trainable ansatz circuit. The encode circuit will encode classical data into quantum state, and the trainable ansatz circuit apply on the quantum state. Args: encoder_params_names (list[str]): Parameters names of encoder circuit. The order of this parameters is the same as the order of data passed in construct. ansatz_params_names (list[str]): Parameters names of ansatz circuit. The order of this parameters is the same as the order of trainable parameters. circuit (Circuit): Quantum circuit construct by encode circuit and ansatz circuit. hams (list[Hamiltonian]): Hamiltonian or a list of Hamiltonian for measurement. weight_init (Union[Tensor, str, Initializer, numbers.Number]): The trainable weight_init parameter. The dtype is same as input x. The values of str refer to the function `initializer`. Default: 'normal'. n_threads (int): Number of threads for data parallel. Default: 1. Inputs: - **input** (Tensor) - Tensor of shape :math:`(N, E_{in})`, where :math:`N` is batch size, :math:`E_{in}` is the number of parameters in encoder circuit. Outputs: Tensor of shape :math:`(N, H_{out})`, where :math:`H_{out}` is the number of hamiltonians. Supported Platforms: ``CPU`` Examples: >>> from projectq.ops import QubitOperator >>> from mindquantum.nn import MindQuantumLayer >>> from mindquantum import Circuit, Hamiltonian >>> import mindquantum.gate as G >>> encoder_circ = Circuit([G.RX('a').on(0)]) >>> encoder_circ.no_grad() >>> ansatz = Circuit([G.RY('b').on(0)]) >>> ham = Hamiltonian(QubitOperator('Z0')) >>> net = MindQuantumLayer(['a'], ['b'], encoder_circ + ansatz, ham) >>> res = net(Tensor(np.array([[1.0]]).astype(np.float32))) >>> res.asnumpy() array([[0.54030216]], dtype=float32) """ def __init__(self, encoder_params_names, ansatz_params_names, circuit, hams, weight_init='normal', n_threads=1): super(MindQuantumLayer, self).__init__() self.circuit = circuit self.hams = hams self.encoder_params_names = encoder_params_names self.ansatz_params_names = ansatz_params_names self.weight = Parameter(initializer(weight_init, len(ansatz_params_names)), name="weight") self.pqc = generate_pqc_operator(encoder_params_names, ansatz_params_names, circuit, hams, n_threads=n_threads)
[docs] def final_state(self, encoder_data, ansatz_data=None, circuit=None, hams=None): """ Get the quantum state after evolution. Args: encoder_data (Tensor): A one dimension tensor for encoder circuit. ansatz_data (Tensor): A one dimension tensor for ansatz circuit. If ansatz_data is None, then the traind parameter will be used. Default: None. circuit (Circuit): Quantum circuit construct by encode circuit and ansatz circuit. If None, the circuit for train will be used. Default: None. hams (list[Hamiltonian]): Hamiltonian or a list of Hamiltonian for measurement. If None, the hamiltonians for train will be used. Default: None. Returns: numpy.ndarray: the final quantum state. """ if circuit is None: circuit = self.circuit if hams is None: hams = self.hams if ansatz_data is None: ansatz_data = self.weight if len(encoder_data.shape) != 1: raise ValueError("Except a one dimension tensor for encoder_data!") data = np.array([]) data = np.append(data, encoder_data.asnumpy()) data = np.append(data, ansatz_data.asnumpy()) data = Tensor(data.astype(np.float32)) param_names = [] param_names.extend(self.encoder_params_names) param_names.extend(self.ansatz_params_names) evol = generate_evolution_operator(param_names, circuit, hams) state = evol(data) state = state.asnumpy() state = state[:, 0] + state[:, 1] * 1j return state
def construct(self, x): x, _, _ = self.pqc(x, self.weight) return x