refactor: refactor kernel common to have better code

This commit is contained in:
2026-07-22 11:57:56 +08:00
parent 5bfdfb71c2
commit 3dd8275787
5 changed files with 87 additions and 179 deletions
+3 -3
View File
@@ -2,7 +2,7 @@ use crate::cli::{AppConfig, AppResolver};
use anyhow::Result; use anyhow::Result;
use lcrconn::{ use lcrconn::{
BfsResolver, DeviceKind, LutResolver, Request, Resolver, Response, ResponsePriority, BfsResolver, DeviceKind, LutResolver, Request, Resolver, Response, ResponsePriority,
common::{Circuit, CircuitDeviceScale, JointKind, sanitize_device_value, sanitize_floating_point}, common::{Circuit, CircuitDeviceScale, JointKind, validate_device_value, validate_floating_point},
dataset::{DatasetCollection, from_human_readable_value, to_human_readable_value}, dataset::{DatasetCollection, from_human_readable_value, to_human_readable_value},
query::MAX_RESPONSE_CNT, query::MAX_RESPONSE_CNT,
}; };
@@ -310,7 +310,7 @@ impl App {
let value = self.parse_plain_float(pct_str, |x| *x >= 0.0 && *x <= 100.0); let value = self.parse_plain_float(pct_str, |x| *x >= 0.0 && *x <= 100.0);
value value
.map(|v| v / 100.0 * target_value) .map(|v| v / 100.0 * target_value)
.map(|v| sanitize_device_value(v)) .map(|v| validate_device_value(v))
.transpose() .transpose()
.ok() .ok()
.flatten() .flatten()
@@ -349,7 +349,7 @@ impl App {
Ok(value) => value, Ok(value) => value,
Err(_) => return None, Err(_) => return None,
}; };
let value = sanitize_floating_point(value).ok()?; let value = validate_floating_point(value).ok()?;
if checker(&value) { Some(value) } else { None } if checker(&value) { Some(value) } else { None }
} }
+77 -169
View File
@@ -1,13 +1,15 @@
use strum_macros::EnumIter; use strum_macros::EnumIter;
use thiserror::Error as TeError; use thiserror::Error as TeError;
// region: Sanitizer // region: Validator
/// Error occurs when validating floating point value.
#[derive(Debug, TeError)] #[derive(Debug, TeError)]
#[error("given floating value {0} is invalid")] #[error("given floating point value {0} is invalid")]
pub struct FloatingPointError(f64); pub struct FloatingPointError(f64);
pub fn sanitize_floating_point(f: f64) -> Result<f64, FloatingPointError> { /// Check whether given floating point value is okey for arithmetic operation.
pub fn validate_floating_point(f: f64) -> Result<f64, FloatingPointError> {
if f.is_finite() { if f.is_finite() {
Ok(f) Ok(f)
} else { } else {
@@ -15,16 +17,21 @@ pub fn sanitize_floating_point(f: f64) -> Result<f64, FloatingPointError> {
} }
} }
/// Error occurs when validating device value.
#[derive(Debug, TeError)] #[derive(Debug, TeError)]
pub enum DeviceValueError { pub enum DeviceValueError {
#[error("{0}")] #[error("given device value is bad floating point: {0}")]
BadFloatingPoint(#[from] FloatingPointError), BadFloatingPoint(#[from] FloatingPointError),
#[error("given device value {0} is out of range")] #[error("given device value {0} is out of range")]
OutOfRange(f64), OutOfRange(f64),
} }
pub fn sanitize_device_value(f: f64) -> Result<f64, DeviceValueError> { /// Check whether given value is good for device value.
let f = sanitize_floating_point(f)?; ///
/// A good device value should be finity floating point,
/// and it should be greater than zero.
pub fn validate_device_value(f: f64) -> Result<f64, DeviceValueError> {
let f = validate_floating_point(f)?;
if f > 0f64 { if f > 0f64 {
Ok(f) Ok(f)
} else { } else {
@@ -97,14 +104,21 @@ impl CircuitDeviceScale {
// region: Circuit Stuff // region: Circuit Stuff
/// Error occurs when manipulating [SubCircuit]. /// Error occurs when manipulating [Circuit] and [SubCircuit].
#[derive(Debug, TeError)] #[derive(Debug, TeError)]
pub enum SubCircuitError { pub enum CircuitError {
#[error("invalid device value in circuit: {0}")] #[error("invalid device value in circuit: {0}")]
BadDeviceValue(DeviceValueError), BadDeviceValue(DeviceValueError),
#[error("bad previous computed circuit value: {0}")] #[error("third device cannot exist without second device when building circuit")]
InterleavedSubCircuit,
#[error("the joint or device with given index is not presented in circuit")]
NoSuchDevice,
#[error("invalid target value: {0}")]
BadTargetValue(DeviceValueError),
#[error("bad previous evaluated joint value: {0}")]
BadPreviousValue(DeviceValueError), BadPreviousValue(DeviceValueError),
#[error("arithmetic error: {0}")] #[error("floating point is invalid after arithmetic operation: {0}")]
BadArithmetic(FloatingPointError), BadArithmetic(FloatingPointError),
} }
@@ -122,24 +136,24 @@ impl SubCircuit {
/// ///
/// The input device value should greater than zero, /// The input device value should greater than zero,
/// otherwise an error will return. /// otherwise an error will return.
pub fn new(device_value: f64, joint_kind: JointKind) -> Result<Self, SubCircuitError> { pub fn new(device_value: f64, joint_kind: JointKind) -> Result<Self, CircuitError> {
let device_value = sanitize_device_value(device_value) let device_value =
.map_err(|err| SubCircuitError::BadDeviceValue(err))?; validate_device_value(device_value).map_err(|err| CircuitError::BadDeviceValue(err))?;
Ok(Self { Ok(Self {
device_value, device_value,
joint_kind, joint_kind,
}) })
} }
/// Compute the joint value with given previous computed value and device kind. /// Evaluate the joint value with given previous joint evaluated value and device kind.
/// ///
/// Parameter `value` should be the value computed from previous devices. /// Parameter `value` should be the value evaluated from previous joint.
/// And it should greater than zero. /// And it should greater than zero.
/// `device_kind` is the kind of the device. /// `device_kind` is the kind of the device.
pub fn compute(&self, value: f64, device_kind: DeviceKind) -> Result<f64, SubCircuitError> { pub fn evaluate(&self, value: f64, device_kind: DeviceKind) -> Result<f64, CircuitError> {
// Check the range of provided value for computing // Check the range of provided value for computing
let value = let value =
sanitize_device_value(value).map_err(|err| SubCircuitError::BadPreviousValue(err))?; validate_device_value(value).map_err(|err| CircuitError::BadPreviousValue(err))?;
// We perform series connect for: series resistor, series inductor and parallel capacitor. // We perform series connect for: series resistor, series inductor and parallel capacitor.
// We perform parallel connect for: parallel resistor, parallel inductor and series capacitor. // We perform parallel connect for: parallel resistor, parallel inductor and series capacitor.
@@ -148,11 +162,11 @@ impl SubCircuit {
_ => self.joint_kind, _ => self.joint_kind,
}; };
sanitize_floating_point(match joint_kind { validate_floating_point(match joint_kind {
JointKind::Series => self.device_value + value, JointKind::Series => self.device_value + value,
JointKind::Parallel => (self.device_value * value) / (self.device_value + value), JointKind::Parallel => (self.device_value * value) / (self.device_value + value),
}) })
.map_err(|err| SubCircuitError::BadArithmetic(err)) .map_err(|err| CircuitError::BadArithmetic(err))
} }
/// Get the device value. /// Get the device value.
@@ -166,19 +180,6 @@ impl SubCircuit {
} }
} }
/// Error occurs when manipulating [Circuit].
#[derive(Debug, TeError)]
pub enum CircuitError {
#[error("invalid device value in circuit: {0}")]
BadDeviceValue(DeviceValueError),
#[error("third device cannot exist without second device when building circuit")]
BlankSecondSubCircuit,
#[error("{0}")]
SubCircuit(#[from] SubCircuitError),
#[error("the joint or device with given index is not presented in circuit")]
NoSuchDevice,
}
/// The circuit composed of multiple joints. /// The circuit composed of multiple joints.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Circuit { pub struct Circuit {
@@ -193,20 +194,20 @@ pub struct Circuit {
impl Circuit { impl Circuit {
/// Initialize the circuit with subcircuit. /// Initialize the circuit with subcircuit.
/// ///
/// * `first_device_value` - The value of the first device. /// - `first_device_value`: The value of the first device.
/// * `second_device_subckt` - The second device and its joint property. /// - `second_device_subckt`: The second device and its joint property.
/// * `third_device_subckt` - The third device and its joint property. /// - `third_device_subckt`: The third device and its joint property.
fn new( fn new(
first_device_value: f64, first_device_value: f64,
second_device_subckt: Option<SubCircuit>, second_device_subckt: Option<SubCircuit>,
third_device_subckt: Option<SubCircuit>, third_device_subckt: Option<SubCircuit>,
) -> Result<Self, CircuitError> { ) -> Result<Self, CircuitError> {
// Check the value of first device // Check the value of first device
let first_device_value = sanitize_device_value(first_device_value) let first_device_value = validate_device_value(first_device_value)
.map_err(|err| CircuitError::BadDeviceValue(err))?; .map_err(|err| CircuitError::BadDeviceValue(err))?;
// Check impossible form // Check impossible form
if second_device_subckt.is_none() && third_device_subckt.is_some() { if second_device_subckt.is_none() && third_device_subckt.is_some() {
return Err(CircuitError::BlankSecondSubCircuit); return Err(CircuitError::InterleavedSubCircuit);
} }
// Everything is okey // Everything is okey
@@ -250,23 +251,51 @@ impl Circuit {
) )
} }
/// Compute the circuit value with given value and device kind /// Evaluate the circuit value with device kind
pub fn compute(&self, device_kind: DeviceKind) -> Result<f64, CircuitError> { pub fn evaluate(&self, device_kind: DeviceKind) -> Result<f64, CircuitError> {
let mut value = self.first_device_value; let mut value = self.first_device_value;
match &self.second_device_subckt { match &self.second_device_subckt {
Some(subckt) => value = subckt.compute(value, device_kind)?, Some(subckt) => value = subckt.evaluate(value, device_kind)?,
None => return Ok(value), None => return Ok(value),
} }
match &self.third_device_subckt { match &self.third_device_subckt {
Some(subckt) => value = subckt.compute(value, device_kind)?, Some(subckt) => value = subckt.evaluate(value, device_kind)?,
None => return Ok(value), None => return Ok(value),
} }
Ok(value) Ok(value)
} }
/// Evaluate the circuit value with given target value and device kind
pub fn evaluate_with_target(
&self,
target_value: f64,
device_kind: DeviceKind,
) -> Result<CircuitEvaluation, CircuitError> {
let target_value =
validate_device_value(target_value).map_err(|err| CircuitError::BadTargetValue(err))?;
let value = self.evaluate(device_kind)?;
let difference = validate_floating_point(value - target_value)
.map_err(|err| CircuitError::BadArithmetic(err))?;
let unsigned_difference = validate_floating_point(difference.abs())
.map_err(|err| CircuitError::BadArithmetic(err))?;
let relative_difference = validate_floating_point(difference / target_value)
.map_err(|err| CircuitError::BadArithmetic(err))?;
let unsigned_relative_difference = validate_floating_point(relative_difference.abs())
.map_err(|err| CircuitError::BadArithmetic(err))?;
Ok(CircuitEvaluation {
value,
difference,
unsigned_difference,
relative_difference,
unsigned_relative_difference,
})
}
/// Get the device scale. /// Get the device scale.
/// ///
/// # Returns /// # Returns
@@ -320,146 +349,25 @@ impl Circuit {
} }
} }
/// Error occurs when manipulating [CircuitCalculator]. /// The evaluation result of circuit with target value.
#[derive(Debug, TeError)]
pub enum CircuitCalculatorError {
#[error("invalid target value: {0}")]
BadTargetValue(DeviceValueError),
#[error("{0}")]
Circuit(#[from] CircuitError),
#[error("arithmetic error: {0}")]
BadArithmetic(FloatingPointError),
#[error("bad provided value reducing computation steps: {0}")]
BadReuseValue(FloatingPointError),
}
/// The helper for circuit value computation.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct CircuitCalculator { pub struct CircuitEvaluation {
/// The kind of the device.
device_kind: DeviceKind,
/// The target value.
target_value: f64,
}
impl CircuitCalculator {
/// Initialize this calculator with given device kind and target value.
pub fn new(device_kind: DeviceKind, target_value: f64) -> Result<Self, CircuitCalculatorError> {
let target_value = sanitize_device_value(target_value)
.map_err(|err| CircuitCalculatorError::BadTargetValue(err))?;
Ok(Self {
device_kind,
target_value,
})
}
/// The value of this circuit. /// The value of this circuit.
pub fn value(&self, circuit: &Circuit) -> Result<f64, CircuitCalculatorError> { pub value: f64,
Ok(circuit.compute(self.device_kind)?)
}
/// The signed difference between the target value and the value of this circuit. /// The signed difference between the target value and the value of this circuit.
/// ///
/// Positive value indicates that the value of this circuit is greater than the target value. /// Positive value indicates that the value of this circuit is greater than the target value.
/// Negative value indicates that the value of this circuit is less than the target value. /// Negative value indicates that the value of this circuit is less than the target value.
/// pub difference: f64,
/// * `circuit` - The circuit for computation.
/// * `value` - The value of the circuit computed by the [`value`](Self::value) method
/// for reducing computation steps, or `None` if you request this method to compute the value.
pub fn difference(
&self,
circuit: &Circuit,
value: Option<f64>,
) -> Result<f64, CircuitCalculatorError> {
let value = match value {
Some(v) => sanitize_floating_point(v)
.map_err(|err| CircuitCalculatorError::BadReuseValue(err))?,
None => self.value(circuit)?,
};
sanitize_floating_point(value - self.target_value)
.map_err(|err| CircuitCalculatorError::BadArithmetic(err))
}
/// The unsigned difference between the target value and the value of this circuit. /// The unsigned difference between the target value and the value of this circuit.
/// pub unsigned_difference: f64,
/// * `circuit` - The circuit for computation.
/// * `value` - The value of the circuit computed by the [`value`](Self::value) method
/// for reducing computation steps, or `None` if you request this method to compute the value.
/// * `difference` - The difference of the circuit computed by the
/// [`difference`](Self::difference) method for reducing computation steps,
/// or `None` if you request this method to compute the difference.
pub fn unsigned_difference(
&self,
circuit: &Circuit,
value: Option<f64>,
difference: Option<f64>,
) -> Result<f64, CircuitCalculatorError> {
let diff = match difference {
Some(d) => sanitize_floating_point(d)
.map_err(|err| CircuitCalculatorError::BadReuseValue(err))?,
None => self.difference(circuit, value)?,
};
sanitize_floating_point(diff.abs())
.map_err(|err| CircuitCalculatorError::BadArithmetic(err))
}
/// The signed relative difference between the target value and the value of this circuit. /// The signed relative difference between the target value and the value of this circuit.
/// ///
/// Positive value indicates that the value of this circuit is greater than the target value. /// Positive value indicates that the value of this circuit is greater than the target value.
/// Negative value indicates that the value of this circuit is less than the target value. /// Negative value indicates that the value of this circuit is less than the target value.
/// pub relative_difference: f64,
/// * `circuit` - The circuit for computation.
/// * `value` - The value of the circuit computed by the [`value`](Self::value) method
/// for reducing computation steps, or `None` if you request this method to compute the value.
/// * `difference` - The difference of the circuit computed by the
/// [`difference`](Self::difference) method for reducing computation steps,
/// or `None` if you request this method to compute the difference.
pub fn relative_difference(
&self,
circuit: &Circuit,
value: Option<f64>,
difference: Option<f64>,
) -> Result<f64, CircuitCalculatorError> {
let diff = match difference {
Some(d) => sanitize_floating_point(d)
.map_err(|err| CircuitCalculatorError::BadReuseValue(err))?,
None => self.difference(circuit, value)?,
};
sanitize_floating_point(diff / self.target_value)
.map_err(|err| CircuitCalculatorError::BadArithmetic(err))
}
/// The unsigned relative difference between the target value and the value of this circuit. /// The unsigned relative difference between the target value and the value of this circuit.
/// pub unsigned_relative_difference: f64,
/// * `circuit` - The circuit for computation.
/// * `value` - The value of the circuit computed by the [`value`](Self::value) method
/// for reducing computation steps, or `None` if you request this method to compute the value.
/// * `difference` - The difference of the circuit computed by the
/// [`difference`](Self::difference) method for reducing computation steps,
/// or `None` if you request this method to compute the difference.
/// * `relative_difference` - The relative difference of the circuit computed by the
/// [`relative_difference`](Self::relative_difference) method for reducing computation steps,
/// or `None` if you request this method to compute the relative difference.
///
pub fn unsigned_relative_difference(
&self,
circuit: &Circuit,
value: Option<f64>,
difference: Option<f64>,
relative_difference: Option<f64>,
) -> Result<f64, CircuitCalculatorError> {
let rel_diff = match relative_difference {
Some(rd) => sanitize_floating_point(rd)
.map_err(|err| CircuitCalculatorError::BadReuseValue(err))?,
None => self.relative_difference(circuit, value, difference)?,
};
sanitize_floating_point(rel_diff.abs())
.map_err(|err| CircuitCalculatorError::BadArithmetic(err))
}
} }
// endregion // endregion
+3 -3
View File
@@ -1,5 +1,5 @@
use crate::common::{ use crate::common::{
DeviceValueError, FloatingPointError, sanitize_device_value, sanitize_floating_point, DeviceValueError, FloatingPointError, validate_device_value, validate_floating_point,
}; };
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use std::collections::HashSet; use std::collections::HashSet;
@@ -43,7 +43,7 @@ impl DatasetItem {
/// Create a new dataset item with validation. /// Create a new dataset item with validation.
fn new(value: f64, str_value: String) -> Result<Self, DatasetError> { fn new(value: f64, str_value: String) -> Result<Self, DatasetError> {
// Check arguments // Check arguments
let value = sanitize_device_value(value)?; let value = validate_device_value(value)?;
if str_value.is_empty() { if str_value.is_empty() {
return Err(DatasetError::BlankDeviceValue); return Err(DatasetError::BlankDeviceValue);
} }
@@ -392,7 +392,7 @@ pub fn from_human_readable_value(strl: &str) -> Result<f64, ParseHumanReadableVa
}; };
let num = num_part.parse::<f64>()?; let num = num_part.parse::<f64>()?;
Ok(sanitize_floating_point(num * multiplier)?) Ok(validate_floating_point(num * multiplier)?)
} }
/// The unit scale for human readable value. /// The unit scale for human readable value.
+3 -3
View File
@@ -1,6 +1,6 @@
use crate::common::{ use crate::common::{
Circuit, CircuitCalculator, CircuitCalculatorError, DeviceKind, DeviceValueError, Circuit, CircuitCalculator, CircuitCalculatorError, DeviceKind, DeviceValueError,
sanitize_device_value, validate_device_value,
}; };
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use thiserror::Error as TeError; use thiserror::Error as TeError;
@@ -54,9 +54,9 @@ impl Request {
) -> Result<Self, RequestError> { ) -> Result<Self, RequestError> {
// Check arguments // Check arguments
let target_value = let target_value =
sanitize_device_value(target_value).map_err(|err| RequestError::BadTargetValue(err))?; validate_device_value(target_value).map_err(|err| RequestError::BadTargetValue(err))?;
let tolerance = let tolerance =
sanitize_device_value(tolerance).map_err(|err| RequestError::BadTolerance(err))?; validate_device_value(tolerance).map_err(|err| RequestError::BadTolerance(err))?;
if count_limit == 0 || count_limit > MAX_RESPONSE_CNT { if count_limit == 0 || count_limit > MAX_RESPONSE_CNT {
return Err(RequestError::BadCountLimit(count_limit)); return Err(RequestError::BadCountLimit(count_limit));
} }
+1 -1
View File
@@ -28,7 +28,7 @@ pub struct LutItem {
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> { pub fn new(circuit: Circuit, device_kind: DeviceKind) -> Result<Self, LutResolverError> {
let value = circuit.compute(device_kind)?; let value = circuit.evaluate(device_kind)?;
Ok(Self { Ok(Self {
circuit, circuit,
value: OrderedFloat(value), value: OrderedFloat(value),