circuit.py 47.7 KB
Newer Older
Q
Quleaf 已提交
1
# Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.
Q
Quleaf 已提交
2 3 4 5 6 7 8 9 10 11 12 13 14
#
# 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.

Q
Quleaf 已提交
15 16 17 18 19
import gc
import math
from functools import reduce
from collections import defaultdict
import numpy as np
Q
Quleaf 已提交
20
from numpy import binary_repr, eye, identity
Q
Quleaf 已提交
21 22 23
import matplotlib.pyplot as plt

import paddle
Q
Quleaf 已提交
24
from paddle.complex import kron as pp_kron
Q
Quleaf 已提交
25 26 27
from paddle.complex import reshape as complex_reshape
from paddle.complex import matmul, transpose, trace
from paddle.complex.tensor.math import elementwise_mul
Q
Quleaf 已提交
28

Q
Quleaf 已提交
29
import paddle.fluid as fluid
Q
Quleaf 已提交
30
from paddle.fluid import dygraph
Q
Quleaf 已提交
31 32
from paddle.fluid.layers import reshape, cast, eye, zeros
from paddle.fluid.framework import ComplexVariable
Q
Quleaf 已提交
33

Q
Quleaf 已提交
34
from paddle_quantum.simulator import StateTranfer, init_state_gen, measure_state
Q
Quleaf 已提交
35
from paddle_quantum.utils import dagger, pauli_str_to_matrix
Q
Quleaf 已提交
36 37
from paddle_quantum.intrinsic import *
from paddle_quantum.state import density_op
Q
Quleaf 已提交
38 39 40

__all__ = [
    "UAnsatz",
Q
Quleaf 已提交
41
    "H_prob"
Q
Quleaf 已提交
42 43 44
]


Q
Quleaf 已提交
45
class UAnsatz:
Q
Quleaf 已提交
46
    r"""基于 PaddlePaddle 的动态图机制实现量子线路的 ``class`` 。
Q
Quleaf 已提交
47 48

    用户可以通过实例化该 ``class`` 来搭建自己的量子线路。
Q
Quleaf 已提交
49

Q
Quleaf 已提交
50 51
    Attributes:
        n (int): 该线路的量子比特数
Q
Quleaf 已提交
52 53
    """

Q
Quleaf 已提交
54
    def __init__(self, n):
Q
Quleaf 已提交
55
        r"""UAnsatz 的构造函数,用于实例化一个 UAnsatz 对象
Q
Quleaf 已提交
56

Q
Quleaf 已提交
57 58
        Args:
            n (int): 该线路的量子比特数
Q
Quleaf 已提交
59

Q
Quleaf 已提交
60 61 62 63 64 65
        """
        self.n = n
        self.__state = None
        self.__run_state = ''
        # Record history of adding gates to the circuit
        self.__history = []
Q
Quleaf 已提交
66

Q
Quleaf 已提交
67 68
    def run_state_vector(self, input_state=None, store_state=True):
        r"""运行当前的量子线路,输入输出的形式为态矢量。
Q
Quleaf 已提交
69

Q
Quleaf 已提交
70 71 72
        Args:
            input_state (ComplexVariable, optional): 输入的态矢量,默认为 :math:`|00...0\rangle`
            store_state (Bool, optional): 是否存储输出的态矢量,默认为 ``True`` ,即存储
Q
Quleaf 已提交
73

Q
Quleaf 已提交
74 75
        Returns:
            ComplexVariable: 量子线路输出的态矢量
Q
Quleaf 已提交
76

Q
Quleaf 已提交
77
        代码示例:
Q
Quleaf 已提交
78

Q
Quleaf 已提交
79
        .. code-block:: python
Q
Quleaf 已提交
80

Q
Quleaf 已提交
81 82 83 84 85 86 87 88
            import numpy as np
            from paddle import fluid
            from paddle_quantum.circuit import UAnsatz
            n = 2
            theta = np.ones(3)
            input_state = np.ones(2**n)+0j
            input_state = input_state / np.linalg.norm(input_state)
            with fluid.dygraph.guard():
Q
Quleaf 已提交
89

Q
Quleaf 已提交
90 91 92 93 94 95 96
                input_state_var = fluid.dygraph.to_variable(input_state)
                theta = fluid.dygraph.to_variable(theta)
                cir = UAnsatz(n)
                cir.rx(theta[0], 0)
                cir.ry(theta[1], 1)
                cir.rz(theta[2], 1)
                vec = cir.run_state_vector(input_state_var).numpy()
Q
Quleaf 已提交
97
                print(f"The output state vector is {vec}")
Q
Quleaf 已提交
98

Q
Quleaf 已提交
99
        ::
Q
Quleaf 已提交
100

Q
Quleaf 已提交
101
            The output state vector is [0.17470783-0.09544332j 0.59544332+0.32529217j 0.17470783-0.09544332j 0.59544332+0.32529217j]
Q
Quleaf 已提交
102 103 104 105 106
        """
        state = init_state_gen(self.n, 0) if input_state is None else input_state
        old_shape = state.shape
        assert reduce(lambda x, y: x * y, old_shape) == 2 ** self.n, 'The length of the input vector is not right'
        state = complex_reshape(state, (2 ** self.n,))
Q
Quleaf 已提交
107

Q
Quleaf 已提交
108 109 110
        state_conj = ComplexVariable(state.real, -state.imag)
        assert fluid.layers.abs(paddle.complex.sum(elementwise_mul(state_conj, state)).real - 1) < 1e-8, \
            'Input state is not a normalized vector'
Q
Quleaf 已提交
111

Q
Quleaf 已提交
112 113 114 115 116
        for history_ele in self.__history:
            if history_ele[0] == 'u':
                state = StateTranfer(state, 'u', history_ele[1], history_ele[2])
            elif history_ele[0] in {'x', 'y', 'z', 'h'}:
                state = StateTranfer(state, history_ele[0], history_ele[1], params=history_ele[2])
Q
Quleaf 已提交
117 118
            elif history_ele[0] == 'SWAP':
                state = StateTranfer(state, 'SWAP', history_ele[1])
Q
Quleaf 已提交
119 120 121 122 123 124 125 126 127 128 129 130
            elif history_ele[0] == 'CNOT':
                state = StateTranfer(state, 'CNOT', history_ele[1])

        if store_state:
            self.__state = state
            # Add info about which function user called
            self.__run_state = 'state_vector'

        return complex_reshape(state, old_shape)

    def run_density_matrix(self, input_state=None, store_state=True):
        r"""运行当前的量子线路,输入输出的形式为密度矩阵。
Q
Quleaf 已提交
131

Q
Quleaf 已提交
132 133 134
        Args:
            input_state (ComplexVariable, optional): 输入的密度矩阵,默认为 :math:`|00...0\rangle \langle00...0|`
            store_state (bool, optional): 是否存储输出的密度矩阵,默认为 ``True`` ,即存储
Q
Quleaf 已提交
135

Q
Quleaf 已提交
136 137 138 139 140 141
        Returns:
            ComplexVariable: 量子线路输出的密度矩阵

        代码示例:

        .. code-block:: python
Q
Quleaf 已提交
142

Q
Quleaf 已提交
143 144 145 146 147 148 149 150
            import numpy as np
            from paddle import fluid
            from paddle_quantum.circuit import UAnsatz
            n = 1
            theta = np.ones(3)
            input_state = np.diag(np.arange(2**n))+0j
            input_state = input_state / np.trace(input_state)
            with fluid.dygraph.guard():
Q
Quleaf 已提交
151

Q
Quleaf 已提交
152 153 154 155 156 157 158
                input_state_var = fluid.dygraph.to_variable(input_state)
                theta = fluid.dygraph.to_variable(theta)
                cir = UAnsatz(n)
                cir.rx(theta[0], 0)
                cir.ry(theta[1], 0)
                cir.rz(theta[2], 0)
                density = cir.run_density_matrix(input_state_var).numpy()
Q
Quleaf 已提交
159
                print(f"The output density matrix is\n{density}")
Q
Quleaf 已提交
160 161 162

        ::

Q
Quleaf 已提交
163
            The output density matrix is
Q
Quleaf 已提交
164 165 166 167
            [[ 0.35403671+0.j         -0.47686058-0.03603751j]
            [-0.47686058+0.03603751j  0.64596329+0.j        ]]
        """
        state = dygraph.to_variable(density_op(self.n)) if input_state is None else input_state
