import logging
from abc import ABC, abstractmethod
from enum import Enum
from typing import Generic, TypeVar, Any, Optional
from olc.alg.alg_context import AlgContext
from olc.utils.num_utils import NumUtils
T = TypeVar("T")
logger = logging.getLogger(__name__)
class AlgType(Enum):
FLOWDECISION = "FLOWDECISION"
ADMISSION = "ADMISSION"
class ParaName:
def __init__(self, key: str, default_value: Any, dynamic: bool = False):
self.key = key
self.default_value = default_value
self.dynamic = dynamic
class Algorithm(ABC, Generic[T]):
def __init__(self, alg_type: AlgType, auto: bool = False):
self.alg_type = alg_type
self.auto = auto
self.para_names: dict[str, ParaName] = {}
@abstractmethod
def make_decision(self, alg_context: AlgContext[T]) -> T:
pass
@abstractmethod
def check(self, params: dict[str, Any]) -> bool:
"""
算法参数检查
:param params: 需要检查的参数
:return:
"""
for key in params.keys():
if key not in self.para_names:
logger.warning(f"invalid parameter {key}")
return False
return True
def get_param(self, key: str) -> Optional[ParaName]:
return self.para_names.get(key, None)
def get_dynamic_param_key(self) -> list[str]:
"""
获取动态参数Key
:return: key list
"""
result = []
for key, para in self.para_names.items():
if para.dynamic:
result.append(key)
return result
def valid_min_max_param(
self, min_name: str, max_name: str, params: dict[str, Any]
) -> bool:
min_obj = params.get(min_name, None)
max_obj = params.get(max_name, None)
if min_obj is not None:
min_val = NumUtils.cast_to_float(min_obj)
else:
ins_min_param: Optional[ParaName] = self.get_param(min_name)
if ins_min_param is None:
logger.warning(f"params not fount key:{min_name}")
return False
min_val = NumUtils.cast_to_float(ins_min_param.default_value)
if max_obj is not None:
max_val = NumUtils.cast_to_float(max_obj)
else:
ins_max_param: Optional[ParaName] = self.get_param(max_name)
if ins_max_param is None:
logger.warning(f"params not fount key:{max_name}")
return False
max_val = NumUtils.cast_to_float(ins_max_param.default_value)
if max_val is None or min_val is None:
logger.warning(f"check error: {min_name} or {max_name} is None")
return False
if max_val < min_val:
logger.warning(f"check error: {min_name}:{min_val} > {max_name}:{max_val}")
return False
return True
def check_float_param(self, key: str, params: dict[str, Any]) -> bool:
param_obj = params.get(key, None)
if param_obj is None:
ins_param: Optional[ParaName] = self.get_param(key)
if ins_param is None:
logger.warning(f"params not fount key:{key}")
return False
return True