From bbd47006d451baa20f9d061412d81868875f4e05 Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Mon, 29 Jun 2026 20:10:23 +0800 Subject: [PATCH] fix: fix kernel lut build issue --- kernel/lcrconn/src/resolver.rs | 4 +- kernel/lcrconn/src/resolver/bfs.rs | 2 +- kernel/lcrconn/src/resolver/lut.rs | 225 ++++++++++++++++------- legacy/src/lcr_connector/resolver/lut.py | 8 +- 4 files changed, 162 insertions(+), 77 deletions(-) diff --git a/kernel/lcrconn/src/resolver.rs b/kernel/lcrconn/src/resolver.rs index f4a1e18..aa0a587 100644 --- a/kernel/lcrconn/src/resolver.rs +++ b/kernel/lcrconn/src/resolver.rs @@ -9,8 +9,8 @@ use thiserror::Error as TeError; pub enum ResolverError { #[error("{0}")] BfsResolver(#[from] bfs::BfsResolverError), - #[error("a")] - LutResolver, + #[error("{0}")] + LutResolver(#[from] lut::LutResolverError), } /// Abstract base trait for all resolvers. diff --git a/kernel/lcrconn/src/resolver/bfs.rs b/kernel/lcrconn/src/resolver/bfs.rs index 4a42b5a..20585f3 100644 --- a/kernel/lcrconn/src/resolver/bfs.rs +++ b/kernel/lcrconn/src/resolver/bfs.rs @@ -170,7 +170,7 @@ impl ResultBucket { /// Consume the bucket and return all stored items. pub fn into_iter(self) -> impl Iterator { - self.heap.into_iter().map(|entry| entry.item) + self.heap.into_iter().map(|entry| entry.into_bfs_item()) } /// Insert a [`BfsItem`] with the given score. diff --git a/kernel/lcrconn/src/resolver/lut.rs b/kernel/lcrconn/src/resolver/lut.rs index 762f291..fc50f31 100644 --- a/kernel/lcrconn/src/resolver/lut.rs +++ b/kernel/lcrconn/src/resolver/lut.rs @@ -1,28 +1,38 @@ -use std::cmp::Ordering; - use super::bfs::BfsResolver; -use super::Resolver; -use crate::common::{Circuit, CircuitCalculator, DeviceKind, LcrConnError}; +use super::{Resolver, ResolverError}; +use crate::common::{Circuit, CircuitCalculator, CircuitCalculatorError, CircuitError, DeviceKind}; use crate::dataset::{Dataset, DatasetCollection}; -use crate::query::{Request, Response}; +use crate::query::{Request, Response, ResponseError}; +use ordered_float::OrderedFloat; +use thiserror::Error as TeError; + +/// Errors occurs in LUT resolver. +#[derive(Debug, TeError)] +pub enum LutResolverError { + #[error("failed to build circuit: {0}")] + Circuit(#[from] CircuitError), + #[error("failed on computing circuit properties: {0}")] + CircuitCalculator(#[from] CircuitCalculatorError), + #[error("fail to build response: {0}")] + Response(#[from] ResponseError), +} /// An item in the lookup table. pub struct LutItem { /// The circuit represented by this item. circuit: Circuit, /// The value of this circuit. - value: f64, + value: OrderedFloat, } impl LutItem { /// Create a new LUT item by computing the circuit value. - /// - /// # Errors - /// - /// See [`Circuit::compute`]. - pub fn new(circuit: Circuit, device_kind: DeviceKind) -> Result { + pub fn new(circuit: Circuit, device_kind: DeviceKind) -> Result { let value = circuit.compute(device_kind)?; - Ok(Self { circuit, value }) + Ok(Self { + circuit, + value: OrderedFloat(value), + }) } /// The circuit represented by this item. @@ -32,7 +42,76 @@ impl LutItem { /// The value of this circuit. pub fn value(&self) -> f64 { - self.value + self.value.0 + } +} + +/// The ranged index for bisect LUT finding in resolver. +#[derive(Debug, Clone)] +pub struct RangedIndex { + pos: Option, + lower_bound: usize, + upper_bound: usize, +} + +impl RangedIndex { + /// Build ranged index with position, lower and upper bound. + pub fn new(pos: usize, lower_bound: usize, upper_bound: usize) -> Self { + let pos = if pos < lower_bound || pos > upper_bound { + None + } else { + Some(pos) + }; + + Self { + pos, + lower_bound, + upper_bound, + } + } + + /// Check if the index is in range. True if it is, otherwise false. + pub fn in_range(&self) -> bool { + self.pos.is_some() + } + + /// Get the index as usize. + /// + /// # Panics + /// + /// Panic if index is out of range. + pub fn position(&self) -> usize { + self.pos.expect("unexpected out of range index") + } + + /// Increment the index. Return true if the index is advanced. + pub fn inc(&mut self) -> bool { + match self.pos { + Some(pos) => { + self.pos = if pos >= self.upper_bound { + None + } else { + Some(pos + 1) + }; + true + } + None => false, + } + } + + /// Decrement the index. Return true if the index is advanced. + pub fn dec(&mut self) -> bool { + match self.pos { + Some(pos) => { + self.pos = if pos <= self.lower_bound { + None + } else { + Some(pos - 1) + }; + true + } + None => false, + } } } @@ -48,11 +127,7 @@ pub struct LutResolver { impl LutResolver { /// Create a new LUT resolver by building lookup tables from the given datasets. - /// - /// # Errors - /// - /// See [`LutItem::new`]. - pub fn new(datasets: &DatasetCollection) -> Result { + pub fn new(datasets: &DatasetCollection) -> Result { Ok(Self { resistor_lut: Self::build_lut(datasets.resistor_dataset(), DeviceKind::Resistor)?, capacitor_lut: Self::build_lut(datasets.capacitor_dataset(), DeviceKind::Capacitor)?, @@ -60,18 +135,20 @@ impl LutResolver { }) } - fn build_lut(dataset: &Dataset, device_kind: DeviceKind) -> Result, LcrConnError> { - let mut lut: Vec = Vec::new(); - - let circuits = BfsResolver::iter_one_device_circuit(dataset) - .chain(BfsResolver::iter_two_devices_circuit(dataset)) - .chain(BfsResolver::iter_three_devices_circuit(dataset)); - - for circuit in circuits { - lut.push(LutItem::new(circuit, device_kind)?); - } - - lut.sort_by(|a, b| a.value.partial_cmp(&b.value).unwrap_or(Ordering::Equal)); + fn build_lut( + dataset: &Dataset, + device_kind: DeviceKind, + ) -> Result, LutResolverError> { + // Fetch all items + let mut lut = itertools::chain!( + BfsResolver::iter_one_device_circuit(&dataset), + BfsResolver::iter_two_devices_circuit(&dataset), + BfsResolver::iter_three_devices_circuit(&dataset) + ) + .map(|circuit| -> Result { LutItem::new(circuit?, device_kind) }) + .collect::, _>>()?; + // Sort them and return + lut.sort_by(|a, b| a.value.cmp(&b.value)); Ok(lut) } @@ -82,75 +159,87 @@ impl LutResolver { DeviceKind::Inductor => &self.inductor_lut, } } -} -impl Resolver for LutResolver { - fn resolve(&self, request: &Request) -> Result { - let lut = self.pick_lut(request.device_kind); - let target = request.target_value; - let count_limit = request.count_limit; + fn intern_resolve(&self, request: &Request) -> Result { + let lut = self.pick_lut(request.get_device_kind()); + let target = OrderedFloat(request.get_target_value()); + let count_limit = request.get_count_limit(); let mut bucket: Vec = Vec::new(); // Locate the insertion point of target in the sorted LUT. // left/right start at the two nearest neighbours and expand outward. + let lower_bound = 0; + let upper_bound = lut.len() - 1; let idx = lut.partition_point(|item| item.value < target); + let mut left = RangedIndex::new(idx, lower_bound, upper_bound); + let mut right = left.clone(); + left.dec(); // Expand outward non-symmetrically: at each step compare the two // candidates on each side and advance the one that is closer to the // target. This guarantees items are visited in strictly increasing // difference order, so the first N items within tolerance are exactly // the N best matches. - let mut left = idx as isize - 1; - let mut right = idx as isize; - let lut_len = lut.len() as isize; - - let ccalc = CircuitCalculator::new(request.device_kind, target); - - while left >= 0 || right < lut_len { + let ccalc = CircuitCalculator::new(request.get_device_kind(), target.0)?; + loop { + // Check result count if bucket.len() >= count_limit { break; } - let go_left = if left < 0 { - false - } else if right >= lut_len { - true + let go_left = if left.in_range() { + if right.in_range() { + let left_item = &lut[left.position()]; + let left_diff = ccalc.unsigned_difference( + left_item.circuit(), + Some(left_item.value()), + None, + )?; + let right_item = &lut[right.position()]; + let right_diff = ccalc.unsigned_difference( + right_item.circuit(), + Some(right_item.value()), + None, + )?; + left_diff <= right_diff + } else { + true + } } else { - let left_item = &lut[left as usize]; - let left_diff = - ccalc.unsigned_difference(left_item.circuit(), Some(left_item.value()))?; - let right_item = &lut[right as usize]; - let right_diff = ccalc - .unsigned_difference(right_item.circuit(), Some(right_item.value()))?; - left_diff <= right_diff + if right.in_range() { + false + } else { + break; + } }; let item = if go_left { - let item = &lut[left as usize]; - left -= 1; + let item = &lut[left.position()]; + left.dec(); item } else { - let item = &lut[right as usize]; - right += 1; + let item = &lut[right.position()]; + right.inc(); item }; - let diff = ccalc.unsigned_difference(item.circuit(), Some(item.value()))?; + let diff = ccalc.unsigned_difference(item.circuit(), Some(item.value()), None)?; // Since the LUT is sorted, values on each side only move further // from target as we advance. Once one side exceeds tolerance, - // the rest of that side is guaranteed out of range — disable it. - if diff > request.tolerance { - if go_left { - left = -1; - } else { - right = lut_len; - } - continue; + // the rest of that side is guaranteed out of range. + if diff > request.get_tolerance() { + break; } bucket.push(item.circuit().clone()); } - Response::new(request, bucket) + Ok(Response::new(request, bucket.into_iter())?) + } +} + +impl Resolver for LutResolver { + fn resolve(&self, request: &Request) -> Result { + Ok(self.intern_resolve(request)?) } } diff --git a/legacy/src/lcr_connector/resolver/lut.py b/legacy/src/lcr_connector/resolver/lut.py index 8d13d51..cb85bc5 100644 --- a/legacy/src/lcr_connector/resolver/lut.py +++ b/legacy/src/lcr_connector/resolver/lut.py @@ -121,13 +121,9 @@ class LutResolver(Resolver): diff = ccalc.unsigned_difference(item.circuit, value=item.value) # Since the LUT is sorted, values on each side only move further # from target as we advance. Once one side exceeds tolerance, - # the rest of that side is guaranteed out of range — disable it. + # the rest of that side is guaranteed out of range. if diff > request.tolerance: - if go_left: - left = -1 - else: - right = len(lut) - continue + break bucket.append(item.circuit)