Q
Quleaf 已提交
168

Q
Quleaf 已提交
169
        assert state.real.shape == [2 ** self.n, 2 ** self.n], "The dimension is not right"
Q
Quleaf 已提交
170
        state = matmul(self.U, matmul(state, dagger(self.U)))
Q
Quleaf 已提交
171

Q
Quleaf 已提交
172 173 174 175 176 177 178 179 180 181
        if store_state:
            self.__state = state
            # Add info about which function user called
            self.__run_state = 'density_matrix'

        return state

    @property
    def U(self):
        r"""量子线路的酉矩阵形式。
Q
Quleaf 已提交
182

Q
Quleaf 已提交
183 184 185 186 187 188
        Returns:
            ComplexVariable: 当前线路的酉矩阵表示

        代码示例:

        .. code-block:: python
Q
Quleaf 已提交
189

Q
Quleaf 已提交
190 191 192 193 194 195 196 197
            from paddle import fluid
            from paddle_quantum.circuit import UAnsatz
            n = 2
            with fluid.dygraph.guard():
                cir = UAnsatz(2)
                cir.h(0)
                cir.cnot([0, 1])
                matrix = cir.U
Q
Quleaf 已提交
198
                print("The unitary matrix of the circuit for Bell state preparation is\n",matrix.numpy())
Q
Quleaf 已提交
199 200 201

        ::

Q
Quleaf 已提交
202
            The unitary matrix of the circuit for Bell state preparation is
Q
Quleaf 已提交
203 204 205 206
            [[ 0.70710678+0.j  0.        +0.j  0.70710678+0.j  0.        +0.j]
            [ 0.        +0.j  0.70710678+0.j  0.        +0.j  0.70710678+0.j]
            [ 0.        +0.j  0.70710678+0.j  0.        +0.j -0.70710678+0.j]
            [ 0.70710678+0.j  0.        +0.j -0.70710678+0.j  0.        +0.j]]
Q
Quleaf 已提交
207
        """
Q
Quleaf 已提交
208 209 210 211
        state = ComplexVariable(eye(2 ** self.n, dtype='float64'), zeros([2 ** self.n, 2 ** self.n], dtype='float64'))
        shape = (2 ** self.n, 2 ** self.n)
        num_ele = reduce(lambda x, y: x * y, shape)
        state = ComplexVariable(reshape(state.real, [num_ele]), reshape(state.imag, [num_ele]))
Q
Quleaf 已提交
212

Q
Quleaf 已提交
213 214 215 216 217
        for history_ele in self.__history:
            if history_ele[0] == 'u':
                state = StateTranfer(state, 'u', history_ele[1], history_ele[2])
            elif history_ele[0] in {'x', 'y', 'z', 'h'}:
                state = StateTranfer(state, history_ele[0], history_ele[1], params=history_ele[2])
Q
Quleaf 已提交
218 219
            elif history_ele[0] == 'SWAP':
                state = StateTranfer(state, 'SWAP', history_ele[1])
Q
Quleaf 已提交
220 221
            elif history_ele[0] == 'CNOT':
                state = StateTranfer(state, 'CNOT', history_ele[1])
Q
Quleaf 已提交
222

Q
Quleaf 已提交
223
        return ComplexVariable(reshape(state.real, shape), reshape(state.imag, shape))
Q
Quleaf 已提交
224 225

    """
Q
Quleaf 已提交
226
    Common Gates
Q
Quleaf 已提交
227 228
    """

Q
Quleaf 已提交
229
    def rx(self, theta, which_qubit):
Q
Quleaf 已提交
230 231
        r"""添加关于 x 轴的单量子比特旋转门。

Q
Quleaf 已提交
232
        其矩阵形式为:
Q
Quleaf 已提交
233

Q
Quleaf 已提交
234
        .. math::
Q
Quleaf 已提交
235

Q
Quleaf 已提交
236
            \begin{bmatrix} \cos\frac{\theta}{2} & -i\sin\frac{\theta}{2} \\ -i\sin\frac{\theta}{2} & \cos\frac{\theta}{2} \end{bmatrix}
Q
Quleaf 已提交
237

Q
Quleaf 已提交
238 239
        Args:
            theta (Variable): 旋转角度
Q
Quleaf 已提交
240 241
            which_qubit (int): 作用在的 qubit 的编号,其值应该在 :math:`[0, n)` 范围内, :math:`n` 为该量子线路的量子比特数

Q
Quleaf 已提交
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
        ..  code-block:: python

            import numpy as np
            from paddle import fluid
            from paddle_quantum.circuit import UAnsatz
            theta = np.array([np.pi], np.float64)
            with fluid.dygraph.guard():
                theta = fluid.dygraph.to_variable(theta)
                num_qubits = 1
                cir = UAnsatz(num_qubits)
                which_qubit = 0
                cir.rx(theta[0], which_qubit)
        """
        assert 0 <= which_qubit < self.n, "the qubit should >= 0 and < n(the number of qubit)"
        self.__history.append(['u', [which_qubit], [theta,
                                                    dygraph.to_variable(np.array([-math.pi / 2])),
                                                    dygraph.to_variable(np.array([math.pi / 2]))]])

    def ry(self, theta, which_qubit):
Q
Quleaf 已提交
261
        r"""添加关于 y 轴的单量子比特旋转门。
Q
Quleaf 已提交
262 263

        其矩阵形式为:
Q
Quleaf 已提交
264

Q
Quleaf 已提交
265
        .. math::
Q
Quleaf 已提交
266

Q
Quleaf 已提交
267 268 269 270
            \begin{bmatrix} \cos\frac{\theta}{2} & -\sin\frac{\theta}{2} \\ \sin\frac{\theta}{2} & \cos\frac{\theta}{2} \end{bmatrix}

        Args:
            theta (Variable): 旋转角度
Q
Quleaf 已提交
271
            which_qubit (int): 作用在的 qubit 的编号,其值应该在 :math:`[0, n)` 范围内, :math:`n` 为该量子线路的量子比特数
Q
Quleaf 已提交
272 273

        ..  code-block:: python
Q
Quleaf 已提交
274

Q
Quleaf 已提交
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
            import numpy as np
            from paddle import fluid
            from paddle_quantum.circuit import UAnsatz
            theta = np.array([np.pi], np.float64)
            with fluid.dygraph.guard():
                theta = fluid.dygraph.to_variable(theta)
                num_qubits = 1
                cir = UAnsatz(num_qubits)
                which_qubit = 0
                cir.ry(theta[0], which_qubit)
        """
        assert 0 <= which_qubit < self.n, "the qubit should >= 0 and < n(the number of qubit)"
        self.__history.append(['u', [which_qubit], [theta,
                                                    dygraph.to_variable(np.array([0.0])),
                                                    dygraph.to_variable(np.array([0.0]))]])

    def rz(self, theta, which_qubit):
Q
Quleaf 已提交
292 293
        r"""添加关于 z 轴的单量子比特旋转门。

Q
Quleaf 已提交
294
        其矩阵形式为:
Q
Quleaf 已提交
295

Q
Quleaf 已提交
296
        .. math::
Q
Quleaf 已提交
297

Q
Quleaf 已提交
298
            \begin{bmatrix} 1 & 0 \\ 0 & e^{i\theta} \end{bmatrix}
Q
Quleaf 已提交
299

Q
Quleaf 已提交
300 301
        Args:
            theta (Variable): 旋转角度
Q
Quleaf 已提交
302 303
            which_qubit (int): 作用在的 qubit 的编号,其值应该在 :math:`[0, n)` 范围内, :math:`n` 为该量子线路的量子比特数

Q
Quleaf 已提交
304
        ..  code-block:: python
Q
Quleaf 已提交
305

Q
Quleaf 已提交
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
            import numpy as np
            from paddle import fluid
            from paddle_quantum.circuit import UAnsatz
            theta = np.array([np.pi], np.float64)
            with fluid.dygraph.guard():
                theta = fluid.dygraph.to_variable(theta)
                num_qubits = 1
                cir = UAnsatz(num_qubits)
                which_qubit = 0
                cir.ry(theta[0], which_qubit)
        """
        assert 0 <= which_qubit < self.n, "the qubit should >= 0 and < n(the number of qubit)"
        self.__history.append(['u', [which_qubit], [dygraph.to_variable(np.array([0.0])),
                                                    dygraph.to_variable(np.array([0.0])),
                                                    theta]])

    def cnot(self, control):
