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 {
#[error("{0}")]
BfsResolver(#[from] bfs::BfsResolverError),
#[error("a")]
LutResolver,
#[error("{0}")]
LutResolver(#[from] lut::LutResolverError),
}
/// Abstract base trait for all resolvers.

View File

@@ -170,7 +170,7 @@ impl ResultBucket {
/// Consume the bucket and return all stored items.
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.

View File

@@ -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<f64>,
}
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<Self, LcrConnError> {
pub fn new(circuit: Circuit, device_kind: DeviceKind) -> Result<Self, LutResolverError> {
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<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 {
/// Create a new LUT resolver by building lookup tables from the given datasets.
///
/// # Errors
///
/// See [`LutItem::new`].
pub fn new(datasets: &DatasetCollection) -> Result<Self, LcrConnError> {
pub fn new(datasets: &DatasetCollection) -> Result<Self, LutResolverError> {
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<Vec<LutItem>, LcrConnError> {
let mut lut: Vec<LutItem> = 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<Vec<LutItem>, 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, LutResolverError> { LutItem::new(circuit?, device_kind) })
.collect::<Result<Vec<_>, _>>()?;
// 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<Response, LcrConnError> {
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<Response, LutResolverError> {
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<Circuit> = 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
} 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()))?;
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 {
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<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)
# 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)