MindQuantum 0.7.0源代码阅读理解(1)

MindQuantum 0.7.0 源代码阅读理解(1)

因本人在研究中需要对 MindQuantum 原代码进行改写,以实现所需功能,在接下来的几篇博文里,我会以笔记的形式充分阅读并理解其源代码,欢迎读者一起学习。本人能力有限,肯定不乏错误,建议读者在参考时要时刻保持批判的态度。
关于 MindQuantum 的安装、API、版本信息等,请参考 MindQuantum 官网

1. utils (常用工具)文件

该部分是源代码中常见的内容,下面先解决他们,打好基础。
上一篇博文介绍了 1.1 type_value_check.py,下面介绍 1.2 f.py,其中定义了一些有用的函数,比如计算矢量模长、归一化等。

1.2 f.py

import numbers
from functools import lru_cache
# functool 模块中的 lru_cache 装饰器,可以直接将函数或类方法的结果缓存住,后续调用则直接返回缓存的结果。

import numpy as np

from mindquantum.config.config import _GLOBAL_MAT_VALUE

# 上一篇博客中介绍过,现在用上了吧
from .type_value_check import (
    _check_input_type,
    _check_int_type,
    _check_value_should_between_close_set,
    _check_value_should_not_less,
)

__all__ = ['random_circuit', 'mod', 'normalize', 'random_state']

# 按指定参数生成随机线路
def random_circuit(n_qubits, gate_num, sd_rate=0.5, ctrl_rate=0.2, seed=None):
    """
    Generate a random circuit.

    Args:
        n_qubits (int): Number of qubits of random circuit.
        gate_num (int): Number of gates in random circuit.
        sd_rate (float): The rate of single qubit gate and double qubits gates.
        ctrl_rate (float): The possibility that a gate has a control qubit.
        seed (int): Random seed to generate random circuit.

    Examples:
        >>> from mindquantum.utils import random_circuit
        >>> random_circuit(3, 4, 0.5, 0.5, 100)
        q1: ──Z────RX(0.944)────────●────────RX(-0.858)──
              │        │            │            │
        q2: ──●────────●────────RZ(-2.42)────────●───────
    """
    # pylint: disable=import-outside-toplevel,cyclic-import
    # pylint是一个Python源代码中查找bug的工具,能找出错误,和代码规范的运行。也就是你的代码有Error错误的时候能找出来错误,没有错误的时候,能根据Python代码规范给你建议修改代码,让代码变更美观。
    from ..core import gates
    from ..core.circuit import Circuit

    _check_int_type('n_qubits', n_qubits)
    _check_int_type('gate_num', gate_num)
    _check_input_type('sd_rate', float, sd_rate)
    _check_input_type('ctrl_rate', float, ctrl_rate)
    if seed is None:
        seed = np.random.randint(1, 2**23)
    _check_int_type('seed', seed)
    _check_value_should_not_less('n_qubits', 1, n_qubits)
    _check_value_should_not_less('gate_num', 1, gate_num)
    _check_value_should_between_close_set('sd_rate', 0, 1, sd_rate)
    _check_value_should_between_close_set('ctrl_rate', 0, 1, ctrl_rate)
    _check_value_should_between_close_set('seed', 0, 2**32 - 1, seed)
    if n_qubits == 1:
        sd_rate = 1
        ctrl_rate = 0
    single = {
        'param': [gates.RX, gates.RY, gates.RZ, gates.PhaseShift],
        'non_param': [gates.X, gates.Y, gates.Z, gates.H],
    }
    double = {'param': [gates.XX, gates.YY, gates.ZZ], 'non_param': [gates.SWAP]}
    circuit = Circuit()
    np.random.seed(seed)
    qubits = range(n_qubits)
    for _ in range(gate_num):
        if n_qubits == 1:
            q1, q2 = int(qubits[0]), None
        else:
            q1, q2 = np.random.choice(qubits, 2, replace=False) # 不放回抽取
            q1, q2 = int(q1), int(q2)
        if np.random.random() < sd_rate:
            if np.random.random() > ctrl_rate:
                q2 = None
            if np.random.random() < 0.5:
                gate = np.random.choice(single['param'])
                param = np.random.uniform(-np.pi * 2, np.pi * 2)
                circuit += gate(param).on(q1, q2)
            else:
                gate = np.random.choice(single['non_param'])
                circuit += gate.on(q1, q2)
        else:
            if np.random.random() < 0.75:
                gate = np.random.choice(double['param'])
                param = np.random.uniform(-np.pi * 2, np.pi * 2)
                circuit += gate(param).on([q1, q2])
            else:
                gate = np.random.choice(double['non_param'])
                circuit += gate.on([q1, q2])
    return circuit

# 检查是否为 数组 或 列表
def _check_num_array(vec, name):
    if not isinstance(vec, (np.ndarray, list)):
        raise TypeError(f"{name} requires a numpy.ndarray or a list of number, but get {type(vec)}.")

