mindquantum.framework.operations 源代码

# 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."""
import mindspore as ms
import numpy as np
from mindspore import context, nn
from mindspore.ops import operations
from mindspore.ops.primitive import constexpr

from mindquantum.core.circuit import Circuit
from mindquantum.core.operators import Hamiltonian
from mindquantum.simulator import GradOpsWrapper, Simulator
from mindquantum.utils.type_value_check import (
    _check_input_type,
    _check_int_type,
    _check_value_should_not_less,
)


@constexpr
def check_enc_input_shape(data, encoder_tensor, enc_len):
    """Check encoder parameter input shape."""
    if not isinstance(data, ms.Tensor):
        raise TypeError(f"Encoder parameter requires a Tensor but get {type(data)}")
    if len(encoder_tensor) != 2 or encoder_tensor[1] != enc_len:
        raise ValueError(
            'Encoder data requires a two dimension Tensor with second'
            + f' dimension should be {enc_len}, but get shape {encoder_tensor}'
        )


@constexpr
def check_ans_input_shape(data, ansatz_tensor, ans_len):
    """Check ansatz input shape."""
    if not isinstance(data, ms.Tensor):
        raise TypeError(f"Ansatz parameter requires a Tensor but get {type(data)}")
    if len(ansatz_tensor) != 1 or ansatz_tensor[0] != ans_len:
        raise ValueError(
            f'Ansatz data requires a one dimension Tensor with shape {ans_len} ' + f'but get {ansatz_tensor}'
        )


@constexpr
def check_state_vector_shape(data, data_shape, qubit_dim):
    """Check state vector shape."""
    if not isinstance(data, ms.Tensor):
        raise TypeError(f"Quantum state vector requires a Tensor but get {type(data)}.")
    if len(data_shape) != 2 or data_shape[1] != qubit_dim:
        raise ValueError(
            'Quantum state vector requires a two dimension Tensor with'
            f' second dimension should be {qubit_dim}, but get shape {data_shape}.'
        )


