feat: use AI to migrate project (no fix now)
This commit is contained in:
156
kernel/lcrconn/src/resolver/lut.rs
Normal file
156
kernel/lcrconn/src/resolver/lut.rs
Normal file
@@ -0,0 +1,156 @@
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use super::bfs::BfsResolver;
|
||||
use super::Resolver;
|
||||
use crate::common::{Circuit, CircuitValueTrait, DeviceKind, LcrConnError};
|
||||
use crate::dataset::{Dataset, DatasetCollection};
|
||||
use crate::query::{Request, Response};
|
||||
|
||||
/// An item in the lookup table.
|
||||
pub struct LutItem {
|
||||
/// The circuit represented by this item.
|
||||
circuit: Circuit,
|
||||
/// The value of this circuit.
|
||||
value: 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> {
|
||||
let value = circuit.compute(device_kind)?;
|
||||
Ok(Self { circuit, value })
|
||||
}
|
||||
|
||||
/// The circuit represented by this item.
|
||||
pub fn circuit(&self) -> &Circuit {
|
||||
&self.circuit
|
||||
}
|
||||
|
||||
/// The value of this circuit.
|
||||
pub fn value(&self) -> f64 {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
/// A resolver that uses a lookup table to find the best matching circuit.
|
||||
pub struct LutResolver {
|
||||
/// The lookup table for resistors.
|
||||
resistor_lut: Vec<LutItem>,
|
||||
/// The lookup table for capacitors.
|
||||
capacitor_lut: Vec<LutItem>,
|
||||
/// The lookup table for inductors.
|
||||
inductor_lut: Vec<LutItem>,
|
||||
}
|
||||
|
||||
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> {
|
||||
Ok(Self {
|
||||
resistor_lut: Self::build_lut(datasets.resistor(), DeviceKind::Resistor)?,
|
||||
capacitor_lut: Self::build_lut(datasets.capacitor(), DeviceKind::Capacitor)?,
|
||||
inductor_lut: Self::build_lut(datasets.inductor(), DeviceKind::Inductor)?,
|
||||
})
|
||||
}
|
||||
|
||||
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));
|
||||
Ok(lut)
|
||||
}
|
||||
|
||||
fn pick_lut(&self, device_kind: DeviceKind) -> &[LutItem] {
|
||||
match device_kind {
|
||||
DeviceKind::Resistor => &self.resistor_lut,
|
||||
DeviceKind::Capacitor => &self.capacitor_lut,
|
||||
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;
|
||||
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 idx = lut.partition_point(|item| item.value < target);
|
||||
|
||||
// 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 cv_trait = CircuitValueTrait::new(request.device_kind, target);
|
||||
|
||||
while left >= 0 || right < lut_len {
|
||||
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 =
|
||||
cv_trait.unsigned_difference(left_item.circuit(), Some(left_item.value()))?;
|
||||
let right_item = &lut[right as usize];
|
||||
let right_diff = cv_trait
|
||||
.unsigned_difference(right_item.circuit(), Some(right_item.value()))?;
|
||||
left_diff <= right_diff
|
||||
};
|
||||
|
||||
let item = if go_left {
|
||||
let item = &lut[left as usize];
|
||||
left -= 1;
|
||||
item
|
||||
} else {
|
||||
let item = &lut[right as usize];
|
||||
right += 1;
|
||||
item
|
||||
};
|
||||
|
||||
let diff = cv_trait.unsigned_difference(item.circuit(), Some(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.
|
||||
if diff > request.tolerance {
|
||||
if go_left {
|
||||
left = -1;
|
||||
} else {
|
||||
right = lut_len;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
bucket.push(item.circuit().clone());
|
||||
}
|
||||
|
||||
Response::new(request, bucket)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user