Q
Quleaf 已提交
323 324 325 326
        r"""添加一个 CNOT 门。

        对于 2 量子比特的量子线路,当 ``control`` 为 ``[0, 1]`` 时,其矩阵形式为:

Q
Quleaf 已提交
327
        .. math::
Q
Quleaf 已提交
328

Q
Quleaf 已提交
329 330 331 332
            \begin{align}
            CNOT &=|0\rangle \langle 0|\otimes I + |1 \rangle \langle 1|\otimes X\\
            &=\begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0 \end{bmatrix}
            \end{align}
Q
Quleaf 已提交
333

Q
Quleaf 已提交
334
        Args:
Q
Quleaf 已提交
335
            control (list): 作用在的 qubit 的编号,``control[0]`` 为控制位,``control[1]`` 为目标位,其值都应该在 :math:`[0, n)` 范围内, :math:`n` 为该量子线路的量子比特数
Q
Quleaf 已提交
336 337

        ..  code-block:: python
Q
Quleaf 已提交
338

Q
Quleaf 已提交
339 340 341 342 343 344 345 346 347 348 349 350 351
            import numpy as np
            from paddle import fluid
            from paddle_quantum.circuit import UAnsatz
            num_qubits = 2
            with fluid.dygraph.guard():
                cir = UAnsatz(num_qubits)
                cir.cnot([0, 1])
        """
        assert 0 <= control[0] < self.n and 0 <= control[1] < self.n,\
            "the qubit should >= 0 and < n(the number of qubit)"
        assert control[0] != control[1], "the control qubit is the same as the target qubit"
        self.__history.append(['CNOT', control])

Q
Quleaf 已提交
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
    def swap(self, control):
        r"""添加一个 SWAP 门。

        其矩阵形式为:

        .. math::

            \begin{align}
            SWAP &=\begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}
            \end{align}

        Args:
            control (list): 作用在的 qubit 的编号,``control[0]`` 和``control[1]`` 是想要交换的位,其值都应该在 :math:`[0, n)`范围内, :math:`n` 为该量子线路的量子比特数

        ..  code-block:: python

            import numpy as np
            from paddle import fluid
            from paddle_quantum.circuit import UAnsatz
            num_qubits = 2
            with fluid.dygraph.guard():
                cir = UAnsatz(num_qubits)
                cir.swap([0, 1])
        """
        assert 0 <= control[0] < self.n and 0 <= control[1] < self.n, "the qubit should >= 0 and < n(the number of qubit)"
        assert control[0] != control[1], "the indices needed to be swapped should not be the same"
        self.__history.append(['SWAP', control])

Q
Quleaf 已提交
380
    def x(self, which_qubit):
Q
Quleaf 已提交
381 382
        r"""添加单量子比特 X 门。

Q
Quleaf 已提交
383
        其矩阵形式为:
Q
Quleaf 已提交
384

Q
Quleaf 已提交
385
        .. math::
Q
Quleaf 已提交
386

Q
Quleaf 已提交
387
            \begin{bmatrix} 0 & 1 \\ 1 & 0 \end{bmatrix}
Q
Quleaf 已提交
388

Q
Quleaf 已提交
389
        Args:
Q
Quleaf 已提交
390
            which_qubit (int): 作用在的qubit的编号,其值应该在 :math:`[0, n)` 范围内, :math:`n` 为该量子线路的量子比特数
Q
Quleaf 已提交
391

Q
Quleaf 已提交
392
        .. code-block:: python
Q
Quleaf 已提交
393

Q
Quleaf 已提交
394 395 396 397 398 399 400 401 402 403 404 405
            from paddle import fluid
            from paddle_quantum.circuit import UAnsatz
            with fluid.dygraph.guard():
                num_qubits = 1
                cir = UAnsatz(num_qubits)
                which_qubit = 0
                cir.x(which_qubit)
        """
        assert 0 <= which_qubit < self.n, "the qubit should >= 0 and < n(the number of qubit)"
        self.__history.append(['x', [which_qubit], None])

    def y(self, which_qubit):
Q
Quleaf 已提交
406 407
        r"""添加单量子比特 Y 门。

Q
Quleaf 已提交
408
        其矩阵形式为:
Q
Quleaf 已提交
409

Q
Quleaf 已提交
410
        .. math::
Q
Quleaf 已提交
411

Q
Quleaf 已提交
412
            \begin{bmatrix} 0 & -i \\ i & 0 \end{bmatrix}
Q
Quleaf 已提交
413

Q
Quleaf 已提交
414
        Args:
Q
Quleaf 已提交
415 416
            which_qubit (int): 作用在的 qubit 的编号,其值应该在 :math:`[0, n)` 范围内, :math:`n` 为该量子线路的量子比特数

Q
Quleaf 已提交
417
        .. code-block:: python
Q
Quleaf 已提交
418

Q
Quleaf 已提交
419 420 421 422 423 424 425 426 427 428 429 430
            from paddle import fluid
            from paddle_quantum.circuit import UAnsatz
            with fluid.dygraph.guard():
                num_qubits = 1
                cir = UAnsatz(num_qubits)
                which_qubit = 0
                cir.y(which_qubit)
        """
        assert 0 <= which_qubit < self.n, "the qubit should >= 0 and < n(the number of qubit)"
        self.__history.append(['y', [which_qubit], None])

    def z(self, which_qubit):
Q
Quleaf 已提交
431 432
        r"""添加单量子比特 Z 门。

Q
Quleaf 已提交
433
        其矩阵形式为:
Q
Quleaf 已提交
434

Q
Quleaf 已提交
435
        .. math::
Q
Quleaf 已提交
436

Q
Quleaf 已提交
437
            \begin{bmatrix} 1 & 0 \\ 0 & -1 \end{bmatrix}
Q
Quleaf 已提交
438

Q
Quleaf 已提交
439
        Args:
Q
Quleaf 已提交
440
            which_qubit (int): 作用在的qubit的编号,其值应该在 :math:`[0, n)` 范围内, :math:`n` 为该量子线路的量子比特数
Q
Quleaf 已提交
441

Q
Quleaf 已提交
442
        .. code-block:: python
Q
Quleaf 已提交
443

Q
Quleaf 已提交
444 445 446 447 448 449 450 451 452 453 454 455
            from paddle import fluid
            from paddle_quantum.circuit import UAnsatz
            with fluid.dygraph.guard():
                num_qubits = 1
                cir = UAnsatz(num_qubits)
                which_qubit = 0
                cir.z(which_qubit)
        """
        assert 0 <= which_qubit < self.n, "the qubit should >= 0 and < n(the number of qubit)"
        self.__history.append(['z', [which_qubit], None])

    def h(self, which_qubit):
Q
Quleaf 已提交
456
        r"""添加一个单量子比特的 Hadamard 门。
Q
Quleaf 已提交
457

Q
Quleaf 已提交
458
        其矩阵形式为:
Q
Quleaf 已提交
459 460

        .. math::
Q
Quleaf 已提交
461

Q
Quleaf 已提交
462 463 464
            H = \frac{1}{\sqrt{2}}\begin{bmatrix} 1&1\\1&-1 \end{bmatrix}

        Args:
Q
Quleaf 已提交
465
            which_qubit (int): 作用在的 qubit 的编号,其值应该在 :math:`[0, n)` 范围内, :math:`n` 为该量子线路的量子比特数
Q
Quleaf 已提交
466 467 468 469 470
        """
        assert 0 <= which_qubit < self.n, "the qubit should >= 0 and < n(the number of qubit)"
        self.__history.append(['h', [which_qubit], None])

    def s(self, which_qubit):