[文档]class MQOps(nn.Cell): """ MindQuantum operator. A quantum circuit evolution operator that include encoder and ansatz circuit, who return the expectation of given hamiltonian w.r.t final state of parameterized quantum circuit (PQC). This ops is `PYNATIVE_MODE` supported only. Args: expectation_with_grad (GradOpsWrapper): a grad ops that receive encoder data and ansatz data and return the expectation value and gradient value of parameters respect to expectation. Inputs: - **enc_data** (Tensor) - Tensor of encoder data with shape :math:`(N, M)` that you want to encode into quantum state, where :math:`N` means the batch size and :math:`M` means the number of encoder parameters. - **ans_data** (Tensor) - Tensor with shape :math:`N` for ansatz circuit, where :math:`N` means the number of ansatz parameters. Outputs: Tensor, The expectation value of the hamiltonian. Supported Platforms: ``GPU``, ``CPU`` Examples: >>> import numpy as np >>> import mindspore as ms >>> from mindquantum.core.circuit import Circuit >>> from mindquantum.core.operators import Hamiltonian, QubitOperator >>> from mindquantum.framework import MQOps >>> from mindquantum.simulator import Simulator >>> ms.set_context(mode=ms.PYNATIVE_MODE, device_target="CPU") >>> enc = Circuit().ry('a', 0).as_encoder() >>> ans = Circuit().h(0).rx('b', 0) >>> ham = Hamiltonian(QubitOperator('Z0')) >>> sim = Simulator('mqvector', 1) >>> grad_ops = sim.get_expectation_with_grad(ham, enc + ans) >>> enc_data = np.array([[0.1]]) >>> ans_data = np.array([0.2]) >>> f, g_enc, g_ans = grad_ops(enc_data, ans_data) >>> f array([[0.0978434+0.j]]) >>> net = MQOps(grad_ops) >>> f_ms = net(ms.Tensor(enc_data), ms.Tensor(ans_data)) >>> f_ms Tensor(shape=[1, 1], dtype=Float32, value= [[ 9.78433937e-02]]) """ def __init__(self, expectation_with_grad): """Initialize a MQOps object.""" super().__init__() _mode_check(self) _check_grad_ops(expectation_with_grad) self.expectation_with_grad = expectation_with_grad self.shape_ops = operations.Shape() self.g_enc = None self.g_ans = None def extend_repr(self): """Extend string representation.""" return self.expectation_with_grad.str def construct(self, enc_data, ans_data): """Construct an MQOps node.""" check_enc_input_shape(enc_data, self.shape_ops(enc_data), len(self.expectation_with_grad.encoder_params_name)) check_ans_input_shape(ans_data, self.shape_ops(ans_data), len(self.expectation_with_grad.ansatz_params_name)) fval, g_enc, g_ans = self.expectation_with_grad(enc_data.asnumpy(), ans_data.asnumpy()) self.g_enc = np.real(g_enc) self.g_ans = np.real(g_ans) return ms.Tensor(np.real(fval), dtype=ms.float32) def bprop(self, enc_data, ans_data, out, dout): # pylint: disable=unused-argument """Implement the bprop function.""" dout = dout.asnumpy() enc_grad = np.einsum('smp,sm->sp', self.g_enc, dout) ans_grad = np.einsum('smp,sm->p', self.g_ans, dout) return ms.Tensor(enc_grad, dtype=ms.float32), ms.Tensor(ans_grad, dtype=ms.float32)
[文档]class MQN2Ops(nn.Cell): r""" MindQuantum operator. A quantum circuit evolution operator that include encoder and ansatz circuit, who return the square of absolute value of expectation of given hamiltonian w.r.t final state of parameterized quantum circuit (PQC). This ops is `PYNATIVE_MODE` supported only. .. math:: O = \left|\left<\varphi\right| U^\dagger_l H U_r\left|\psi\right>\right|^2 Args: expectation_with_grad (GradOpsWrapper): a grad ops that receive encoder data and ansatz data and return the expectation value and gradient value of parameters respect to expectation. Inputs: - **enc_data** (Tensor) - Tensor of encoder data with shape :math:`(N, M)` that you want to encode into quantum state, where :math:`N` means the batch size and :math:`M` means the number of encoder parameters. - **ans_data** (Tensor) - Tensor with shape :math:`N` for ansatz circuit, where :math:`N` means the number of ansatz parameters. Outputs: Tensor, The square of absolute value of expectation value of the hamiltonian. Supported Platforms: ``GPU``, ``CPU`` Examples: >>> import numpy as np >>> import mindspore as ms >>> from mindquantum.core.circuit import Circuit >>> from mindquantum.core.operators import Hamiltonian, QubitOperator >>> from mindquantum.framework import MQN2Ops >>> from mindquantum.simulator import Simulator >>> ms.set_context(mode=ms.PYNATIVE_MODE, device_target="CPU") >>> enc = Circuit().ry('a', 0).as_encoder() >>> ans = Circuit().h(0).rx('b', 0) >>> ham = Hamiltonian(QubitOperator('Z0')) >>> sim = Simulator('mqvector', 1) >>> grad_ops = sim.get_expectation_with_grad(ham, enc + ans) >>> enc_data = np.array([[0.1]]) >>> ans_data = np.array([0.2]) >>> f, g_enc, g_ans = grad_ops(enc_data, ans_data) >>> np.abs(f) ** 2 array([[0.00957333]]) >>> net = MQN2Ops(grad_ops) >>> f_ms = net(ms.Tensor(enc_data), ms.Tensor(ans_data)) >>> f_ms Tensor(shape=[1, 1], dtype=Float32, value= [[ 9.57333017e-03]]) """ def __init__(self, expectation_with_grad): """Initialize a MQN2Ops object.""" super().__init__() _mode_check(self) _check_grad_ops(expectation_with_grad) self.expectation_with_grad = expectation_with_grad self.shape_ops = operations.Shape() self.f = None # pylint: disable=invalid-name self.g_enc = None self.g_ans = None def extend_repr(self): """Extend string representation.""" return self.expectation_with_grad.str def construct(self, enc_data, ans_data): """Construct an MQN2Ops node.""" check_enc_input_shape(enc_data, self.shape_ops(enc_data), len(self.expectation_with_grad.encoder_params_name)) check_ans_input_shape(ans_data, self.shape_ops(ans_data), len(self.expectation_with_grad.ansatz_params_name)) fval, g_enc, g_ans = self.expectation_with_grad(enc_data.asnumpy(), ans_data.asnumpy()) self.f = fval self.g_enc = g_enc self.g_ans = g_ans return ms.Tensor(np.abs(fval) ** 2, dtype=ms.float32) def bprop(self, enc_data, ans_data, out, dout): # pylint: disable=unused-argument """Implement the bprop function.""" dout = dout.asnumpy() enc_grad = 2 * np.real(np.einsum('smp,sm,sm->sp', self.g_enc, dout, np.conj(self.f))) ans_grad = 2 * np.real(np.einsum('smp,sm,sm->p', self.g_ans, dout, np.conj(self.f))) return ms.Tensor(enc_grad, dtype=ms.float32), ms.Tensor(ans_grad, dtype=ms.float32)
[文档]class MQAnsatzOnlyOps(nn.Cell): r""" MindQuantum operator. A quantum circuit evolution operator that only include ansatz circuit, who return the expectation of given hamiltonian w.r.t final state of parameterized quantum circuit (PQC). This ops is `PYNATIVE_MODE` supported only. Args: expectation_with_grad (GradOpsWrapper): a grad ops that receive encoder data and ansatz data and return the expectation value and gradient value of parameters respect to expectation. Inputs: - **ans_data** (Tensor) - Tensor with shape :math:`N` for ansatz circuit, where :math:`N` means the number of ansatz parameters. Outputs: Tensor, The expectation value of the hamiltonian. Supported Platforms: ``GPU``, ``CPU`` Examples: >>> import numpy as np >>> import mindspore as ms >>> from mindquantum.core.circuit import Circuit >>> from mindquantum.core.operators import Hamiltonian, QubitOperator >>> from mindquantum.framework import MQAnsatzOnlyOps >>> from mindquantum.simulator import Simulator >>> ms.set_context(mode=ms.PYNATIVE_MODE, device_target="CPU") >>> circ = Circuit().ry('a', 0).h(0).rx('b', 0) >>> ham = Hamiltonian(QubitOperator('Z0')) >>> sim = Simulator('mqvector', 1) >>> grad_ops = sim.get_expectation_with_grad(ham, circ) >>> data = np.array([0.1, 0.2]) >>> f, g = grad_ops(data) >>> f array([[0.0978434+0.j]]) >>> net = MQAnsatzOnlyOps(grad_ops) >>> f_ms = net(ms.Tensor(data)) >>> f_ms Tensor(shape=[1], dtype=Float32, value= [ 9.78433937e-02]) """ def __init__(self, expectation_with_grad): """Initialize a MQAnsatzOnlyOps object.""" super().__init__() _mode_check(self) _check_grad_ops(expectation_with_grad) self.expectation_with_grad = expectation_with_grad self.shape_ops = operations.Shape() self.g = None # pylint: disable=invalid-name def extend_repr(self): """Extend string representation.""" return self.expectation_with_grad.str def construct(self, arg): """Construct a MQAnsatzOnlyOps node.""" check_ans_input_shape(arg, self.shape_ops(arg), len(self.expectation_with_grad.ansatz_params_name)) fval, g_ans = self.expectation_with_grad(arg.asnumpy()) self.g = np.real(g_ans[0]) return ms.Tensor(np.real(fval[0]), dtype=ms.float32) def bprop(self, arg, out, dout): # pylint: disable=unused-argument """Implement the bprop function.""" dout = dout.asnumpy() grad = dout @ self.g return ms.Tensor(grad, dtype=ms.float32)
[文档]class MQN2AnsatzOnlyOps(nn.Cell): r""" MindQuantum operator. A quantum circuit evolution operator that only include ansatz circuit, who return the square of absolute value of given hamiltonian w.r.t final state of parameterized quantum circuit (PQC). This ops is `PYNATIVE_MODE` supported only. Args: expectation_with_grad (GradOpsWrapper): a grad ops that receive encoder data and ansatz data and return the expectation value and gradient value of parameters respect to expectation. Inputs: - **ans_data** (Tensor) - Tensor with shape :math:`N` for ansatz circuit, where :math:`N` means the number of ansatz parameters. Outputs: Tensor, The square of absolute value of expectation value of the hamiltonian. Supported Platforms: ``GPU``, ``CPU`` Examples: >>> import numpy as np >>> import mindspore as ms >>> from mindquantum.core.circuit import Circuit >>> from mindquantum.core.operators import Hamiltonian, QubitOperator >>> from mindquantum.framework import MQN2AnsatzOnlyOps >>> from mindquantum.simulator import Simulator >>> ms.set_context(mode=ms.PYNATIVE_MODE, device_target="CPU") >>> circ = Circuit().ry('a', 0).h(0).rx('b', 0) >>> ham = Hamiltonian(QubitOperator('Z0')) >>> sim = Simulator('mqvector', 1) >>> grad_ops = sim.get_expectation_with_grad(ham, circ) >>> data = np.array([0.1, 0.2]) >>> f, g = grad_ops(data) >>> np.abs(f) ** 2 array([[0.00957333]]) >>> net = MQN2AnsatzOnlyOps(grad_ops) >>> f_ms = net(ms.Tensor(data)) >>> f_ms Tensor(shape=[1], dtype=Float32, value= [ 9.57333017e-03]) """ def __init__(self, expectation_with_grad): """Initialize a MQN2AnsatzOnlyOps object.""" super().__init__() _mode_check(self) _check_grad_ops(expectation_with_grad) self.expectation_with_grad = expectation_with_grad self.shape_ops = operations.Shape() # pylint: disable=invalid-name self.f = None self.g = None def extend_repr(self): """Extend string representation.""" return self.expectation_with_grad.str def construct(self, arg): """Construct a MQN2AnsatzOnlyOps node.""" check_ans_input_shape(arg, self.shape_ops(arg), len(self.expectation_with_grad.ansatz_params_name)) fval, g_ans = self.expectation_with_grad(arg.asnumpy()) self.f = fval[0] self.g = g_ans[0] return ms.Tensor(np.abs(fval[0]) ** 2, dtype=ms.float32) def bprop(self, arg, out, dout): # pylint: disable=unused-argument """Implement the bprop function.""" dout = dout.asnumpy() grad = 2 * np.real(np.einsum('m,m,mp->p', np.conj(self.f), dout, self.g)) return ms.Tensor(grad, dtype=ms.float32)
[文档]class MQEncoderOnlyOps(nn.Cell): r""" MindQuantum operator. A quantum circuit evolution operator that only include encoder circuit, who return the square of absolute value of given hamiltonian w.r.t final state of parameterized quantum circuit (PQC). This ops is `PYNATIVE_MODE` supported only. Args: expectation_with_grad (GradOpsWrapper): a grad ops that receive encoder data and ansatz data and return the expectation value and gradient value of parameters respect to expectation. Inputs: - **enc_data** (Tensor) - Tensor of encoder data with shape :math:`(N, M)` that you want to encode into quantum state, where :math:`N` means the batch size and :math:`M` means the number of encoder parameters. Outputs: Tensor, The expectation value of the hamiltonian. Supported Platforms: ``GPU``, ``CPU`` Examples: >>> import numpy as np >>> import mindspore as ms >>> from mindquantum.core.circuit import Circuit >>> from mindquantum.core.operators import Hamiltonian, QubitOperator >>> from mindquantum.framework import MQEncoderOnlyOps >>> from mindquantum.simulator import Simulator >>> ms.set_context(mode=ms.PYNATIVE_MODE, device_target="CPU") >>> circ = Circuit().ry('a', 0).h(0).rx('b', 0).as_encoder() >>> ham = Hamiltonian(QubitOperator('Z0')) >>> sim = Simulator('mqvector', 1) >>> grad_ops = sim.get_expectation_with_grad(ham, circ) >>> data = np.array([[0.1, 0.2], [0.3, 0.4]]) >>> f, g = grad_ops(data) >>> f array([[0.0978434 +0.j], [0.27219214+0.j]]) >>> net = MQEncoderOnlyOps(grad_ops) >>> f_ms = net(ms.Tensor(data)) >>> f_ms Tensor(shape=[2, 1], dtype=Float32, value= [[ 9.78433937e-02], [ 2.72192121e-01]]) """ def __init__(self, expectation_with_grad): """Initialize a MQEncoderOnlyOps object.""" super().__init__() _mode_check(self) _check_grad_ops(expectation_with_grad) self.expectation_with_grad = expectation_with_grad self.shape_ops = operations.Shape() self.g = None # pylint: disable=invalid-name def extend_repr(self): """Extend string representation.""" return self.expectation_with_grad.str def construct(self, arg): """Construct a MQEncoderOnlyOps node.""" check_enc_input_shape(arg, self.shape_ops(arg), len(self.expectation_with_grad.encoder_params_name)) fval, g_enc = self.expectation_with_grad(arg.asnumpy()) self.g = np.real(g_enc) return ms.Tensor(np.real(fval), dtype=ms.float32) def bprop(self, arg, out, dout): # pylint: disable=unused-argument """Implement the bprop function.""" dout = dout.asnumpy() grad = np.einsum('smp,sm->sp', self.g, dout) return ms.Tensor(grad, dtype=ms.float32)
[文档]class MQN2EncoderOnlyOps(nn.Cell): r""" MindQuantum operator. A quantum circuit evolution operator that only include encoder circuit, who return the square of absolute value of given hamiltonian w.r.t final state of parameterized quantum circuit (PQC). This ops is `PYNATIVE_MODE` supported only. Args: expectation_with_grad (GradOpsWrapper): a grad ops that receive encoder data and ansatz data and return the square of absolute value of expectation value and gradient value of parameters respect to expectation. Inputs: - **ans_data** (Tensor) - Tensor with shape :math:`N` for ansatz circuit, where :math:`N` means the number of ansatz parameters. Outputs: Tensor, The square of absolute value of expectation value of the hamiltonian. Supported Platforms: ``GPU``, ``CPU`` Examples: >>> import numpy as np >>> import mindspore as ms >>> from mindquantum.core.circuit import Circuit >>> from mindquantum.core.operators import Hamiltonian, QubitOperator >>> from mindquantum.framework import MQN2EncoderOnlyOps >>> from mindquantum.simulator import Simulator >>> ms.set_context(mode=ms.PYNATIVE_MODE, device_target="CPU") >>> circ = Circuit().ry('a', 0).h(0).rx('b', 0).as_encoder() >>> ham = Hamiltonian(QubitOperator('Z0')) >>> sim = Simulator('mqvector', 1) >>> grad_ops = sim.get_expectation_with_grad(ham, circ) >>> data = np.array([[0.1, 0.2], [0.3, 0.4]]) >>> f, g = grad_ops(data) >>> np.abs(f) ** 2 array([[0.00957333], [0.07408856]]) >>> net = MQN2EncoderOnlyOps(grad_ops) >>> f_ms = net(ms.Tensor(data)) >>> f_ms Tensor(shape=[2, 1], dtype=Float32, value= [[ 9.57333017e-03], [ 7.40885586e-02]]) """ def __init__(self, expectation_with_grad): """Initialize a MQN2EncoderOnlyOps object.""" super().__init__() _mode_check(self) _check_grad_ops(expectation_with_grad) self.expectation_with_grad = expectation_with_grad self.shape_ops = operations.Shape() # pylint: disable=invalid-name self.f = None self.g = None def extend_repr(self): """Extend string representation.""" return self.expectation_with_grad.str def construct(self, arg): """Construct a MQN2EncoderOnlyOps node.""" check_enc_input_shape(arg, self.shape_ops(arg), len(self.expectation_with_grad.encoder_params_name)) fval, g_enc = self.expectation_with_grad(arg.asnumpy()) self.f = fval self.g = g_enc return ms.Tensor(np.abs(fval) ** 2, dtype=ms.float32) def bprop(self, arg, out, dout): # pylint: disable=unused-argument """Implement the bprop function.""" dout = dout.asnumpy() grad = 2 * np.real(np.einsum('smp,sm,sm->sp', self.g, dout, np.conj(self.f))) return ms.Tensor(grad, dtype=ms.float32)
# pylint: disable=too-many-instance-attributes
[文档]class QRamVecOps(nn.Cell): r""" MindQuantum vector state qram operator. A QRam operator with can directly encode classical data into quantum state vector. This ops is `PYNATIVE_MODE` supported only. Note: - For MindSpore with version less than 2.0.0, complex tensor as neural network cell input is not supported, so we should split quantum state to real and image part, and use them as input tensor. This may change when MindSpore upgrade. - Currently, we can not compute the gradient of the measurement result with respect to each quantum amplitude. Args: hams (Union[:class:`~.core.operators.Hamiltonian`, List[:class:`~.core.operators.Hamiltonian`]]): A :class:`~.core.operators.Hamiltonian` or a list of :class:`~.core.operators.Hamiltonian` that need to get expectation. circ (:class:`~.core.circuit.Circuit`): The parameterized quantum circuit. sim (:class:`~.simulator.Simulator`): The simulator to do simulation. n_thread (int): The parallel thread for evaluate a batch of initial state. If ``None``, evolution will run in single thread. Default: ``None``. Inputs: - **qs_r** (Tensor) - The real part of quantum state with shape :math:`(N, M)`, where :math:`N` is batch size and :math:`M` is the length of quantum state vector. - **qs_i** (Tensor) - The image part of quantum state with shape :math:`(N, M)`, where :math:`N` is batch size and :math:`M` is the length of quantum state vector. - **ans_data** (Tensor) - Tensor with shape :math:`N` for ansatz circuit, where :math:`N` means the number of ansatz parameters. Outputs: Tensor, The expectation value of the hamiltonian. Supported Platforms: ``GPU``, ``CPU`` Examples: >>> import numpy as np >>> import mindspore as ms >>> from mindquantum.core.circuit import Circuit >>> from mindquantum.core.operators import Hamiltonian, QubitOperator >>> from mindquantum.framework import QRamVecOps >>> from mindquantum.simulator import Simulator >>> from mindquantum.utils import random_state >>> ms.set_context(mode=ms.PYNATIVE_MODE, device_target="CPU") >>> circ = Circuit().ry('a', 0).h(0).rx('b', 0).as_ansatz() >>> ham = Hamiltonian(QubitOperator('Z0')) >>> sim = Simulator('mqvector', 1) >>> grad_ops = sim.get_expectation_with_grad(ham, circ) >>> qs = random_state((3, 2), norm_axis=1, seed=42) >>> qs_r, qs_i = ms.Tensor(qs.real), ms.Tensor(qs.imag) >>> ansatz_data = np.array([1.0, 2.0]) >>> net = QRamVecOps(ham, circ, sim) >>> f_ms = net(qs_r, qs_i, ms.Tensor(ansatz_data)) >>> f_ms Tensor(shape=[3, 1], dtype=Float32, value= [[-7.97555372e-02], [-3.92564088e-01], [ 4.03987877e-02]]) >>> for i in qs: ... sim.set_qs(i) ... f, g = grad_ops(ansatz_data) ... print(f.real[0, 0]) -0.07975553553458492 -0.39256407750502403 0.04039878594782581 """ def __init__(self, hams, circ, sim, n_thread=None): """Initialize a qram operator.""" super().__init__() _mode_check(self) if isinstance(hams, Hamiltonian): hams = [hams] for i in hams: _check_input_type('hams', Hamiltonian, i) if n_thread is None: n_thread = 1 _check_input_type('circ', Circuit, circ) _check_input_type('sim', Simulator, sim) _check_int_type('n_thread', n_thread) _check_value_should_not_less('n_thread', 1, n_thread) if circ.encoder_params_name: raise ValueError("circ can not have encoder parameters.") self.hams = hams self.circ = circ self.sim = sim.copy() self.n_thread = n_thread self.shape_ops = operations.Shape() self.g_ans = None self.g_enc = None self.dim = 1 << self.sim.n_qubits def extend_repr(self): """Extend string representation.""" grad_str = f'{self.sim.n_qubits} qubit' + ('' if self.sim.n_qubits == 1 else 's') grad_str += f' {self.sim.backend.name} VQA Operator' return grad_str def construct(self, qs_r, qs_i, ans_data): """Construct an MQOps node.""" check_state_vector_shape(qs_r, self.shape_ops(qs_r), self.dim) check_state_vector_shape(qs_i, self.shape_ops(qs_i), self.dim) check_ans_input_shape(ans_data, self.shape_ops(ans_data), len(self.circ.params_name)) enc_data = qs_r.asnumpy() + qs_i.asnumpy() * 1j f = self.sim.backend.sim.qram_expectation_with_grad( [i.get_cpp_obj() for i in self.hams], self.circ.get_cpp_obj(), self.circ.get_cpp_obj(True), enc_data, ans_data.asnumpy(), self.circ.params_name, self.n_thread, len(self.hams), ) f = np.array(f) f, g = f[:, :, 0], f[:, :, 1:] self.g_ans = np.real(g) self.g_enc = ms.Tensor(np.zeros(shape=enc_data.shape), dtype=ms.float32) return ms.Tensor(np.real(f), dtype=ms.float32) def bprop(self, enc_data_r, enc_data_i, ans_data, out, dout): # pylint: disable=unused-argument,too-many-arguments """Implement the bprop function.""" dout = dout.asnumpy() ans_grad = np.einsum('smp,sm->p', self.g_ans, dout) return self.g_enc, self.g_enc, ms.Tensor(ans_grad, dtype=ms.float32)
def _mode_check(self): if context.get_context('mode') != context.PYNATIVE_MODE: raise RuntimeError( f'{self.__class__} is `PYNATIVE_MODE` supported only. Run command below to set context\n' 'import mindspore as ms\n' 'ms.context.set_context(mode=ms.context.PYNATIVE_MODE, device_target="CPU")' ) def _check_grad_ops(expectation_with_grad): if not isinstance(expectation_with_grad, GradOpsWrapper): raise TypeError(f'expectation_with_grad requires a GradOpsWrapper, but get {type(expectation_with_grad)}')