1
0

fix: fix kernel lut build issue

This commit is contained in:
2026-06-29 20:10:23 +08:00
parent 4af8dd97a2
commit bbd47006d4
4 changed files with 162 additions and 77 deletions

View File

@@ -9,8 +9,8 @@ use thiserror::Error as TeError;
pub enum ResolverError { pub enum ResolverError {
#[error("{0}")] #[error("{0}")]
BfsResolver(#[from] bfs::BfsResolverError), BfsResolver(#[from] bfs::BfsResolverError),
#[error("a")] #[error("{0}")]
LutResolver, LutResolver(#[from] lut::LutResolverError),
} }
/// Abstract base trait for all resolvers. /// Abstract base trait for all resolvers.

View File

@@ -170,7 +170,7 @@ impl ResultBucket {
/// Consume the bucket and return all stored items. /// Consume the bucket and return all stored items.
pub fn into_iter(self) -> impl Iterator<Item = BfsItem> { pub fn into_iter(self) -> impl Iterator<Item = BfsItem> {
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. /// Insert a [`BfsItem`] with the given score.

View File

@@ -1,28 +1,38 @@
use std::cmp::Ordering;
use super::bfs::BfsResolver; use super::bfs::BfsResolver;
use super::Resolver; use super::{Resolver, ResolverError};
use crate::common::{Circuit, CircuitCalculator, DeviceKind, LcrConnError}; use crate::common::{Circuit, CircuitCalculator, CircuitCalculatorError, CircuitError, DeviceKind};
use crate::dataset::{Dataset, DatasetCollection}; 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. /// An item in the lookup table.
pub struct LutItem { pub struct LutItem {
/// The circuit represented by this item. /// The circuit represented by this item.
circuit: Circuit, circuit: Circuit,
/// The value of this circuit. /// The value of this circuit.
value: f64, value: OrderedFloat<f64>,
} }
impl LutItem { impl LutItem {
/// Create a new LUT item by computing the circuit value. /// Create a new LUT item by computing the circuit value.
/// pub fn new(circuit: Circuit, device_kind: DeviceKind) -> Result<Self, LutResolverError> {
/// # Errors
///
/// See [`Circuit::compute`].
pub fn new(circuit: Circuit, device_kind: DeviceKind) -> Result<Self, LcrConnError> {
let value = circuit.compute(device_kind)?; let value = circuit.compute(device_kind)?;
Ok(Self { circuit, value }) Ok(Self {
circuit,
value: OrderedFloat(value),
})
} }
/// The circuit represented by this item. /// The circuit represented by this item.
@@ -32,7 +42,76 @@ impl LutItem {
/// The value of this circuit. /// The value of this circuit.
pub fn value(&self) -> f64 { 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<usize>,
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 { impl LutResolver {
/// Create a new LUT resolver by building lookup tables from the given datasets. /// Create a new LUT resolver by building lookup tables from the given datasets.
/// pub fn new(datasets: &DatasetCollection) -> Result<Self, LutResolverError> {
/// # Errors
///
/// See [`LutItem::new`].
pub fn new(datasets: &DatasetCollection) -> Result<Self, LcrConnError> {
Ok(Self { Ok(Self {
resistor_lut: Self::build_lut(datasets.resistor_dataset(), DeviceKind::Resistor)?, resistor_lut: Self::build_lut(datasets.resistor_dataset(), DeviceKind::Resistor)?,
capacitor_lut: Self::build_lut(datasets.capacitor_dataset(), DeviceKind::Capacitor)?, 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<Vec<LutItem>, LcrConnError> { fn build_lut(
let mut lut: Vec<LutItem> = Vec::new(); dataset: &Dataset,
device_kind: DeviceKind,
let circuits = BfsResolver::iter_one_device_circuit(dataset) ) -> Result<Vec<LutItem>, LutResolverError> {
.chain(BfsResolver::iter_two_devices_circuit(dataset)) // Fetch all items
.chain(BfsResolver::iter_three_devices_circuit(dataset)); let mut lut = itertools::chain!(
BfsResolver::iter_one_device_circuit(&dataset),
for circuit in circuits { BfsResolver::iter_two_devices_circuit(&dataset),
lut.push(LutItem::new(circuit, device_kind)?); BfsResolver::iter_three_devices_circuit(&dataset)
} )
.map(|circuit| -> Result<LutItem, LutResolverError> { LutItem::new(circuit?, device_kind) })
lut.sort_by(|a, b| a.value.partial_cmp(&b.value).unwrap_or(Ordering::Equal)); .collect::<Result<Vec<_>, _>>()?;
// Sort them and return
lut.sort_by(|a, b| a.value.cmp(&b.value));
Ok(lut) Ok(lut)
} }
@@ -82,75 +159,87 @@ impl LutResolver {
DeviceKind::Inductor => &self.inductor_lut, DeviceKind::Inductor => &self.inductor_lut,
} }
} }
}
impl Resolver for LutResolver { fn intern_resolve(&self, request: &Request) -> Result<Response, LutResolverError> {
fn resolve(&self, request: &Request) -> Result<Response, LcrConnError> { let lut = self.pick_lut(request.get_device_kind());
let lut = self.pick_lut(request.device_kind); let target = OrderedFloat(request.get_target_value());
let target = request.target_value; let count_limit = request.get_count_limit();
let count_limit = request.count_limit;
let mut bucket: Vec<Circuit> = Vec::new(); let mut bucket: Vec<Circuit> = Vec::new();
// Locate the insertion point of target in the sorted LUT. // Locate the insertion point of target in the sorted LUT.
// left/right start at the two nearest neighbours and expand outward. // 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 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 // Expand outward non-symmetrically: at each step compare the two
// candidates on each side and advance the one that is closer to the // candidates on each side and advance the one that is closer to the
// target. This guarantees items are visited in strictly increasing // target. This guarantees items are visited in strictly increasing
// difference order, so the first N items within tolerance are exactly // difference order, so the first N items within tolerance are exactly
// the N best matches. // the N best matches.
let mut left = idx as isize - 1; let ccalc = CircuitCalculator::new(request.get_device_kind(), target.0)?;
let mut right = idx as isize; loop {
let lut_len = lut.len() as isize; // Check result count
let ccalc = CircuitCalculator::new(request.device_kind, target);
while left >= 0 || right < lut_len {
if bucket.len() >= count_limit { if bucket.len() >= count_limit {
break; break;
} }
let go_left = if left < 0 { let go_left = if left.in_range() {
false if right.in_range() {
} else if right >= lut_len { let left_item = &lut[left.position()];
true let left_diff = ccalc.unsigned_difference(
} else { left_item.circuit(),
let left_item = &lut[left as usize]; Some(left_item.value()),
let left_diff = None,
ccalc.unsigned_difference(left_item.circuit(), Some(left_item.value()))?; )?;
let right_item = &lut[right as usize]; let right_item = &lut[right.position()];
let right_diff = ccalc let right_diff = ccalc.unsigned_difference(
.unsigned_difference(right_item.circuit(), Some(right_item.value()))?; right_item.circuit(),
Some(right_item.value()),
None,
)?;
left_diff <= right_diff left_diff <= right_diff
} else {
true
}
} else {
if right.in_range() {
false
} else {
break;
}
}; };
let item = if go_left { let item = if go_left {
let item = &lut[left as usize]; let item = &lut[left.position()];
left -= 1; left.dec();
item item
} else { } else {
let item = &lut[right as usize]; let item = &lut[right.position()];
right += 1; right.inc();
item 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 // Since the LUT is sorted, values on each side only move further
// from target as we advance. Once one side exceeds tolerance, // 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 diff > request.get_tolerance() {
if go_left { break;
left = -1;
} else {
right = lut_len;
}
continue;
} }
bucket.push(item.circuit().clone()); 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<Response, ResolverError> {
Ok(self.intern_resolve(request)?)
} }
} }

View File

@@ -121,13 +121,9 @@ class LutResolver(Resolver):
diff = ccalc.unsigned_difference(item.circuit, value=item.value) diff = ccalc.unsigned_difference(item.circuit, value=item.value)
# Since the LUT is sorted, values on each side only move further # Since the LUT is sorted, values on each side only move further
# from target as we advance. Once one side exceeds tolerance, # 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 diff > request.tolerance:
if go_left: break
left = -1
else:
right = len(lut)
continue
bucket.append(item.circuit) bucket.append(item.circuit)