feat: add response type
This commit is contained in:
129
legacy/query.py
Normal file
129
legacy/query.py
Normal 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)
|
||||||
@@ -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'
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
@@ -67,13 +68,13 @@ class ResultBucket(Iterable[LutItem]):
|
|||||||
def score(self) -> float:
|
def score(self) -> float:
|
||||||
"""The score associated with this item."""
|
"""The score associated with this item."""
|
||||||
return self.__score
|
return self.__score
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def item(self) -> LutItem:
|
def item(self) -> 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))
|
||||||
|
|||||||
Reference in New Issue
Block a user