"""
模块: dynamic_range
功能: 估计Ising模型的上下界
"""
import numpy as np
from kaiwu.classical import SimulatedAnnealingOptimizer
from kaiwu.preprocess._utils import _partial_assignment
from kaiwu.license import track_data
[文档]
@track_data()
def lower_bound_parameters(ising_mat):
"""所有系数绝对值的和取负,确定Ising模型哈密顿量的下界
Args:
ising_mat (np.ndarray): Ising矩阵
Returns:
float: 哈密顿量的下界
Examples:
>>> import numpy as np
>>> import kaiwu as kw
>>> mat = np.array([[0, 18, -12],
... [18, 0, 1],
... [-12, 1, 0]])
>>> lb = kw.preprocess.lower_bound_parameters(mat)
>>> lb
np.int64(-62)
"""
return _lower_bound_parameters(ising_mat)
def _lower_bound_parameters(ising_mat):
"""所有系数绝对值的和取负,确定Ising模型哈密顿量的下界"""
return -np.abs(ising_mat).sum()
[文档]
@track_data()
def upper_bound_sample(ising_matrix, steps=10):
"""基于采样估计哈密顿量的上界
Args:
ising_matrix (np.ndarray): Ising矩阵
steps (int): 步数
Returns:
float: 哈密顿量的上界
Examples:
>>> import numpy as np
>>> import kaiwu as kw
>>> mat = np.array([[0, 18, -12],
... [18, 0, 1],
... [-12, 1, 0]])
>>> ub = kw.preprocess.upper_bound_sample(mat)
"""
return _upper_bound_sample(ising_matrix, steps=steps)
def _upper_bound_sample(ising_matrix, steps=10):
"""基于采样估计哈密顿量的上界"""
solution = np.random.randint(0, 2, (ising_matrix.shape[0],)) * 2 - 1
min_h = -solution.dot(ising_matrix).dot(solution)
for _ in range(steps):
solution = np.random.randint(0, 2, (ising_matrix.shape[0],)) * 2 - 1
hamilton = -solution.dot(ising_matrix).dot(solution)
min_h = min(min_h, hamilton)
return min_h
[文档]
@track_data()
def upper_bound_simulated_annealing(ising_matrix):
"""基于模拟退火估计哈密顿量的上界
Args:
ising_matrix (np.ndarray): Ising矩阵
Returns:
float: 哈密顿量的上界
Examples:
>>> import numpy as np
>>> import kaiwu as kw
>>> mat = np.array([[0, 18, -12],
... [18, 0, 1],
... [-12, 1, 0]])
>>> ub = kw.preprocess.upper_bound_simulated_annealing(mat)
"""
optimizer = SimulatedAnnealingOptimizer(size_limit=1)
solution = optimizer.solve(ising_matrix)[0]
return -solution.dot(ising_matrix).dot(solution)
LOWER_BOUND = {
# 'roof_dual': lower_bound_roof_dual,
"min_sum": _lower_bound_parameters
}
UPPER_BOUND = {
"simulated_annealing": upper_bound_simulated_annealing,
"sample": _upper_bound_sample,
}
def _compute_pre_opt_bounds(ising_matrix, i, j):
lower_bound = LOWER_BOUND["min_sum"]
upper_bound = UPPER_BOUND["sample"]
change_diff = 1e-08
# Define sub-qubos
ising_matrix = (ising_matrix + ising_matrix.T) / 2
mat_nn, bias_nn = _partial_assignment(ising_matrix, [i, j], [-1, -1])
mat_np, bias_np = _partial_assignment(ising_matrix, [i, j], [-1, 1])
mat_pn, bias_pn = _partial_assignment(ising_matrix, [i, j], [1, -1])
mat_pp, bias_pp = _partial_assignment(ising_matrix, [i, j], [1, 1])
# compute bounds
upper_nn = upper_bound(mat_nn) - bias_nn
upper_np = upper_bound(mat_np) - bias_np
upper_pn = upper_bound(mat_pn) - bias_pn
upper_pp = upper_bound(mat_pp) - bias_pp
upper_p = min(upper_nn, upper_pp)
upper_n = min(upper_np, upper_pn)
lower_nn = lower_bound(mat_nn) - bias_nn
lower_np = lower_bound(mat_np) - bias_np
lower_pn = lower_bound(mat_pn) - bias_pn
lower_pp = lower_bound(mat_pp) - bias_pp
lower_p = min(lower_nn, lower_pp)
lower_n = min(lower_np, lower_pn)
coefficient_upper_bound = (
float("inf") if lower_n > upper_p else (lower_p - upper_n - change_diff) / 2
)
coefficient_lower_bound = (
-float("inf") if lower_p > upper_n else (upper_p - lower_n + change_diff) / 2
)
return coefficient_lower_bound, coefficient_upper_bound
if __name__ == "__main__":
import doctest
doctest.testmod()