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 the iterator protocol. """ __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 __iter__(self) -> Iterator[ResponseItem]: return iter(self.__sorted_items)