kaiwu.preprocess._precision 源代码

# -*- coding: utf-8 -*-
"""
提供Ising矩阵精度校验相关功能
"""
import numpy as np

from kaiwu.license import track_data
from kaiwu.core import qubo_matrix_to_ising_matrix, ising_matrix_to_qubo_matrix


[文档] @track_data() def calculate_ising_matrix_bit_width(ising_matrix, bit_width=8): """计算 ising 矩阵的参数位宽 Args: ising_matrix (np.ndarray): ising 矩阵 bit_width (int): 最大位宽限制 Returns: dict: 返回Ising矩阵的精度和缩放因子 - precision (int): Ising矩阵精度 - multiplier (float): 缩放因子 示例1: >>> import numpy as np >>> import kaiwu as kw >>> _matrix = -np.array([[ -0., 127., -12., -5.], ... [127., -0., -12., -12.], ... [-12., -12., -0., -9.], ... [ -5., -12., -9., -0.]]) >>> kw.preprocess.calculate_ising_matrix_bit_width(_matrix) {'precision': 8, 'multiplier': np.float64(1.0)} 示例2(缩放后符合要求): >>> import numpy as np >>> import kaiwu as kw >>> _matrix = -np.array([[ -0., 12.7, -1.2, -0.5], ... [12.7, -0., -1.2, -1.2], ... [-1.2, -1.2, -0., -0.9], ... [-0.5, -1.2, -0.9, -0.]]) >>> kw.preprocess.calculate_ising_matrix_bit_width(_matrix) {'precision': 8, 'multiplier': np.float64(10.0)} 示例3(缩放后也不符合要求): >>> import numpy as np >>> import kaiwu as kw >>> _matrix = -np.array([[-488., 516., -48.], ... [ 516., -516., -48.], ... [ -48., -48., 60.]]) >>> kw.preprocess.calculate_ising_matrix_bit_width(_matrix) {'precision': inf, 'multiplier': inf} """ bit_width = bit_width - 1 # 留一位符号位 if not np.any(ising_matrix): return {"precision": np.inf, "multiplier": np.inf} abs_matrix = np.abs(ising_matrix) threshold = 1e-10 non_zero_elements = abs_matrix[np.where(np.abs(abs_matrix) > threshold)] normalization_factor = np.min(non_zero_elements) normalized_matrix = ising_matrix / normalization_factor abs_normalized_matrix = np.abs(normalized_matrix) scaling_factor_upper_limit = ( int(np.floor(2**bit_width / abs_normalized_matrix.max())) + 1 ) for i in range(1, scaling_factor_upper_limit): scaled_normalized_matrix = ising_matrix * i / normalization_factor if np.array_equal( np.around(scaled_normalized_matrix, decimals=0), np.around(scaled_normalized_matrix, decimals=8), ): for j in range(1, bit_width + 1): upper_bound = 2**j if np.around(scaled_normalized_matrix.max()) == upper_bound: continue if i < int(np.floor(upper_bound / abs_normalized_matrix.max())) + 1: return {"precision": j + 1, "multiplier": i / normalization_factor} return {"precision": np.inf, "multiplier": np.inf}
[文档] @track_data() def adjust_ising_matrix_precision(ising_matrix, bit_width=8): """调整 ising 矩阵精度, 通过此接口调整后矩阵可能会有较大的精度损失,比如矩阵有一个数远大于其它数时,调整后矩阵精度损失严重无法使用 Args: ising_matrix(np.ndarray): 目标矩阵 bit_width(int): 精度范围,目前只支持8位,有一位是符号位 Returns: np.ndarray: 符合精度要求的 ising 矩阵 Examples: >>> import numpy as np >>> import kaiwu as kw >>> ori_ising_mat1 = np.array([[0, 0.22, 0.198], ... [0.22, 0, 0.197], ... [0.198, 0.197, 0]]) >>> ising_mat1 = kw.preprocess.adjust_ising_matrix_precision(ori_ising_mat1) >>> ising_mat1 array([[ 0, 127, 114], [127, 0, 114], [114, 114, 0]]) >>> ori_ising_mat2 = np.array([[0, 0.22, 0.198], ... [0.22, 0, 50], ... [0.198, 50, 0]]) >>> ising_mat2 = kw.preprocess.adjust_ising_matrix_precision(ori_ising_mat2) >>> ising_mat2 # The solutions obtained by qubo_mat2 and ori_qubo_mat2 matrices are quite different array([[ 0, 1, 1], [ 1, 0, 127], [ 1, 127, 0]]) """ # 校验矩阵精度范围,如何符合要求直接返回 result = calculate_ising_matrix_bit_width(ising_matrix, bit_width) if result.get("precision") > bit_width: # 保留一位符号位 bit_width = bit_width - 1 # 取绝对值 abs_matrix = np.abs(ising_matrix) # 缩放因子 factor = (2**bit_width - 1) / abs_matrix.max() # 小数位数 decimal_bit_width = 0 # 符合精度要求的ising矩阵 ising_matrix = np.round( factor * ising_matrix * pow(2, decimal_bit_width) ).astype(int) return ising_matrix
[文档] @track_data() def calculate_qubo_matrix_bit_width(qubo_matrix, bit_width=8): """校验QUBO矩阵元素位宽 将QUBO矩阵转为伊辛矩阵,通过校验伊辛矩阵的元素位宽来实现对QUBO矩阵的校验 Args: qubo_matrix (np.ndarray): QUBO矩阵 bit_width (int): 位宽 Returns: np.ndarray: 符合精度要求的 ising 矩阵 Examples1: >>> import numpy as np >>> import kaiwu as kw >>> _matrix = -np.array([[-480., 508., -48.], ... [ 508., -508., -48.], ... [ -48., -48., 60.]]) >>> kw.preprocess.calculate_qubo_matrix_bit_width(_matrix) {'precision': 8, 'multiplier': np.float64(1.0)} Examples2(缩放后符合要求): >>> import numpy as np >>> import kaiwu as kw >>> _matrix = -np.array([[-512., 520., -48.], ... [ 520., -520., -48.], ... [ -48., -48., 40.]]) >>> kw.preprocess.calculate_qubo_matrix_bit_width(_matrix) {'precision': 8, 'multiplier': np.float64(0.5)} Examples3(缩放后也不符合要求): >>> import numpy as np >>> import kaiwu as kw >>> _matrix = -np.array([[-488., 516., -48.], ... [ 516., -516., -48.], ... [ -48., -48., 60.]]) >>> kw.preprocess.calculate_qubo_matrix_bit_width(_matrix) {'precision': inf, 'multiplier': inf} """ # qubo模型转ising ising_matrix, _ = qubo_matrix_to_ising_matrix(qubo_matrix) return calculate_ising_matrix_bit_width(ising_matrix, bit_width)
[文档] @track_data() def adjust_qubo_matrix_precision(qubo_matrix, bit_width=8): """调整矩阵精度, 通过此接口调整后矩阵可能会有较大的精度损失,比如矩阵有一个数远大于其它数时,调整后矩阵精度损失严重无法使用 Args: qubo_matrix (np.ndarray): 目标矩阵 bit_width (int): 精度范围,目前只支持8位,有一位是符号位 Returns: np.ndarray: 符合精度要求的QUBO矩阵 Examples: >>> import numpy as np >>> import kaiwu as kw >>> ori_qubo_mat1 = np.array([[0.89, 0.22, 0.198], ... [0.22, 0.23, 0.197], ... [0.198, 0.197, 0.198]]) >>> qubo_mat1 = kw.preprocess.adjust_qubo_matrix_precision(ori_qubo_mat1) >>> qubo_mat1 array([[348., 168., 152.], [ -0., 92., 152.], [ -0., -0., 80.]]) >>> ori_qubo_mat2 = np.array([[0.89, 0.22, 0.198], ... [0.22, 0.23, 0.197], ... [0.198, 0.197, 100]]) >>> qubo_mat2 = kw.preprocess.adjust_qubo_matrix_precision(ori_qubo_mat2) >>> qubo_mat2 # The solutions obtained by qubo_mat2 and ori_qubo_mat2 matrices are quite different array([[ 8., -0., -0.], [ -0., 4., -0.], [ -0., -0., 508.]]) """ # qubo矩阵转ising ising_matrix, _ = qubo_matrix_to_ising_matrix(qubo_matrix) # 校验矩阵精度范围,如何符合要求直接返回 result = calculate_ising_matrix_bit_width(ising_matrix) if result.get("precision") > bit_width: _ising_matrix = adjust_ising_matrix_precision(ising_matrix, bit_width) # 符合精度要求的qubo矩阵 qubo_matrix, _ = ising_matrix_to_qubo_matrix(_ising_matrix) return qubo_matrix
if __name__ == "__main__": import doctest doctest.testmod()