Q
Quleaf 已提交
471
        r"""添加一个单量子比特的 S 门。
Q
Quleaf 已提交
472

Q
Quleaf 已提交
473
        其矩阵形式为:
Q
Quleaf 已提交
474 475

        .. math::
Q
Quleaf 已提交
476

Q
Quleaf 已提交
477 478 479
            S = \begin{bmatrix} 1&0\\0&i \end{bmatrix}

        Args:
Q
Quleaf 已提交
480
            which_qubit (int): 作用在的 qubit 的编号,其值应该在 :math:`[0, n)` 范围内, :math:`n` 为该量子线路的量子比特数
Q
Quleaf 已提交
481 482 483 484 485 486 487
        """
        assert 0 <= which_qubit < self.n, "the qubit should >= 0 and < n(the number of qubit)"
        self.__history.append(['u', [which_qubit], [dygraph.to_variable(np.array([0.0])),
                                                    dygraph.to_variable(np.array([0.0])),
                                                    dygraph.to_variable(np.array([math.pi / 2]))]])

    def t(self, which_qubit):
Q
Quleaf 已提交
488
        r"""添加一个单量子比特的 T 门。
Q
Quleaf 已提交
489

Q
Quleaf 已提交
490
        其矩阵形式为:
Q
Quleaf 已提交
491 492 493 494

        .. math::

            T = \begin{bmatrix} 1&0\\0&e^\frac{i\pi}{4} \end{bmatrix}
Q
Quleaf 已提交
495

Q
Quleaf 已提交
496
        Args:
Q
Quleaf 已提交
497
            which_qubit (int): 作用在的 qubit 的编号,其值应该在 :math:`[0, n)` 范围内, :math:`n` 为该量子线路的量子比特数
Q
Quleaf 已提交
498 499 500 501 502 503 504 505 506
        """
        assert 0 <= which_qubit < self.n, "the qubit should >= 0 and < n(the number of qubit)"
        self.__history.append(['u', [which_qubit], [dygraph.to_variable(np.array([0.0])),
                                                    dygraph.to_variable(np.array([0.0])),
                                                    dygraph.to_variable(np.array([math.pi / 4]))]])

    def u3(self, theta, phi, lam, which_qubit):
        r"""添加一个单量子比特的旋转门。

Q
Quleaf 已提交
507
        其矩阵形式为:
Q
Quleaf 已提交
508

Q
Quleaf 已提交
509
        .. math::
Q
Quleaf 已提交
510

Q
Quleaf 已提交
511 512 513 514 515 516 517 518 519 520 521 522
            \begin{align}
            U3(\theta, \phi, \lambda) =
            \begin{bmatrix}
                \cos\frac\theta2&-e^{i\lambda}\sin\frac\theta2\\
                e^{i\phi}\sin\frac\theta2&e^{i(\phi+\lambda)}\cos\frac\theta2
            \end{bmatrix}
            \end{align}

        Args:
              theta (Variable): 旋转角度 :math:`\theta` 。
              phi (Variable): 旋转角度 :math:`\phi` 。
              lam (Variable): 旋转角度 :math:`\lambda` 。
Q
Quleaf 已提交
523
              which_qubit (int): 作用在的 qubit 的编号,其值应该在 :math:`[0, n)` 范围内, :math:`n` 为该量子线路的量子比特数
Q
Quleaf 已提交
524 525 526
        """
        assert 0 <= which_qubit < self.n, "the qubit should >= 0 and < n(the number of qubit)"
        self.__history.append(['u', [which_qubit], [theta, phi, lam]])
Q
Quleaf 已提交
527

Q
Quleaf 已提交
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
    def universal_2_qubit_gate(self, theta, which_qubits):
        r"""添加 2-qubit 通用门,这个通用门需要 15 个参数。

        Args:
            theta (Variable): 2-qubit 通用门的参数,其维度为 ``(15, )``
            which_qubits(list): 作用的量子比特编号

        代码示例:

        .. code-block:: python

            import numpy as np
            from paddle import fluid
            from paddle_quantum.circuit import UAnsatz
            n = 2
            theta = np.ones(15)
            with fluid.dygraph.guard():
                theta = fluid.dygraph.to_variable(theta)
                cir = UAnsatz(n)
                cir.universal_2_qubit_gate(fluid.dygraph.to_variable(theta), [0, 1])
                cir.run_state_vector()
                print(cir.measure(shots = 0))

        ::

            {'00': 0.4306256106527819, '01': 0.07994547866706268, '10': 0.07994547866706264, '11': 0.40948343201309334}
        """
 
        assert len(theta.shape) == 1, 'The shape of theta is not right'
        assert len(theta) == 15, 'This Ansatz accepts 15 parameters'
        assert len(which_qubits) == 2, "You should add this gate on two qubits"

        a, b = which_qubits
    
        self.u3(theta[0], theta[1], theta[2], a)
        self.u3(theta[3], theta[4], theta[5], b)
        self.cnot([b, a])
        self.rz(theta[6], a)
        self.ry(theta[7], b)
        self.cnot([a, b])
        self.ry(theta[8], b)
        self.cnot([b, a])
        self.u3(theta[9], theta[10], theta[11], a)
        self.u3(theta[12], theta[13], theta[14], b)

    def __u3qg_U(self, theta, which_qubits):
        r"""
        用于构建 universal_3_qubit_gate
        """
        self.cnot(which_qubits[1:])
        self.ry(theta[0], which_qubits[1])
        self.cnot(which_qubits[:2])
        self.ry(theta[1], which_qubits[1])
        self.cnot(which_qubits[:2])
        self.cnot(which_qubits[1:])
        self.h(which_qubits[2])
        self.cnot([which_qubits[1], which_qubits[0]])
        self.cnot([which_qubits[0], which_qubits[2]])
        self.cnot(which_qubits[1:])
        self.rz(theta[2], which_qubits[2])
        self.cnot(which_qubits[1:])
        self.cnot([which_qubits[0], which_qubits[2]])

    def __u3qg_V(self, theta, which_qubits):
        r"""
        用于构建 universal_3_qubit_gate
        """
        self.cnot([which_qubits[2], which_qubits[0]])
        self.cnot(which_qubits[:2])
        self.cnot([which_qubits[2], which_qubits[1]])
        self.ry(theta[0], which_qubits[2])
        self.cnot(which_qubits[1:])
        self.ry(theta[1], which_qubits[2])
        self.cnot(which_qubits[1:])
        self.s(which_qubits[2])
        self.cnot([which_qubits[2], which_qubits[0]])
        self.cnot(which_qubits[:2])
        self.cnot([which_qubits[1], which_qubits[0]])
        self.h(which_qubits[2])
        self.cnot([which_qubits[0], which_qubits[2]])
        self.rz(theta[2], which_qubits[2])
        self.cnot([which_qubits[0], which_qubits[2]])

    def universal_3_qubit_gate(self, theta, which_qubits):
        r"""添加 3-qubit 通用门,这个通用门需要 81 个参数。

        Note:
            参考: https://cds.cern.ch/record/708846/files/0401178.pdf

        Args:
            theta (Variable): 3-qubit 通用门的参数,其维度为 ``(81, )``
            which_qubits(list): 作用的量子比特编号

        代码示例:

        .. code-block:: python

            import numpy as np
            from paddle import fluid
            from paddle_quantum.circuit import UAnsatz
            n = 3
            theta = np.ones(81)
            with fluid.dygraph.guard():
                theta = fluid.dygraph.to_variable(theta)
                cir = UAnsatz(n)
                cir.universal_3_qubit_gate(fluid.dygraph.to_variable(theta), [0, 1, 2])
                cir.run_state_vector()
                print(cir.measure(shots = 0))

        ::

            {'000': 0.06697926831547105, '001': 0.13206788591381013, '010': 0.2806525391078656, '011': 0.13821526515701105, '100': 0.1390530116439897, '101': 0.004381404333075108, '110': 0.18403296778911565, '111': 0.05461765773966483}
        """
        assert len(which_qubits) == 3, "You should add this gate on three qubits"
        assert len(theta) == 81, "The length of theta is supposed to be 81"

        psi = fluid.layers.reshape(x=theta[: 60], shape=[4, 15])
        phi = fluid.layers.reshape(x=theta[60:], shape=[7, 3])
        self.universal_2_qubit_gate(psi[0], which_qubits[:2])
        self.u3(phi[0][0], phi[0][1], phi[0][2], which_qubits[2])

        self.__u3qg_U(phi[1], which_qubits)

        self.universal_2_qubit_gate(psi[1], which_qubits[:2])
        self.u3(phi[2][0], phi[2][1], phi[2][2], which_qubits[2])

        self.__u3qg_V(phi[3], which_qubits)

        self.universal_2_qubit_gate(psi[2], which_qubits[:2])
        self.u3(phi[4][0], phi[4][1], phi[4][2], which_qubits[2])

        self.__u3qg_U(phi[5], which_qubits)

        self.universal_2_qubit_gate(psi[3], which_qubits[:2])
        self.u3(phi[6][0], phi[6][1], phi[6][2], which_qubits[2])

