1
0

fix: update kernel common

This commit is contained in:
2026-06-29 10:06:00 +08:00
parent ccd96e6801
commit 9d9c0473e8
2 changed files with 181 additions and 176 deletions

View File

@@ -1,6 +1,41 @@
use strum_macros::EnumIter;
use thiserror::Error as TeError;
// region: Sanitizer
#[derive(Debug, TeError)]
#[error("given floating value {0} is invalid")]
pub struct FloatingPointError(f64);
pub fn sanitize_floating_point(f: f64) -> Result<f64, FloatingPointError> {
if f.is_finite() {
Ok(f)
} else {
Err(FloatingPointError(f))
}
}
#[derive(Debug, TeError)]
pub enum DeviceValueError {
#[error("{0}")]
BadFloatingPoint(#[from] FloatingPointError),
#[error("given device value {0} is out of range")]
OutOfRange(f64),
}
pub fn sanitize_device_value(f: f64) -> Result<f64, DeviceValueError> {
let f = sanitize_floating_point(f)?;
if f > 0f64 {
Ok(f)
} else {
Err(DeviceValueError::OutOfRange(f))
}
}
// endregion
// region: Circuit Utilities
/// The kind of device.
#[derive(Debug, Clone, Copy)]
pub enum DeviceKind {
@@ -35,82 +70,6 @@ impl JointKind {
}
}
/// Error occurs when manipulating [SubCircuit].
#[derive(Debug, TeError)]
pub enum SubCircuitError {
#[error("given circuit device value {0} should greater than zero")]
BadDeviceValue(f64),
#[error("the previous computed circuit value {0} should greater than zero")]
BadPreviousValue(f64),
#[error("bad float point arithmetic")]
BadArithmetic,
}
/// The part of circuit composed of two devices and the joint kind.
#[derive(Debug, Clone)]
pub struct SubCircuit {
/// The value of the device.
device_value: f64,
/// The joint kind between this device and the next device.
joint_kind: JointKind,
}
impl SubCircuit {
/// Initialize subcircuit with given device value and joint kind.
///
/// The input device value should greater than zero,
/// otherwise an error will return.
pub fn new(device_value: f64, joint_kind: JointKind) -> Result<Self, SubCircuitError> {
if device_value > 0f64 {
Ok(Self {
device_value,
joint_kind,
})
} else {
Err(SubCircuitError::BadDeviceValue(device_value))
}
}
/// Compute the joint value with given previous computed value and device kind.
///
/// Parameter `value` should be the value computed from previous devices.
/// And it should greater than zero.
/// `device_kind` is the kind of the device.
pub fn compute(&self, value: f64, device_kind: DeviceKind) -> Result<f64, SubCircuitError> {
// Check the range of provided value for computing
if !(value > 0f64) {
return Err(SubCircuitError::BadPreviousValue(value));
}
// We perform series connect for: series resistor, series inductor and parallel capacitor.
// We perform parallel connect for: parallel resistor, parallel inductor and series capacitor.
let joint_kind = match device_kind {
DeviceKind::Capacitor => self.joint_kind.flip(),
_ => self.joint_kind,
};
let rv = match joint_kind {
JointKind::Series => self.device_value + value,
JointKind::Parallel => (self.device_value * value) / (self.device_value + value),
};
if rv.is_finite() {
Ok(rv)
} else {
Err(SubCircuitError::BadArithmetic)
}
}
/// Get the device value.
pub fn device_value(&self) -> f64 {
self.device_value
}
/// Get the joint kind.
pub fn joint_kind(&self) -> JointKind {
self.joint_kind
}
}
/// The scale of devices in the circuit.
#[derive(Debug, Clone, Copy)]
pub enum CircuitDeviceScale {
@@ -134,11 +93,84 @@ impl CircuitDeviceScale {
}
}
// endregion
// region: Circuit Stuff
/// Error occurs when manipulating [SubCircuit].
#[derive(Debug, TeError)]
pub enum SubCircuitError {
#[error("invalid device value in circuit: {0}")]
BadDeviceValue(DeviceValueError),
#[error("bad previous computed circuit value: {0}")]
BadPreviousValue(DeviceValueError),
#[error("arithmetic error: {0}")]
BadArithmetic(FloatingPointError),
}
/// The part of circuit composed of two devices and the joint kind.
#[derive(Debug, Clone)]
pub struct SubCircuit {
/// The value of the device.
device_value: f64,
/// The joint kind between this device and the next device.
joint_kind: JointKind,
}
impl SubCircuit {
/// Initialize subcircuit with given device value and joint kind.
///
/// The input device value should greater than zero,
/// otherwise an error will return.
pub fn new(device_value: f64, joint_kind: JointKind) -> Result<Self, SubCircuitError> {
let device_value = sanitize_device_value(device_value)
.map_err(|err| SubCircuitError::BadDeviceValue(err))?;
Ok(Self {
device_value,
joint_kind,
})
}
/// Compute the joint value with given previous computed value and device kind.
///
/// Parameter `value` should be the value computed from previous devices.
/// And it should greater than zero.
/// `device_kind` is the kind of the device.
pub fn compute(&self, value: f64, device_kind: DeviceKind) -> Result<f64, SubCircuitError> {
// Check the range of provided value for computing
let value =
sanitize_device_value(value).map_err(|err| SubCircuitError::BadPreviousValue(err))?;
// We perform series connect for: series resistor, series inductor and parallel capacitor.
// We perform parallel connect for: parallel resistor, parallel inductor and series capacitor.
let joint_kind = match device_kind {
DeviceKind::Capacitor => self.joint_kind.flip(),
_ => self.joint_kind,
};
sanitize_floating_point(match joint_kind {
JointKind::Series => self.device_value + value,
JointKind::Parallel => (self.device_value * value) / (self.device_value + value),
})
.map_err(|err| SubCircuitError::BadArithmetic(err))
}
/// Get the device value.
pub fn device_value(&self) -> f64 {
self.device_value
}
/// Get the joint kind.
pub fn joint_kind(&self) -> JointKind {
self.joint_kind
}
}
/// Error occurs when manipulating [Circuit].
#[derive(Debug, TeError)]
pub enum CircuitError {
#[error("given circuit device value {0} should greater than zero")]
BadDeviceValue(f64),
#[error("invalid device value in circuit: {0}")]
BadDeviceValue(DeviceValueError),
#[error("third device cannot exist without second device when building circuit")]
BlankSecondSubCircuit,
#[error("{0}")]
@@ -170,9 +202,8 @@ impl Circuit {
third_device_subckt: Option<SubCircuit>,
) -> Result<Self, CircuitError> {
// Check the value of first device
if !(first_device_value > 0f64) {
return Err(CircuitError::BadDeviceValue(first_device_value));
}
let first_device_value = sanitize_device_value(first_device_value)
.map_err(|err| CircuitError::BadDeviceValue(err))?;
// Check impossible form
if second_device_subckt.is_none() && third_device_subckt.is_some() {
return Err(CircuitError::BlankSecondSubCircuit);
@@ -292,14 +323,14 @@ impl Circuit {
/// Error occurs when manipulating [CircuitCalculator].
#[derive(Debug, TeError)]
pub enum CircuitCalculatorError {
#[error("given target value {0} should be greater than zero")]
BadTargetValue(f64),
#[error("invalid target value: {0}")]
BadTargetValue(DeviceValueError),
#[error("{0}")]
Circuit(#[from] CircuitError),
#[error("bad float point arithmetic")]
BadArithmetic,
#[error("provided value {0} reducing computation steps is invalid")]
BadReuseValue(f64),
#[error("arithmetic error: {0}")]
BadArithmetic(FloatingPointError),
#[error("bad provided value reducing computation steps: {0}")]
BadReuseValue(FloatingPointError),
}
/// The helper for circuit value computation.
@@ -314,14 +345,12 @@ pub struct CircuitCalculator {
impl CircuitCalculator {
/// Initialize this calculator with given device kind and target value.
pub fn new(device_kind: DeviceKind, target_value: f64) -> Result<Self, CircuitCalculatorError> {
if target_value > 0f64 {
Ok(Self {
device_kind,
target_value,
})
} else {
Err(CircuitCalculatorError::BadTargetValue(target_value))
}
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.
@@ -343,22 +372,13 @@ impl CircuitCalculator {
value: Option<f64>,
) -> Result<f64, CircuitCalculatorError> {
let value = match value {
Some(v) => {
if v.is_finite() {
v
} else {
return Err(CircuitCalculatorError::BadReuseValue(v));
}
}
Some(v) => sanitize_floating_point(v)
.map_err(|err| CircuitCalculatorError::BadReuseValue(err))?,
None => self.value(circuit)?,
};
let rv = value - self.target_value;
if rv.is_finite() {
Ok(rv)
} else {
Err(CircuitCalculatorError::BadArithmetic)
}
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.
@@ -376,22 +396,13 @@ impl CircuitCalculator {
difference: Option<f64>,
) -> Result<f64, CircuitCalculatorError> {
let diff = match difference {
Some(d) => {
if d.is_finite() {
d
} else {
return Err(CircuitCalculatorError::BadReuseValue(d));
}
}
Some(d) => sanitize_floating_point(d)
.map_err(|err| CircuitCalculatorError::BadReuseValue(err))?,
None => self.difference(circuit, value)?,
};
let rv = diff.abs();
if rv.is_finite() {
Ok(rv)
} else {
Err(CircuitCalculatorError::BadArithmetic)
}
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.
@@ -412,22 +423,13 @@ impl CircuitCalculator {
difference: Option<f64>,
) -> Result<f64, CircuitCalculatorError> {
let diff = match difference {
Some(d) => {
if d.is_finite() {
d
} else {
return Err(CircuitCalculatorError::BadReuseValue(d));
}
}
Some(d) => sanitize_floating_point(d)
.map_err(|err| CircuitCalculatorError::BadReuseValue(err))?,
None => self.difference(circuit, value)?,
};
let rv = diff / self.target_value;
if rv.is_finite() {
Ok(rv)
} else {
Err(CircuitCalculatorError::BadArithmetic)
}
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.
@@ -450,21 +452,14 @@ impl CircuitCalculator {
relative_difference: Option<f64>,
) -> Result<f64, CircuitCalculatorError> {
let rel_diff = match relative_difference {
Some(rd) => {
if rd.is_finite() {
rd
} else {
return Err(CircuitCalculatorError::BadReuseValue(rd));
}
}
Some(rd) => sanitize_floating_point(rd)
.map_err(|err| CircuitCalculatorError::BadReuseValue(err))?,
None => self.relative_difference(circuit, value, difference)?,
};
let rv = rel_diff.abs();
if rv.is_finite() {
Ok(rv)
} else {
Err(CircuitCalculatorError::BadArithmetic)
}
sanitize_floating_point(rel_diff.abs())
.map_err(|err| CircuitCalculatorError::BadArithmetic(err))
}
}
// endregion

View File

@@ -1,7 +1,12 @@
use thiserror::Error as TeError;
use std::collections::HashSet;
use std::path::Path;
use crate::common::LcrConnError;
/// Error occurs when building dataset.
#[derive(Debug, TeError)]
pub enum DatasetError {
}
/// An item in the dataset.
#[derive(Clone, Debug)]
@@ -17,14 +22,14 @@ impl DatasetItem {
///
/// # Errors
///
/// Returns [`LcrConnError::InvalidDatasetValue`] if the value is not greater than 0.
/// Returns [`LcrConnError::EmptyDatasetItem`] if the string value is empty.
pub fn new(value: f64, str_value: String) -> Result<Self, LcrConnError> {
/// Returns [`DatasetError::InvalidDatasetValue`] if the value is not greater than 0.
/// Returns [`DatasetError::EmptyDatasetItem`] if the string value is empty.
pub fn new(value: f64, str_value: String) -> Result<Self, DatasetError> {
if value <= 0.0 {
return Err(LcrConnError::InvalidDatasetValue(value));
return Err(DatasetError::InvalidDatasetValue(value));
}
if str_value.is_empty() {
return Err(LcrConnError::EmptyDatasetItem);
return Err(DatasetError::EmptyDatasetItem);
}
Ok(Self { value, str_value })
}
@@ -46,10 +51,10 @@ impl Dataset {
///
/// # Errors
///
/// Returns [`LcrConnError::DuplicateDatasetItem`] if duplicate values are found.
/// Returns [`LcrConnError::EmptyDataset`] if the iterable produces no items.
/// Returns [`LcrConnError::InvalidHumanReadableValue`] if a value cannot be parsed.
pub fn from_iterable<I, S>(str_values: I) -> Result<Self, LcrConnError>
/// Returns [`DatasetError::DuplicateDatasetItem`] if duplicate values are found.
/// Returns [`DatasetError::EmptyDataset`] if the iterable produces no items.
/// Returns [`DatasetError::InvalidHumanReadableValue`] if a value cannot be parsed.
pub fn from_iterable<I, S>(str_values: I) -> Result<Self, DatasetError>
where
I: IntoIterator<Item = S>,
S: Into<String>,
@@ -64,7 +69,7 @@ impl Dataset {
let value = from_human_readable_value(&str_value)?;
// Check and update set
if !seen.insert(value) {
return Err(LcrConnError::DuplicateDatasetItem(str_value));
return Err(DatasetError::DuplicateDatasetItem(str_value));
}
// Add into result
items.push(DatasetItem::new(value, str_value)?);
@@ -72,7 +77,7 @@ impl Dataset {
// Check empty case
if items.is_empty() {
return Err(LcrConnError::EmptyDataset);
return Err(DatasetError::EmptyDataset);
}
// Ok, assign it
@@ -86,7 +91,7 @@ impl Dataset {
/// # Errors
///
/// See [`Dataset::from_iterable`].
pub fn from_text(text: &str) -> Result<Self, LcrConnError> {
pub fn from_text(text: &str) -> Result<Self, DatasetError> {
let lines: Vec<String> = text
.lines()
.map(|line| line.trim().to_string())
@@ -99,9 +104,9 @@ impl Dataset {
///
/// # Errors
///
/// Returns [`LcrConnError::Io`] if the file cannot be read.
/// Returns [`DatasetError::Io`] if the file cannot be read.
/// See [`Dataset::from_iterable`] for other errors.
pub fn from_file(path: impl AsRef<Path>) -> Result<Self, LcrConnError> {
pub fn from_file(path: impl AsRef<Path>) -> Result<Self, DatasetError> {
let text = std::fs::read_to_string(path)?;
Self::from_text(&text)
}
@@ -111,7 +116,7 @@ impl Dataset {
/// # Errors
///
/// See [`Dataset::from_iterable`].
pub fn resistor_preset() -> Result<Self, LcrConnError> {
pub fn resistor_preset() -> Result<Self, DatasetError> {
Self::from_iterable([
"100", "220", "270", "390", "470", "680", "1k", "1.2k", "1.5k", "2.2k", "3.3k",
"4.7k", "6.8k", "10k", "47k", "100k", "1M",
@@ -123,7 +128,7 @@ impl Dataset {
/// # Errors
///
/// See [`Dataset::from_iterable`].
pub fn capacitor_preset() -> Result<Self, LcrConnError> {
pub fn capacitor_preset() -> Result<Self, DatasetError> {
Self::from_iterable([
"10p", "22p", "33p", "47p", "68p", "100p", "150p", "220p", "330p", "470p", "560p",
"1u", "2.2u", "3.3u", "4.7u", "10u", "22u", "47u", "100u", "220u", "470u",
@@ -135,7 +140,7 @@ impl Dataset {
/// # Errors
///
/// See [`Dataset::from_iterable`].
pub fn inductor_preset() -> Result<Self, LcrConnError> {
pub fn inductor_preset() -> Result<Self, DatasetError> {
Self::from_iterable([
"0.1u", "0.15u", "0.47u", "0.68u", "1u", "1.5u", "2.2u", "3.3u", "4.7u", "6.8u",
"8.2u", "10u", "15u", "22u", "33u", "47u", "68u", "100u",
@@ -155,8 +160,8 @@ impl Dataset {
///
/// # Errors
///
/// Returns [`LcrConnError::Io`] if the file cannot be written.
pub fn save_file(&self, path: impl AsRef<Path>) -> Result<(), LcrConnError> {
/// Returns [`DatasetError::Io`] if the file cannot be written.
pub fn save_file(&self, path: impl AsRef<Path>) -> Result<(), DatasetError> {
std::fs::write(path, self.save_text())?;
Ok(())
}
@@ -206,7 +211,7 @@ impl DatasetCollection {
resistor: I1,
capacitor: I2,
inductor: I3,
) -> Result<Self, LcrConnError>
) -> Result<Self, DatasetError>
where
I1: IntoIterator<Item = S1>,
S1: Into<String>,
@@ -233,7 +238,7 @@ impl DatasetCollection {
/// # Errors
///
/// See [`Dataset::from_text`].
pub fn from_text(resistor: &str, capacitor: &str, inductor: &str) -> Result<Self, LcrConnError> {
pub fn from_text(resistor: &str, capacitor: &str, inductor: &str) -> Result<Self, DatasetError> {
Ok(Self {
resistor: Dataset::from_text(resistor)?,
capacitor: Dataset::from_text(capacitor)?,
@@ -256,7 +261,7 @@ impl DatasetCollection {
resistor: impl AsRef<Path>,
capacitor: impl AsRef<Path>,
inductor: impl AsRef<Path>,
) -> Result<Self, LcrConnError> {
) -> Result<Self, DatasetError> {
Ok(Self {
resistor: Dataset::from_file(resistor)?,
capacitor: Dataset::from_file(capacitor)?,
@@ -269,7 +274,7 @@ impl DatasetCollection {
/// # Errors
///
/// See [`Dataset::from_iterable`].
pub fn devices_preset() -> Result<Self, LcrConnError> {
pub fn devices_preset() -> Result<Self, DatasetError> {
Ok(Self {
resistor: Dataset::resistor_preset()?,
capacitor: Dataset::capacitor_preset()?,
@@ -300,13 +305,13 @@ impl DatasetCollection {
///
/// # Errors
///
/// Returns [`LcrConnError::Io`] if any file cannot be written.
/// Returns [`DatasetError::Io`] if any file cannot be written.
pub fn save_file(
&self,
resistor: impl AsRef<Path>,
capacitor: impl AsRef<Path>,
inductor: impl AsRef<Path>,
) -> Result<(), LcrConnError> {
) -> Result<(), DatasetError> {
self.resistor.save_file(resistor)?;
self.capacitor.save_file(capacitor)?;
self.inductor.save_file(inductor)?;
@@ -329,6 +334,11 @@ impl DatasetCollection {
}
}
#[derive(Debug, TeError)]
pub enum ParseHumanReadableValueError {
}
/// Convert human readable value to float.
///
/// # Arguments
@@ -341,8 +351,8 @@ impl DatasetCollection {
///
/// # Errors
///
/// Returns [`LcrConnError::InvalidHumanReadableValue`] if the input string is not a valid number.
pub fn from_human_readable_value(strl: &str) -> Result<f64, LcrConnError> {
/// Returns [`DatasetError::InvalidHumanReadableValue`] if the input string is not a valid number.
pub fn from_human_readable_value(strl: &str) -> Result<f64, ParseHumanReadableValueError> {
let strl = strl.trim();
let (num_part, multiplier) = if let Some(stripped) = strl.strip_suffix('n') {
@@ -366,7 +376,7 @@ pub fn from_human_readable_value(strl: &str) -> Result<f64, LcrConnError> {
num_part
.parse::<f64>()
.map(|v| v * multiplier)
.map_err(|_| LcrConnError::InvalidHumanReadableValue(strl.to_string()))
.map_err(|_| DatasetError::InvalidHumanReadableValue(strl.to_string()))
}
/// The unit scale for human readable value.