1
0

feat: add response type

This commit is contained in:
2026-06-15 17:13:15 +08:00
parent ed8f5e1943
commit 1c81b24f74
5 changed files with 141 additions and 46 deletions

129
legacy/query.py Normal file
View File

@@ -0,0 +1,129 @@
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)

View File

@@ -1,11 +1,9 @@
from .common import Resolver, ResultPriority, ResolverRequest from .common import Resolver
from .lut import LutResolver from .lut import LutResolver
from .astar import AStarResolver from .astar import AStarResolver
__all__ = [ __all__ = [
'Resolver', 'Resolver',
'ResultPriority',
'ResolverRequest',
'LutResolver', 'LutResolver',
'AStarResolver' 'AStarResolver'
] ]

View File

@@ -1,5 +1,5 @@
from typing import Iterator from typing import Iterator
from .common import Resolver, ResolverRequest, ResultPriority from .common import Resolver, Request, ResultPriority
from ..dataset import DatasetCollection from ..dataset import DatasetCollection
from ..common import Circuit from ..common import Circuit
@@ -12,5 +12,5 @@ class AStarResolver(Resolver):
pass pass
def resolve(self, request: ResolverRequest) -> Iterator[Circuit]: def resolve(self, request: Request) -> Iterator[Circuit]:
pass pass

View File

@@ -1,38 +1,5 @@
import enum
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from dataclasses import dataclass from ..query import Request, Response
from typing import Iterator
from ..common import DeviceKind, Circuit
class ResultPriority(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 ResolverRequest:
"""
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."""
result_priority: ResultPriority
"""The priority of the result."""
count_limit: int
"""The limited count of results."""
class Resolver(ABC): class Resolver(ABC):
""" """
@@ -40,5 +7,5 @@ class Resolver(ABC):
""" """
@abstractmethod @abstractmethod
def resolve(self, request: ResolverRequest) -> Iterator[Circuit]: def resolve(self, request: Request) -> Response:
pass pass

View File

@@ -2,9 +2,10 @@ import heapq
from itertools import chain, product from itertools import chain, product
from typing import Iterable, Iterator from typing import Iterable, Iterator
from functools import cached_property from functools import cached_property
from .common import Resolver, ResolverRequest, ResultPriority from .common import Resolver
from ..dataset import DatasetCollection, Dataset from ..dataset import DatasetCollection, Dataset
from ..common import Circuit, DeviceKind, JointKind, LcrConnException from ..common import Circuit, DeviceKind, JointKind
from ..query import Request, Response
class LutItem: class LutItem:
@@ -73,7 +74,7 @@ class ResultBucket(Iterable[LutItem]):
"""The underlying LutItem.""" """The underlying LutItem."""
return self.__item return self.__item
def __lt__(self, other: 'ResultBucket.ResultBucketItem') -> bool: def __lt__(self, other: "ResultBucket.ResultBucketItem") -> bool:
# heapq is a min-heap: it always pops the smallest element. # heapq is a min-heap: it always pops the smallest element.
# We invert the comparison so that an item with a larger score # We invert the comparison so that an item with a larger score
# is considered "smaller", effectively turning the min-heap # is considered "smaller", effectively turning the min-heap
@@ -179,7 +180,7 @@ class LutResolver(Resolver):
) )
] ]
def resolve(self, request: ResolverRequest) -> Iterator[Circuit]: def resolve(self, request: Request) -> Response:
# Fetch LUT by device kind # Fetch LUT by device kind
lut: list[LutItem] lut: list[LutItem]
match request.device_kind: match request.device_kind:
@@ -202,4 +203,4 @@ class LutResolver(Resolver):
bucket.insert(item, difference) bucket.insert(item, difference)
# Return result # Return result
return map(lambda item: item.circuit, bucket) return Response(request, map(lambda item: item.circuit, bucket))