kaiwu.core._base_solver 源代码

"""
基础模块 Optimizer base class
"""

import logging
import abc
import numpy as np
from kaiwu.core._get_val import get_sol_dict
from kaiwu.core._model_converter import qubo_model_to_ising_model

logger = logging.getLogger(__name__)


[文档] def get_sorted_solutions( matrix, solutions, bias=0.0, negtail_ff=True, sort_solutions=True ): """最优解采样. Args: matrix (np.ndarray): Ising 矩阵. solutions (np.ndarray): 变量配置. bias (float): 常数项. negtail_ff (bool): negtail_flip flag 负尾翻转, Ising模型线性项二次化的矩阵需要负尾翻转. Returns: output (np.ndarray, np.ndarray): 按能量排序的变量配置, 能量. Examples: >>> import numpy as np >>> import kaiwu as kw >>> matrix = -np.array([[ 0. , 1. , 0. , 1. , 1. ], ... [ 1. , 0. , 0. , 1., 1. ], ... [ 0. , 0. , 0. , 1., 1. ], ... [ 1. , 1., 1. , 0. , 1. ], ... [ 1. , 1., 1. , 1. , 0. ]]) >>> solutions = np.array([[ 1, -1, 1, -1, -1], ... [-1, -1, 1, -1, -1], ... [-1, -1, -1, 1, 1], ... [ 1, 1, 1, -1, -1], ... [ 1, 1, 1, -1, -1], ... [ 1, 1, 1, -1, -1]]) >>> kw.core.get_sorted_solutions(matrix, solutions, 0) (array([[-1, -1, -1, 1, 1], [-1, -1, -1, 1, 1], [-1, -1, -1, 1, 1], [-1, -1, -1, 1, 1], [-1, 1, -1, 1, 1], [ 1, 1, -1, 1, 1]]), array([-8., -8., -8., -8., -4., 8.])) """ hamilton = -np.einsum("ij,ij->i", (solutions.dot(matrix)), solutions) + bias if sort_solutions: index = np.argsort(hamilton) solutions = solutions[index] hamilton = hamilton[index] if negtail_ff: solutions = solutions * solutions[:, [-1]] return solutions, hamilton
[文档] class IsingSolver: """ Ising求解器基类 """ def __init__(self): self.matrix = None self._hamiltonian = None
[文档] def set_matrix(self, ising_matrix): """设置矩阵并更新相关内容""" if ising_matrix is not None: self.matrix = ising_matrix self.on_matrix_change() logger.debug("Matrix set in the optimizer.") if self.matrix is None: raise ValueError("Ising matrix must be set")
[文档] def on_matrix_change(self): """ 更新矩阵相关信息, 继承IsingSolver时可以实现。当处理的ising矩阵发生变化时,这个函数的实现会被调用,从而有机会做相应动作 """ logger.debug( "Method on_matrix_change is not implemented in the class inherited from IsingSolver!" )
def _solve(self, ising_matrix=None): "求解逻辑" raise NotImplementedError
[文档] def solve(self, ising_matrix=None, negtail_flip=True, sort_solutions=False): """求解Ising矩阵 Args: ising_matrix (np.ndarray): Ising矩阵 negtail_flip (bool): 是否进行负尾翻转 sort_solutions (bool): 是否对解进行排序 Returns: output (np.ndarray): 解向量 """ self.set_matrix(ising_matrix) solutions = self._solve(self.matrix) if solutions is None: return None solutions, self._hamiltonian = get_sorted_solutions( self.matrix, solutions, 0, negtail_flip, sort_solutions ) return solutions
[文档] def get_hamiltonian(self): """ Returns: hamiltonian (np.ndarray): 当前解的哈密顿量值 """ return self._hamiltonian
class QuboSolverMeta(abc.ABCMeta): """Solver自定义元类""" def __new__(mcs, name, bases, namespace, **kwargs): if name != "Base" and "solve_qubo" in namespace: original_execute = namespace["solve_qubo"] def wrapped_execute(self, *args, **kwargs): result = original_execute(self, *args, **kwargs) if result[0] is None: logger.warning("No solution found!") return result namespace["solve_qubo"] = wrapped_execute return super().__new__(mcs, name, bases, namespace, **kwargs)
[文档] class QuboSolver(metaclass=QuboSolverMeta): """Solver基类 Args: optimizer (IsingSolver): Ising求解器 """ def _to_ising_matrix(self, qubo_model): ising_model = qubo_model_to_ising_model(qubo_model) ising_mat = ising_model.get_matrix() bias = ising_model.get_bias() vars_dict = ising_model.get_variables() return ising_mat, bias, vars_dict
[文档] def solve_qubo(self, qubo_model): """求解QUBO模型 Args: qubo_model (QuboModel): QUBO模型 sort_solutions (bool): 是否对解进行排序 Returns: tuple: QUBO解与哈密顿量 dict: 解字典 float: 当前解的哈密顿量值 """ if isinstance(self, IsingSolver): ising_mat, bias, vars_dict = self._to_ising_matrix(qubo_model) output = self.solve(ising_mat) if output is None: return None, None solutions, hamiltons = get_sorted_solutions( ising_mat, output, 0, negtail_ff=True, sort_solutions=True ) solution_dict = get_sol_dict( solutions[0][:-1] * solutions[0][-1], vars_dict ) return solution_dict, hamiltons[0] + bias raise NotImplementedError