Q
Quleaf 已提交
664
    """
Q
Quleaf 已提交
665
    Measurements
Q
Quleaf 已提交
666 667
    """

Q
Quleaf 已提交
668 669 670 671
    def __process_string(self, s, which_qubits):
        r"""
        This functions return part of string s baesd on which_qubits
        If s = 'abcdefg', which_qubits = [0,2,5], then it returns 'acf'
Q
Quleaf 已提交
672

Q
Quleaf 已提交
673 674 675 676 677
        Note:
            这是内部函数,你并不需要直接调用到该函数。
        """
        new_s = ''.join(s[j] for j in which_qubits)
        return new_s
Q
Quleaf 已提交
678

Q
Quleaf 已提交
679 680 681 682
    def __process_similiar(self, result):
        r"""
        This functions merges values based on identical keys.
        If result = [('00', 10), ('01', 20), ('11', 30), ('11', 40), ('11', 50), ('00', 60)], then it returns {'00': 70, '01': 20, '11': 120}
Q
Quleaf 已提交
683

Q
Quleaf 已提交
684 685 686 687 688 689
        Note:
            这是内部函数,你并不需要直接调用到该函数。
        """
        data = defaultdict(int)
        for idx, val in result:
            data[idx] += val
Q
Quleaf 已提交
690

Q
Quleaf 已提交
691
        return dict(data)
Q
Quleaf 已提交
692

Q
Quleaf 已提交
693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
    def __measure_hist(self, result, which_qubits, shots):
        r"""将测量的结果以柱状图的形式呈现。

        Note:
            这是内部函数,你并不需要直接调用到该函数。

        Args:
              result (dictionary): 测量结果
              which_qubits (list): 测量的量子比特,如测量所有则是 ``None``
              shots(int): 测量次数

        Returns
            dict: 测量结果

        """
        n = self.n if which_qubits is None else len(which_qubits)
        assert n < 6, "Too many qubits to plot"

        ylabel = "Measured Probabilities"
        if shots == 0:
            shots = 1
            ylabel = "Probabilities"

        state_list = [np.binary_repr(index, width=n) for index in range(0, 2 ** n)]
        freq = []
        for state in state_list:
            freq.append(result.get(state, 0.0) / shots)

        plt.bar(range(2 ** n), freq, tick_label=state_list)
        plt.xticks(rotation=90)
        plt.xlabel("Qubit State")
        plt.ylabel(ylabel)
        plt.show()

        return result

    # Which_qubits is list-like
    def measure(self, which_qubits=None, shots=2 ** 10, plot=False):
        r"""对量子线路输出的量子态进行测量。

        Warning:
Q
Quleaf 已提交
734
            当 ``plot`` 为 ``True`` 时,当前量子线路的量子比特数需要小于 6 ,否则无法绘制图片,会抛出异常。
Q
Quleaf 已提交
735 736 737

        Args:
            which_qubits (list, optional): 要测量的qubit的编号,默认全都测量
Q
Quleaf 已提交
738
            shots (int, optional): 该量子线路输出的量子态的测量次数,默认为 1024 次;若为 0,则返回测量结果的精确概率分布
Q
Quleaf 已提交
739
            plot (bool, optional): 是否绘制测量结果图,默认为 ``False`` ,即不绘制
Q
Quleaf 已提交
740

Q
Quleaf 已提交
741 742 743 744 745 746
        Returns:
            dict: 测量的结果

        代码示例:

        .. code-block:: python
Q
Quleaf 已提交
747

Q
Quleaf 已提交
748 749 750 751 752 753 754 755
            import paddle
            from paddle_quantum.circuit import UAnsatz
            with paddle.fluid.dygraph.guard():
                cir = UAnsatz(2)
                cir.h(0)
                cir.cnot([0,1])
                cir.run_state_vector()
                result = cir.measure(shots = 2048, which_qubits = [1])
Q
Quleaf 已提交
756
                print(f"The results of measuring qubit 1 2048 times are {result}")
Q
Quleaf 已提交
757 758 759

        ::

Q
Quleaf 已提交
760
            The results of measuring qubit 1 2048 times are {'0': 964, '1': 1084}
Q
Quleaf 已提交
761 762

        .. code-block:: python
Q
Quleaf 已提交
763

Q
Quleaf 已提交
764 765 766 767 768 769 770 771
            import paddle
            from paddle_quantum.circuit import UAnsatz
            with paddle.fluid.dygraph.guard():
                cir = UAnsatz(2)
                cir.h(0)
                cir.cnot([0,1])
                cir.run_state_vector()
                result = cir.measure(shots = 0, which_qubits = [1])
Q
Quleaf 已提交
772
                print(f"The probability distribution of measurement results on qubit 1 is {result}")
Q
Quleaf 已提交
773 774 775

        ::

Q
Quleaf 已提交
776
            The probability distribution of measurement results on qubit 1 is {'0': 0.4999999999999999, '1': 0.4999999999999999}
Q
Quleaf 已提交
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811
        """
        if self.__run_state == 'state_vector':
            state = self.__state
        elif self.__run_state == 'density_matrix':
            # Take the diagonal of the density matrix as a probability distribution
            diag = np.diag(self.__state.numpy())
            state = fluid.dygraph.to_variable(np.sqrt(diag))
        else:
            # Raise error
            raise ValueError("no state for measurement; please run the circuit first")

        if shots == 0:  # Returns probability distribution over all measurement results
            dic2to10, dic10to2 = dic_between2and10(self.n)
            result = {}
            for i in range(2 ** self.n):
                result[dic10to2[i]] = (state.real[i] ** 2 + state.imag[i] ** 2).numpy()[0]

            if which_qubits is not None:
                new_result = [(self.__process_string(key, which_qubits), value) for key, value in result.items()]
                result = self.__process_similiar(new_result)
        else:
            if which_qubits is None:  # Return all the qubits
                result = measure_state(state, shots)
            else:
                assert all([e < self.n for e in which_qubits]), 'Qubit index out of range'
                which_qubits.sort()  # Sort in ascending order

                collapse_all = measure_state(state, shots)
                new_collapse_all = [(self.__process_string(key, which_qubits), value) for key, value in
                                    collapse_all.items()]
                result = self.__process_similiar(new_collapse_all)

        return result if not plot else self.__measure_hist(result, which_qubits, shots)

    def expecval(self, H):
