138 lines
3.8 KiB
Python
138 lines
3.8 KiB
Python
import enum
|
|
from functools import cached_property
|
|
from dataclasses import dataclass
|
|
from typing import Iterator
|
|
from common import DeviceKind, Circuit
|
|
|
|
|
|
class ResponsePriority(enum.Enum):
|
|
"""
|
|
The priority of the result.
|
|
"""
|
|
|
|
LESS_DEVICES = enum.auto()
|
|
"""Less devices is the first priority."""
|
|
MORE_ACCURACY = enum.auto()
|
|
"""More accuracy is the first priority."""
|
|
|
|
|
|
@dataclass
|
|
class Request:
|
|
"""
|
|
All request infomation for the resolver.
|
|
"""
|
|
|
|
device_kind: DeviceKind
|
|
"""The kind of device to resolve."""
|
|
target_value: float
|
|
"""The target value of the device."""
|
|
tolerance: float
|
|
"""The tolerance of the device in absolute value."""
|
|
response_priority: ResponsePriority
|
|
"""The priority principle when sorting response items."""
|
|
count_limit: int
|
|
"""The limited count of results."""
|
|
|
|
|
|
class ResponseItem:
|
|
"""
|
|
The possible solution given by the resolver.
|
|
"""
|
|
|
|
__circuit: Circuit
|
|
"""The circuit of the response item."""
|
|
__device_kind: DeviceKind
|
|
"""The kind of device of this circuit."""
|
|
__target_value: float
|
|
"""The target value of this circuit."""
|
|
|
|
def __init__(
|
|
self, circuit: Circuit, device_kind: DeviceKind, target_value: float
|
|
) -> None:
|
|
self.__circuit = circuit
|
|
self.__device_kind = device_kind
|
|
self.__target_value = target_value
|
|
|
|
@property
|
|
def circuit(self) -> Circuit:
|
|
"""
|
|
The circuit of this response item.
|
|
|
|
:return: The circuit.
|
|
"""
|
|
return self.circuit
|
|
|
|
@cached_property
|
|
def device_count(self) -> int:
|
|
"""
|
|
The device count of this circuit.
|
|
|
|
:return: The device count.
|
|
"""
|
|
return self.circuit.device_scale.to_device_count()
|
|
|
|
@cached_property
|
|
def value(self) -> float:
|
|
"""
|
|
The value of this circuit.
|
|
|
|
:return: The value.
|
|
"""
|
|
return self.__circuit.compute(self.__device_kind)
|
|
|
|
@cached_property
|
|
def difference(self) -> float:
|
|
"""
|
|
The absolute difference between the target value and the value of this circuit.
|
|
|
|
:return: The absolute difference.
|
|
"""
|
|
return abs(self.__target_value - self.value)
|
|
|
|
@cached_property
|
|
def relative_difference(self) -> float:
|
|
"""
|
|
The relative difference between the target value and the value of this circuit.
|
|
|
|
:return: The relative difference.
|
|
"""
|
|
return self.difference / self.__target_value
|
|
|
|
|
|
class Response:
|
|
"""
|
|
The collection of possible solutions given by the resolver.
|
|
|
|
For getting the response items, please use `response[index]`.
|
|
For iterating the response items, please use the iterator protocol.
|
|
For getting the count of response items, please use the ``len`` function.
|
|
"""
|
|
|
|
__sorted_items: list[ResponseItem]
|
|
"""The sorted items by priority and difference."""
|
|
|
|
def __init__(self, request: Request, candidates: Iterator[Circuit]) -> None:
|
|
self.__sorted_items = list(
|
|
ResponseItem(item, request.device_kind, request.target_value)
|
|
for item in candidates
|
|
)
|
|
|
|
# Sort by different strategy
|
|
match request.response_priority:
|
|
case ResponsePriority.LESS_DEVICES:
|
|
self.__sorted_items.sort(key=lambda x: (x.device_count, x.difference))
|
|
case ResponsePriority.MORE_ACCURACY:
|
|
self.__sorted_items.sort(key=lambda x: x.difference)
|
|
|
|
# Cut item by limit
|
|
self.__sorted_items = self.__sorted_items[:request.count_limit]
|
|
|
|
def __getitem__(self, index: int) -> ResponseItem:
|
|
return self.__sorted_items[index]
|
|
|
|
def __len__(self) -> int:
|
|
return len(self.__sorted_items)
|
|
|
|
def __iter__(self) -> Iterator[ResponseItem]:
|
|
return iter(self.__sorted_items)
|