fix: fix kernel lut build issue
This commit is contained in:
@@ -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.
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user