Q
Quleaf 已提交
812
        r"""量子线路输出的量子态关于可观测量 H 的期望值。
Q
Quleaf 已提交
813 814 815 816 817 818

        Hint:
            如果想输入的可观测量的矩阵为 :math:`0.7Z\otimes X\otimes I+0.2I\otimes Z\otimes I` 。则 ``H`` 应为 ``[[0.7, 'z0,x1'], [0.2, 'z1']]`` 。
        Args:
            H (list): 可观测量的相关信息
        Returns:
Q
Quleaf 已提交
819
            Variable: 量子线路输出的量子态关于 H 的期望值
Q
Quleaf 已提交
820 821

        代码示例:
Q
Quleaf 已提交
822

Q
Quleaf 已提交
823
        .. code-block:: python
Q
Quleaf 已提交
824

Q
Quleaf 已提交
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841
            import numpy as np
            from paddle import fluid
            from paddle_quantum.circuit import UAnsatz
            n = 5
            H_info = [[0.1, 'x1'], [0.2, 'y0,z4']]
            theta = np.ones(3)
            input_state = np.ones(2**n)+0j
            input_state = input_state / np.linalg.norm(input_state)
            with fluid.dygraph.guard():
                input_state_var = fluid.dygraph.to_variable(input_state)
                theta = fluid.dygraph.to_variable(theta)
                cir = UAnsatz(n)
                cir.rx(theta[0], 0)
                cir.rz(theta[1], 1)
                cir.rx(theta[2], 2)
                cir.run_state_vector(input_state_var)
                expect_value = cir.expecval(H_info).numpy()
Q
Quleaf 已提交
842
                print(f'Calculated expectation value of {H_info} is {expect_value}')
Q
Quleaf 已提交
843

Q
Quleaf 已提交
844
        ::
Q
Quleaf 已提交
845

Q
Quleaf 已提交
846
            Calculated expectation value of [[0.1, 'x1'], [0.2, 'y0,z4']] is [0.05403023]
Q
Quleaf 已提交
847

Q
Quleaf 已提交
848
        .. code-block:: python
Q
Quleaf 已提交
849

Q
Quleaf 已提交
850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
            import numpy as np
            from paddle import fluid
            from paddle_quantum.circuit import UAnsatz
            n = 5
            H_info = [[0.1, 'x1'], [0.2, 'y0,z4']]
            theta = np.ones(3)
            input_state = np.diag(np.arange(2**n))+0j
            input_state = input_state / np.trace(input_state)
            with fluid.dygraph.guard():
                input_state_var = fluid.dygraph.to_variable(input_state)
                theta = fluid.dygraph.to_variable(theta)
                cir = UAnsatz(n)
                cir.rx(theta[0], 0)
                cir.ry(theta[1], 1)
                cir.rz(theta[2], 2)
                cir.run_density_matrix(input_state_var)
                expect_value = cir.expecval(H_info).numpy()
Q
Quleaf 已提交
867
                print(f'Calculated expectation value of {H_info} is {expect_value}')
Q
Quleaf 已提交
868

Q
Quleaf 已提交
869 870
        ::

Q
Quleaf 已提交
871
            Calculated expectation value of [[0.1, 'x1'], [0.2, 'y0,z4']] is [-0.02171538]
Q
Quleaf 已提交
872 873 874 875 876 877 878 879 880 881
        """
        if self.__run_state == 'state_vector':
            return vec_expecval(H, self.__state).real
        elif self.__run_state == 'density_matrix':
            state = self.__state
            H_mat = fluid.dygraph.to_variable(pauli_str_to_matrix(H, self.n))
            return trace(matmul(state, H_mat)).real
        else:
            # Raise error
            raise ValueError("no state for measurement; please run the circuit first")
Q
Quleaf 已提交
882 883

    """
Q
Quleaf 已提交
884
    Circuit Templates
Q
Quleaf 已提交
885 886
    """

Q
Quleaf 已提交
887
    def superposition_layer(self):
Q
Quleaf 已提交
888
        r"""添加一层 Hadamard 门。
Q
Quleaf 已提交
889 890 891 892

        代码示例:

        .. code-block:: python
Q
Quleaf 已提交
893

Q
Quleaf 已提交
894 895 896 897 898 899 900
            import paddle
            from paddle_quantum.circuit import UAnsatz
            with paddle.fluid.dygraph.guard():
                cir = UAnsatz(2)
                cir.superposition_layer()
                cir.run_state_vector()
                result = cir.measure(shots = 0)
Q
Quleaf 已提交
901
                print(f"The probability distribution of measurement results on both qubits is {result}")
Q
Quleaf 已提交
902 903 904

        ::

Q
Quleaf 已提交
905
            The probability distribution of measurement results on both qubits is {'00': 0.2499999999999999, '01': 0.2499999999999999, '10': 0.2499999999999999, '11': 0.2499999999999999}
Q
Quleaf 已提交
906
        """
Q
Quleaf 已提交
907 908 909 910
        for i in range(self.n):
            self.h(i)

    def weak_superposition_layer(self):
Q
Quleaf 已提交
911
        r"""添加一层旋转角度为 :math:`\pi/4` 的 Ry 门。
Q
Quleaf 已提交
912 913 914 915

        代码示例:

        .. code-block:: python
Q
Quleaf 已提交
916

Q
Quleaf 已提交
917 918 919 920 921 922 923
            import paddle
            from paddle_quantum.circuit import UAnsatz
            with paddle.fluid.dygraph.guard():
                cir = UAnsatz(2)
                cir.weak_superposition_layer()
                cir.run_state_vector()
                result = cir.measure(shots = 0)
Q
Quleaf 已提交
924
                print(f"The probability distribution of measurement results on both qubits is {result}")
Q
Quleaf 已提交
925 926 927

        ::

Q
Quleaf 已提交
928
            The probability distribution of measurement results on both qubits is {'00': 0.7285533905932737, '01': 0.12500000000000003, '10': 0.12500000000000003, '11': 0.021446609406726238}
Q
Quleaf 已提交
929
        """
Q
Quleaf 已提交
930 931 932
        _theta = fluid.dygraph.to_variable(np.array([np.pi / 4]))  # Used in fixed Ry gate
        for i in range(self.n):
            self.ry(_theta, i)
Q
Quleaf 已提交
933

Q
Quleaf 已提交
934 935
    def real_entangled_layer(self, theta, depth, which_qubits=None):
        r"""添加 ``depth`` 层包含 Ry 门和 CNOT 门的强纠缠层。
Q
Quleaf 已提交
936

Q
Quleaf 已提交
937 938
        Note:
            这一层量子门的数学表示形式为实数酉矩阵。
Q
Quleaf 已提交
939

Q
Quleaf 已提交
940 941
        Attention:
            ``theta`` 的维度为 ``(depth, n, 1)``
Q
Quleaf 已提交
942

Q
Quleaf 已提交
943
        Args:
Q
Quleaf 已提交
944
            theta (Variable): Ry 门的旋转角度
Q
Quleaf 已提交
945
            depth (int): 纠缠层的深度
Q
Quleaf 已提交
946
            which_qubits(list): 作用的量子比特编号
Q
Quleaf 已提交
947 948 949 950

        代码示例:

        .. code-block:: python
Q
Quleaf 已提交
951

Q
Quleaf 已提交
952 953 954 955 956 957 958 959 960
            import numpy as np
            from paddle import fluid
            from paddle_quantum.circuit import UAnsatz
            n = 2
            DEPTH = 3
            theta = np.ones([DEPTH, n, 1])
            with fluid.dygraph.guard():
                theta = fluid.dygraph.to_variable(theta)
                cir = UAnsatz(n)
Q
Quleaf 已提交
961
                cir.real_entangled_layer(fluid.dygraph.to_variable(theta), DEPTH, [0, 1])
Q
Quleaf 已提交
962 963
                cir.run_state_vector()
                print(cir.measure(shots = 0))
Q
Quleaf 已提交
964

Q
Quleaf 已提交
965 966 967
        ::

            {'00': 2.52129874867343e-05, '01': 0.295456784923382, '10': 0.7045028818254718, '11': 1.5120263659845063e-05}
Q
Quleaf 已提交
968
        """
Q
Quleaf 已提交
969 970 971
        assert self.n > 1, 'you need at least 2 qubits'
        assert len(theta.shape) == 3, 'the shape of theta is not right'
        assert theta.shape[2] == 1, 'the shape of theta is not right'
