Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,22 @@ jobs:
run: cargo fmt --check

- name: clippy
run: cargo clippy --all-features --all-targets -- -D warnings
run: cargo clippy --workspace --all-features --all-targets -- -D warnings

- name: doc
run: cargo doc --all-features --no-deps
run: cargo doc --workspace --all-features --no-deps
env:
RUSTDOCFLAGS: -D warnings

- name: test
# Note: this will be unwieldy if there are many features, but for now it is fine.
# ninterp crate has few enough features that this isn't too hefty
run: cargo hack test --feature-powerset --verbose

- name: test ninterp-uom
# Powerset over autoconvert/serde/std only; f64 pinned as the required storage
# type, other ~21 storage-type alternatives excluded (uom passthrough, not this crate's logic).
run: cargo hack test -p ninterp-uom --feature-powerset --features f64 --exclude-features f32,usize,u8,u16,u32,u64,u128,isize,i8,i16,i32,i64,i128,bigint,biguint,rational,rational32,rational64,bigrational,complex32,complex64 --verbose

- name: install no_std target
run: rustup target add thumbv7m-none-eabi

Expand Down
20 changes: 12 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
[workspace]
members = ["ninterp-uom"]

[workspace.dependencies]
ninterp = { path = ".", version = "0.11.1" }
num-traits = { version = "0.2.15", default-features = false, features = [
"libm",
] }
serde = { version = "1.0.103", default-features = false }

[package]
name = "ninterp"
version = "0.11.1"
Expand All @@ -19,14 +29,8 @@ categories = ["mathematics"]
[dependencies]
dyn-clone = "1"
ndarray = { version = "0.17", default-features = false }
# libm is a no-op under std; it's what powers Float ops (sqrt, ln, ...) without it.
num-traits = { version = "0.2.15", default-features = false, features = [
"libm",
] }
serde = { version = "1.0.103", optional = true, default-features = false, features = [
"derive",
"alloc",
] }
num-traits = { workspace = true, version = "0.2.15" }
serde = { workspace = true, optional = true, features = ["derive", "alloc"] }
serde_unit_struct = { version = "0.1.3", optional = true }
serde-ndim = { version = "2.2.1", optional = true, default-features = false, features = [
"ndarray",
Expand Down
45 changes: 45 additions & 0 deletions ninterp-uom/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
[package]
name = "ninterp-uom"
version = "0.1.0"
edition = "2024"

[dependencies]
ninterp = { workspace = true, version = "0.11.1" }
uom = { version = "0.38.0", default-features = false, features = ["si"] }
serde = { workspace = true, optional = true }

[dev-dependencies]
serde_json = "1.0.140"

[features]
default = ["autoconvert", "std", "f64"]

autoconvert = ["uom/autoconvert"]
std = ["uom/std"]
serde = ["dep:serde", "uom/serde", "ninterp/serde"]

f32 = ["uom/f32"]
f64 = ["uom/f64"]

usize = ["uom/usize"]
u8 = ["uom/u8"]
u16 = ["uom/u16"]
u32 = ["uom/u32"]
u64 = ["uom/u64"]
u128 = ["uom/u128"]
isize = ["uom/isize"]
i8 = ["uom/i8"]
i16 = ["uom/i16"]
i32 = ["uom/i32"]
i64 = ["uom/i64"]
i128 = ["uom/i128"]

bigint = ["uom/bigint"]
biguint = ["uom/biguint"]
rational = ["uom/rational"]
rational32 = ["uom/rational32"]
rational64 = ["uom/rational64"]
bigrational = ["uom/bigrational"]

complex32 = ["uom/complex32"]
complex64 = ["uom/complex64"]
43 changes: 43 additions & 0 deletions ninterp-uom/examples/uom.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use ninterp_uom::ndarray::prelude::*;
use ninterp_uom::prelude::*;

use uom::si::power::kilowatt;
use uom::si::ratio::ratio;

fn main() {
// f(x) = 0.25 kW + 0.5 kW * x, in `f64`, viewed (borrowed, zero-copy).
// Requires the `f64` feature (on by default).
#[cfg(feature = "f64")]
{
use uom::si::f64::{Power, Ratio};

let x = array![Ratio::new::<ratio>(0.), Ratio::new::<ratio>(1.)];
let f_x = array![Power::new::<kilowatt>(0.25), Power::new::<kilowatt>(0.75)];

let interp: UomInterp1DView<Ratio, Power, _, _> =
UomInterp1DView::new(x.view(), f_x.view(), strategy::Linear, Extrapolate::Error)
.unwrap();

// No `unsafe` at the call site, and the output comes back as a `Power`, not a
// bare `f64`.
let output = interp.interpolate(Ratio::new::<ratio>(0.5)).unwrap();
assert_eq!(output, Power::new::<kilowatt>(0.5));
}

// The same wrapper, unmodified, over `f32` storage instead - proving `V` is generic,
// not just `Qx`/`Qv`. Requires the `f32` feature (`cargo run --example uom --features f32`).
#[cfg(feature = "f32")]
{
use uom::si::f32::{Power, Ratio};

let x = array![Ratio::new::<ratio>(0.), Ratio::new::<ratio>(1.)];
let f_x = array![Power::new::<kilowatt>(0.25), Power::new::<kilowatt>(0.75)];

let interp: UomInterp1DView<Ratio, Power, _, _> =
UomInterp1DView::new(x.view(), f_x.view(), strategy::Linear, Extrapolate::Error)
.unwrap();

let output = interp.interpolate(Ratio::new::<ratio>(0.5)).unwrap();
assert_eq!(output, Power::new::<kilowatt>(0.5));
}
}
28 changes: 28 additions & 0 deletions ninterp-uom/src/base_unit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use super::*;

/// A `uom` quantity backed by storage type `V`, convertible to/from its dimension's base
/// unit. Implemented for every `Quantity<D, U, V>`, i.e. every `uom` quantity of every
/// unit system: `Length`, `Power`, `Ratio`, in `f32` or `f64`, all alike.
pub trait BaseUnit<V>: Copy {
fn to_base(self) -> V;
fn from_base(value: V) -> Self;
}

impl<D, U, V> BaseUnit<V> for Quantity<D, U, V>
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: Num + Conversion<V> + Copy,
{
fn to_base(self) -> V {
self.value
}

fn from_base(value: V) -> Self {
Quantity {
dimension: PhantomData,
units: PhantomData,
value,
}
}
}
Loading
Loading