# 计算 模长
def mod(vec_in, axis=0):
    """
    Calculate the mod of input vectors.

    Args:
        vec_in (Union[list[numbers.Number], numpy.ndarray]): The vector you want to calculate mod.
        axis (int): Along which axis you want to calculate mod. Default: 0.

    Returns:
        numpy.ndarray, The mod of input vector.

    Examples:
        >>> from mindquantum.utils import mod
        >>> vec_in = np.array([[1, 2, 3], [4, 5, 6]])
        >>> mod(vec_in)
        array([[4.12310563, 5.38516481, 6.70820393]])
        >>> mod(vec_in, 1)
        array([[3.74165739],
               [8.77496439]])
    """
    _check_num_array(vec_in, 'vec_in')
    vec_in = np.array(vec_in)
    return np.sqrt(np.sum(np.conj(vec_in) * vec_in, axis=axis, keepdims=True))

# 将矢量归一化
def normalize(vec_in, axis=0):
    """
    Normalize the input vectors based on specified axis.

    Args:
        vec_in (Union[list[number], numpy.ndarray]): Vector you want to
            normalize.
        axis (int): Along which axis you want to normalize your vector. Default: 0.

    Returns:
        numpy.ndarray, Vector after normalization.

    Examples:
        >>> from mindquantum.utils import normalize
        >>> vec_in = np.array([[1, 2, 3], [4, 5, 6]])
        >>> normalize(vec_in)
        array([[0.24253563, 0.37139068, 0.4472136 ],
               [0.9701425 , 0.92847669, 0.89442719]])
        >>> normalize(vec_in, 1)
        array([[0.26726124, 0.53452248, 0.80178373],
               [0.45584231, 0.56980288, 0.68376346]])
    """
    _check_num_array(vec_in, 'vec_in')
    vec_in = np.array(vec_in)
    return vec_in / mod(vec_in, axis=axis)

# 生成随机量子态
def random_state(shapes, norm_axis=0, comp=True, seed=None):
    r"""
    Generate some random quantum state.

    Args:
        shapes (tuple): shapes = (m, n) means m quantum states with each state
            formed by :math:`\log_2(n)` qubits.
        norm_axis (int): which axis you want to apply normalization. Default: 0.
        comp (bool): if `True`, each amplitude of the quantum state will be a
            complex number. Default: True.
        seed (int): the random seed. Default: None.

    Returns:
        numpy.ndarray, A normalized random quantum state.

    Examples:
        >>> from mindquantum.utils import random_state
        >>> random_state((2, 2), seed=42)
        array([[0.44644744+0.18597239j, 0.66614846+0.10930256j],
               [0.87252821+0.06923499j, 0.41946926+0.60691409j]])
    """
    if not isinstance(shapes, (int, tuple)):
        raise TypeError(f"shape requires a int of a tuple of int, but get {type(shapes)}!")
    if not isinstance(comp, bool):
        raise TypeError(f"comp requires a bool, but get {comp}!")
    np.random.seed(seed)
    out = np.random.uniform(size=shapes) + 0j
    if comp:
        out += np.random.uniform(size=shapes) * 1j
    if norm_axis is False:
        return out
    return normalize(out, axis=norm_axis)

# 检查两个数之间是否接近误差范围, atol:绝对公差参数 atol=1e-08
def is_two_number_close(a, b, atol=None):  # pylint: disable=invalid-name
    """
    Check whether two number is close within the error of atol.

    This method also works for complex numbers.

    Args:
        a (numbers.Number): The first number.
        b (numbers.Number): The second number.
        atol (float): The atol. If None, the precision defined in global config
            will be used. Default: None.

    Returns:
        bool, whether this two number close to each other.

    Examples:
        >>> from mindquantum.utils import is_two_number_close
        >>> is_two_number_close(1+1j, 1+1j)
        True
    """
    from mindquantum.config.config import (  # pylint: disable=import-outside-toplevel
        Context,
    )

    _check_input_type("a", numbers.Number, a)
    _check_input_type("b", numbers.Number, b)
    if atol is None:
        atol = Context.get_precision()
    _check_input_type("atol", float, atol)
    return np.allclose(np.abs(a - b), 0, atol=atol)

# 检查一个数是否为2的幂。计算原理请参考另一篇博文 https://editor.csdn.net/md/?articleId=126771361
def is_power_of_two(num):
    """Check whether a number is power of 2 or not."""
    return (num & (num - 1) == 0) and num != 0


@lru_cache()
def pauli_string_matrix(pauli_string):
    """
    Generate the matrix of pauli string.

    If pauli string is XYZ, then the matrix will be `Z@Y@X`.
    """
    try:
        matrix = _GLOBAL_MAT_VALUE[pauli_string[0]] # 先计算第一个字符 即 X
        for string in pauli_string[1:]:
            matrix = np.kron(_GLOBAL_MAT_VALUE[string], matrix)
    except KeyError as err:
        raise err
    return matrix
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值