Q
Quleaf 已提交
972
        #assert theta.shape[1] == self.n, 'the shape of theta is not right'
Q
Quleaf 已提交
973 974
        assert theta.shape[0] == depth, 'the depth of theta has a mismatch'

Q
Quleaf 已提交
975 976 977
        if which_qubits is None:
            which_qubits = np.arange(self.n)

Q
Quleaf 已提交
978
        for repeat in range(depth):
Q
Quleaf 已提交
979 980 981 982 983
            for i, q in enumerate(which_qubits):
                self.ry(theta=theta[repeat][i][0], which_qubit=q)
            for i in range(len(which_qubits) - 1):
                self.cnot([which_qubits[i], which_qubits[i + 1]])
            self.cnot([which_qubits[-1], which_qubits[0]])
Q
Quleaf 已提交
984

Q
Quleaf 已提交
985 986
    def complex_entangled_layer(self, theta, depth, which_qubits=None):
        r"""添加 ``depth`` 层包含 U3 门和 CNOT 门的强纠缠层。
Q
Quleaf 已提交
987 988 989

        Note:
            这一层量子门的数学表示形式为复数酉矩阵。
Q
Quleaf 已提交
990

Q
Quleaf 已提交
991 992
        Attention:
            ``theta`` 的维度为 ``(depth, n, 3)`` ,最低维内容为对应的 ``u3`` 的参数 ``(theta, phi, lam)``
Q
Quleaf 已提交
993

Q
Quleaf 已提交
994
        Args:
Q
Quleaf 已提交
995
            theta (Variable): U3 门的旋转角度
Q
Quleaf 已提交
996
            depth (int): 纠缠层的深度
Q
Quleaf 已提交
997
            which_qubits(list): 作用的量子比特编号
Q
Quleaf 已提交
998 999 1000 1001

        代码示例:

        .. code-block:: python
Q
Quleaf 已提交
1002

Q
Quleaf 已提交
1003 1004 1005 1006 1007 1008 1009 1010 1011
            import numpy as np
            from paddle import fluid
            from paddle_quantum.circuit import UAnsatz
            n = 2
            DEPTH = 3
            theta = np.ones([DEPTH, n, 1])
            with fluid.dygraph.guard():
                theta = fluid.dygraph.to_variable(theta)
                cir = UAnsatz(n)
Q
Quleaf 已提交
1012
                cir.complex_entangled_layer(fluid.dygraph.to_variable(theta), DEPTH, [0, 1])
Q
Quleaf 已提交
1013 1014
                cir.run_state_vector()
                print(cir.measure(shots = 0))
Q
Quleaf 已提交
1015

Q
Quleaf 已提交
1016 1017 1018
        ::

            {'00': 0.15032627279218896, '01': 0.564191201239618, '10': 0.03285998070292556, '11': 0.25262254526526823}
Q
Quleaf 已提交
1019
        """
Q
Quleaf 已提交
1020 1021 1022
        assert self.n > 1, 'you need at least 2 qubits'
        assert len(theta.shape) == 3, 'the shape of theta is not right'
        assert theta.shape[2] == 3, 'the shape of theta is not right'
Q
Quleaf 已提交
1023
        # assert theta.shape[1] == self.n, 'the shape of theta is not right'
Q
Quleaf 已提交
1024
        assert theta.shape[0] == depth, 'the depth of theta has a mismatch'
Q
Quleaf 已提交
1025

Q
Quleaf 已提交
1026 1027
        if which_qubits is None:
            which_qubits = np.arange(self.n)
Q
Quleaf 已提交
1028

Q
Quleaf 已提交
1029 1030 1031 1032 1033 1034
        for repeat in range(depth):
            for i, q in enumerate(which_qubits):
                self.u3(theta[repeat][i][0], theta[repeat][i][1], theta[repeat][i][2],  which_qubit=q)
            for i in range(len(which_qubits) - 1):
                self.cnot([which_qubits[i], which_qubits[i + 1]])
            self.cnot([which_qubits[-1], which_qubits[0]])
Q
Quleaf 已提交
1035 1036 1037 1038 1039 1040 1041

    def __add_real_block(self, theta, position):
        r"""
        Add a real block to the circuit in (position). theta is a one dimensional tensor

        Note:
            这是内部函数,你并不需要直接调用到该函数。
Q
Quleaf 已提交
1042
        """
Q
Quleaf 已提交
1043 1044 1045 1046
        assert len(theta) == 4, 'the length of theta is not right'
        assert 0 <= position[0] < self.n and 0 <= position[1] < self.n, 'position is out of range'
        self.ry(theta[0], position[0])
        self.ry(theta[1], position[1])
Q
Quleaf 已提交
1047

Q
Quleaf 已提交
1048
        self.cnot([position[0], position[1]])
Q
Quleaf 已提交
1049

Q
Quleaf 已提交
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075
        self.ry(theta[2], position[0])
        self.ry(theta[3], position[1])

    def __add_complex_block(self, theta, position):
        r"""
        Add a complex block to the circuit in (position). theta is a one dimensional tensor

        Note:
            这是内部函数,你并不需要直接调用到该函数。
        """
        assert len(theta) == 12, 'the length of theta is not right'
        assert 0 <= position[0] < self.n and 0 <= position[1] < self.n, 'position is out of range'
        self.u3(theta[0], theta[1], theta[2], position[0])
        self.u3(theta[3], theta[4], theta[5], position[1])

        self.cnot([position[0], position[1]])

        self.u3(theta[6], theta[7], theta[8], position[0])
        self.u3(theta[9], theta[10], theta[11], position[1])

    def __add_real_layer(self, theta, position):
        r"""
        Add a real layer on the circuit. theta is a two dimensional tensor. position is the qubit range the layer needs to cover

        Note:
            这是内部函数,你并不需要直接调用到该函数。
Q
Quleaf 已提交
1076
        """
Q
Quleaf 已提交
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087
        assert theta.shape[1] == 4 and theta.shape[0] == (position[1] - position[0] + 1) / 2,\
            'the shape of theta is not right'
        for i in range(position[0], position[1], 2):
            self.__add_real_block(theta[int((i - position[0]) / 2)], [i, i + 1])

    def __add_complex_layer(self, theta, position):
        r"""
        Add a complex layer on the circuit. theta is a two dimensional tensor. position is the qubit range the layer needs to cover

        Note:
            这是内部函数,你并不需要直接调用到该函数。
Q
Quleaf 已提交
1088
        """
Q
Quleaf 已提交
1089 1090 1091 1092
        assert theta.shape[1] == 12 and theta.shape[0] == (position[1] - position[0] + 1) / 2,\
            'the shape of theta is not right'
        for i in range(position[0], position[1], 2):
            self.__add_complex_block(theta[int((i - position[0]) / 2)], [i, i + 1])
Q
Quleaf 已提交
1093

Q
Quleaf 已提交
1094
    def real_block_layer(self, theta, depth):
Q
Quleaf 已提交
1095
        r"""添加 ``depth`` 层包含 Ry 门和 CNOT 门的弱纠缠层。
Q
Quleaf 已提交
1096

Q
Quleaf 已提交
1097 1098
        Note:
            这一层量子门的数学表示形式为实数酉矩阵。
Q
Quleaf 已提交
1099

Q
Quleaf 已提交
1100 1101
        Attention:
            ``theta`` 的维度为 ``(depth, n-1, 4)``
Q
Quleaf 已提交
1102

Q
Quleaf 已提交
1103
        Args:
Q
Quleaf 已提交
1104
            theta(Variable): Ry 门的旋转角度
Q
Quleaf 已提交
1105 1106 1107 1108 1109
            depth(int): 纠缠层的深度

        代码示例:

        .. code-block:: python
Q
Quleaf 已提交
1110

Q
Quleaf 已提交
1111 1112
            n = 4
            DEPTH = 3
Q
Quleaf 已提交
1113
            theta = np.ones([DEPTH, n-1, 4])
Q
Quleaf 已提交
1114 1115 1116 1117 1118 1119
            with fluid.dygraph.guard():
                theta = fluid.dygraph.to_variable(theta)
                cir = UAnsatz(n)
                cir.real_block_layer(fluid.dygraph.to_variable(theta), DEPTH)
                cir.run_density_matrix()
                print(cir.measure(shots = 0, which_qubits = [0]))
Q
Quleaf 已提交
1120

Q
Quleaf 已提交
1121 1122 1123
        ::

            {'0': 0.9646724056906162, '1': 0.035327594309385896}
Q
Quleaf 已提交
1124
        """
