1
0
Files
LCRConnector/legacy/resolver/lut.py

110 lines
3.0 KiB
Python
Raw Normal View History

2026-06-02 21:08:48 +08:00
import struct
from typing import Iterator, BinaryIO
from pathlib import Path
from .common import Resolver, ResolverRequest, ResolverResult, ResultPriority
2026-06-15 13:47:31 +08:00
from ..dataset import DatasetCollection
from ..common import Circuit, SubCircuit, JointKind, LcrConnException
2026-06-02 21:08:48 +08:00
class LutResolver(Resolver):
"""
A resolver that uses a lookup table to find the best matching circuit.
"""
lut: tuple[Circuit]
def __init__(self, lut: tuple[Circuit]):
self.lut = lut
@staticmethod
2026-06-15 13:47:31 +08:00
def from_dataset(dataset: DatasetCollection) -> 'LutResolver':
2026-06-02 21:08:48 +08:00
pass
@staticmethod
def from_cache(filename: Path) -> 'LutResolver':
with open(filename, "rb") as f:
cnt = _read_int(f)
return LutResolver(tuple(LutItem.from_cache(f) for _ in range(cnt)))
def save_as_cache(self, filename: Path) -> None:
with open(filename, "wb") as f:
_write_int(f, len(self.lut))
for item in self.lut:
item.save_as_cache(f)
def resolve(self, request: ResolverRequest) -> Iterator[ResolverResult]:
pass
class LutItem:
"""
An item in the lookup table.
"""
circuit: Circuit
"""The circuit represented by this item."""
__value_cache: float | None
"""The cached computed value of the circuit, or None if it has not been cached yet."""
def __init__(self, circuit: Circuit):
self.circuit = circuit
@staticmethod
def from_cache(f: BinaryIO) -> 'LutItem':
cnt = _read_int(f)
if cnt < 1:
raise LcrConnException("Invalid circuit count in LUT item")
device_value = _read_double(f)
circuit = Circuit(device_value)
cnt -= 1
for _ in range(cnt):
j = JointKind.SERIES if _read_bool(f) else JointKind.PARALLEL
dev = _read_double(f)
2026-06-15 13:47:31 +08:00
joint = SubCircuit(j, dev)
2026-06-02 21:08:48 +08:00
circuit.add_joint(joint)
return LutItem(circuit)
def save_as_cache(self, f: BinaryIO) -> None:
_write_int(f, self.circuit.len_devices())
2026-06-15 13:47:31 +08:00
_write_double(f, self.circuit.__first_device_value)
2026-06-02 21:08:48 +08:00
for joint in self.circuit.joints():
_write_bool(f, joint.kind == JointKind.SERIES)
_write_double(f, joint.value)
def compute(self) -> float:
"""The computed value of the circuit."""
if self.__value_cache is None:
self.__value_cache = self.circuit.value()
return self.__value_cache
DOUBLE_PACKER = struct.Struct("d")
INT_PACKER = struct.Struct("I")
BOOL_PACKER = struct.Struct("?")
def _read_double(fs) -> float:
return DOUBLE_PACKER.unpack(fs.read(DOUBLE_PACKER.size))[0]
def _read_int(fs) -> int:
return INT_PACKER.unpack(fs.read(INT_PACKER.size))[0]
def _read_bool(fs) -> bool:
return BOOL_PACKER.unpack(fs.read(BOOL_PACKER.size))[0]
def _write_double(fs, num: float):
fs.write(DOUBLE_PACKER.pack(num))
def _write_int(fs, num: int):
fs.write(INT_PACKER.pack(num))
def _write_bool(fs, num: bool):
fs.write(BOOL_PACKER.pack(num))