Q
Quleaf 已提交
1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
        assert self.n > 1, 'you need at least 2 qubits'
        assert len(theta.shape) == 3, 'The dimension of theta is not right'
        _depth, m, block = theta.shape
        assert depth > 0, 'depth must be greater than zero'
        assert _depth == depth, 'the depth of parameters has a mismatch'
        assert m == self.n - 1 and block == 4, 'The shape of theta is not right'

        if self.n % 2 == 0:
            for i in range(depth):
                self.__add_real_layer(theta[i][:int(self.n / 2)], [0, self.n - 1])
                self.__add_real_layer(theta[i][int(self.n / 2):], [1, self.n - 2]) if self.n > 2 else None
        else:
            for i in range(depth):
                self.__add_real_layer(theta[i][:int((self.n - 1) / 2)], [0, self.n - 2])
                self.__add_real_layer(theta[i][int((self.n - 1) / 2):], [1, self.n - 1])

    def complex_block_layer(self, theta, depth):
Q
Quleaf 已提交
1142 1143
        r"""添加 ``depth`` 层包含 U3 门和 CNOT 门的弱纠缠层。

Q
Quleaf 已提交
1144 1145 1146 1147 1148
        Note:
            这一层量子门的数学表示形式为复数酉矩阵。

        Attention:
            ``theta`` 的维度为 ``(depth, n-1, 12)``
Q
Quleaf 已提交
1149

Q
Quleaf 已提交
1150
        Args:
Q
Quleaf 已提交
1151
            theta (Variable): U3 门的角度信息
Q
Quleaf 已提交
1152 1153 1154 1155 1156
            depth (int): 纠缠层的深度

        代码示例:

        .. code-block:: python
Q
Quleaf 已提交
1157

Q
Quleaf 已提交
1158 1159
            n = 4
            DEPTH = 3
Q
Quleaf 已提交
1160
            theta = np.ones([DEPTH, n-1, 12])
Q
Quleaf 已提交
1161 1162 1163 1164 1165 1166
            with fluid.dygraph.guard():
                theta = fluid.dygraph.to_variable(theta)
                cir = UAnsatz(n)
                cir.complex_block_layer(fluid.dygraph.to_variable(theta), DEPTH)
                cir.run_density_matrix()
                print(cir.measure(shots = 0, which_qubits = [0]))
Q
Quleaf 已提交
1167

Q
Quleaf 已提交
1168
        ::
Q
Quleaf 已提交
1169

Q
Quleaf 已提交
1170
            {'0': 0.5271554811768046, '1': 0.4728445188231988}
Q
Quleaf 已提交
1171
        """
Q
Quleaf 已提交
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187
        assert self.n > 1, 'you need at least 2 qubits'
        assert len(theta.shape) == 3, 'The dimension of theta is not right'
        assert depth > 0, 'depth must be greater than zero'
        _depth, m, block = theta.shape
        assert _depth == depth, 'the depth of parameters has a mismatch'
        assert m == self.n - 1 and block == 12, 'The shape of theta is not right'

        if self.n % 2 == 0:
            for i in range(depth):
                self.__add_complex_layer(theta[i][:int(self.n / 2)], [0, self.n - 1])
                self.__add_complex_layer(theta[i][int(self.n / 2):], [1, self.n - 2]) if self.n > 2 else None
        else:
            for i in range(depth):
                self.__add_complex_layer(theta[i][:int((self.n - 1) / 2)], [0, self.n - 2])
                self.__add_complex_layer(theta[i][int((self.n - 1) / 2):], [1, self.n - 1])

Q
Quleaf 已提交
1188

Q
Quleaf 已提交
1189
def __local_H_prob(cir, hamiltonian, shots=1024):
Q
Quleaf 已提交
1190
    r"""
Q
Quleaf 已提交
1191
    构造出 Pauli 测量电路并测量 ancilla,处理实验结果来得到 ``H`` (只有一项)期望值的实验测量值。
Q
Quleaf 已提交
1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233

    Note:
        这是内部函数,你并不需要直接调用到该函数。
    """
    # Add one ancilla, which we later measure and process the result
    new_cir = UAnsatz(cir.n + 1)
    input_state = pp_kron(cir.run_state_vector(store_state=False), init_state_gen(1))
    # Used in fixed Rz gate
    _theta = fluid.dygraph.to_variable(np.array([-np.pi / 2]))

    op_list = hamiltonian.split(',')
    # Set up pauli measurement circuit
    for op in op_list:
        element = op[0]
        index = int(op[1:])
        if element == 'x':
            new_cir.h(index)
            new_cir.cnot([index, cir.n])
        elif element == 'z':
            new_cir.cnot([index, cir.n])
        elif element == 'y':
            new_cir.rz(_theta, index)
            new_cir.h(index)
            new_cir.cnot([index, cir.n])

    new_cir.run_state_vector(input_state)
    prob_result = new_cir.measure(shots=shots, which_qubits=[cir.n])
    if shots > 0:
        if len(prob_result) == 1:
            if '0' in prob_result:
                result = (prob_result['0']) / shots
            else:
                result = (prob_result['1']) / shots
        else:
            result = (prob_result['0'] - prob_result['1']) / shots
    else:
        result = (prob_result['0'] - prob_result['1'])

    return result


def H_prob(cir, H, shots=1024):
Q
Quleaf 已提交
1234 1235
    r"""构造 Pauli 测量电路并测量关于 H 的期望值。

Q
Quleaf 已提交
1236
    Args:
Q
Quleaf 已提交
1237
        cir (UAnsatz): UAnsatz 的一个实例化对象
Q
Quleaf 已提交
1238
        H (list): 记录哈密顿量信息的列表
Q
Quleaf 已提交
1239 1240
        shots (int, optional): 默认为 1024,表示测量次数;若为 0,则表示返回测量期望值的精确值,即测量无穷次后的期望值

Q
Quleaf 已提交
1241 1242
    Returns:
        float: 测量得到的H的期望值
Q
Quleaf 已提交
1243

Q
Quleaf 已提交
1244 1245 1246
    代码示例:

    .. code-block:: python
Q
Quleaf 已提交
1247

Q
Quleaf 已提交
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264
        import numpy as np
        from paddle import fluid
        from paddle_quantum.circuit import UAnsatz, H_prob
        n = 4
        theta = np.ones(3)
        experiment_shots = 2**10
        H_info = [[0.1, 'x2'], [0.3, 'y1,z3']]
        input_state = np.ones(2**n)+0j
        input_state = input_state / np.linalg.norm(input_state)
        with fluid.dygraph.guard():
            theta = fluid.dygraph.to_variable(theta)
            cir = UAnsatz(n)
            cir.rx(theta[0], 0)
            cir.ry(theta[1], 1)
            cir.rz(theta[2], 1)
            result_1 = H_prob(cir, H_info, shots = experiment_shots)
            result_2 = H_prob(cir, H_info, shots = 0)
Q
Quleaf 已提交
1265 1266
            print(f'The expectation value obtained by {experiment_shots} measurements is {result_1}')
            print(f'The accurate expectation value of H is {result_2}')
Q
Quleaf 已提交
1267 1268 1269

    ::

Q
Quleaf 已提交
1270 1271
        The expectation value obtained by 1024 measurements is 0.2326171875
        The accurate expectation value of H is 0.21242202548207134
Q
Quleaf 已提交
1272 1273 1274
    """
    expval = 0
    for term in H:
Q
Quleaf 已提交
1275
        expval += term[0] * __local_H_prob(cir, term[1], shots=shots)
Q
Quleaf 已提交
1276
    return expval