Skip to content

Commit

Permalink
Fix Unit::expression_reduced()
Browse files Browse the repository at this point in the history
  • Loading branch information
turboladen committed Aug 28, 2024
1 parent eb24192 commit 4717d16
Show file tree
Hide file tree
Showing 25 changed files with 191 additions and 210 deletions.
2 changes: 2 additions & 0 deletions crates/api/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- Added `assert_field_eq!()` macro to allow checking exact equality of objects (since current
implementation of `PartialEq` does not do this).
- `Composition` now derives `Ord`.
- `Unit::simplify()`, extracted from the (redesigned) innards of `Unit::expression_reduced()`.
- `Term` now derives `Hash`.

### Changed

Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/annotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
Composable, IsCompatibleWith, Term,
};

#[derive(Default, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Default, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Annotation(String);

impl Annotation {
Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/term.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ impl From<Atom> for Term {
/// `1+2{foo}`; raised to the -2nd power becomes `1-2{foo}`. Notice that a factor, exponent and
/// annotation are all required to represent that.
///
#[derive(Clone, Debug, Eq)]
#[derive(Clone, Debug, Eq, Hash)]
pub enum Term {
/// Ex. "{tree}", where the inner `String` would be the contents inside the curly braces.
///
Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/term/term_reduce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub(crate) trait TermReduce: crate::composable::ComposablyEq<Term> {
fn term_reduce(&self, rhs: &Term) -> ReducedTerm {
match self.composably_eq(rhs) {
Some(0) => ReducedTerm::ReducedAway,
Some(exponent) => ReducedTerm::ReducedToTerm(self.build(exponent).into()),
Some(exponent) => ReducedTerm::ReducedToTerm(self.build(exponent)),
None => ReducedTerm::NotReducible,
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/term/variants/atom_annotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use super::{
// ╰────────────────╯
/// Ex. "g{sucrose}"
///
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct AtomAnnotation {
pub(crate) atom: Atom,
pub(crate) annotation: Annotation,
Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/term/variants/atom_exponent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use super::{
// ╰──────────────╯
/// Ex. "m2"
///
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct AtomExponent {
pub(crate) atom: Atom,
pub(crate) exponent: Exponent,
Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/term/variants/atom_exponent_annotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use super::{
// ╰────────────────────────╯
/// Ex. "m2{peaches}"
///
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct AtomExponentAnnotation {
pub(crate) atom: Atom,
pub(crate) exponent: Exponent,
Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/term/variants/factor_annotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use super::{
// ╭──────────────────╮
// │ FactorAnnotation │
// ╰──────────────────╯
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct FactorAnnotation {
pub(crate) factor: Factor,
pub(crate) annotation: Annotation,
Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/term/variants/factor_atom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use super::{
// ╭────────────╮
// │ FactorAtom │
// ╰────────────╯
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct FactorAtom {
pub(crate) factor: Factor,
pub(crate) atom: Atom,
Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/term/variants/factor_atom_annotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use super::{
// ╭──────────────────────╮
// │ FactorAtomAnnotation │
// ╰──────────────────────╯
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct FactorAtomAnnotation {
pub(crate) factor: Factor,
pub(crate) atom: Atom,
Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/term/variants/factor_atom_exponent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use super::{
// ╭────────────────────╮
// │ FactorAtomExponent │
// ╰────────────────────╯
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct FactorAtomExponent {
pub(crate) factor: Factor,
pub(crate) atom: Atom,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use super::{
// ╭──────────────────────────────╮
// │ FactorAtomExponentAnnotation │
// ╰──────────────────────────────╯
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct FactorAtomExponentAnnotation {
pub(crate) factor: Factor,
pub(crate) atom: Atom,
Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/term/variants/factor_exponent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use super::{
// ╭────────────────╮
// │ FactorExponent │
// ╰────────────────╯
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct FactorExponent {
pub(crate) factor: Factor,
pub(crate) exponent: Exponent,
Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/term/variants/factor_exponent_annotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use super::{
// ╭──────────────────────────╮
// │ FactorExponentAnnotation │
// ╰──────────────────────────╯
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct FactorExponentAnnotation {
pub(crate) factor: Factor,
pub(crate) exponent: Exponent,
Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/term/variants/factor_prefix_atom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use super::{
// ╭──────────────────╮
// │ FactorPrefixAtom │
// ╰──────────────────╯
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct FactorPrefixAtom {
pub(crate) factor: Factor,
pub(crate) prefix: Prefix,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use super::{
// ╭────────────────────────────╮
// │ FactorPrefixAtomAnnotation │
// ╰────────────────────────────╯
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct FactorPrefixAtomAnnotation {
pub(crate) factor: Factor,
pub(crate) prefix: Prefix,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use super::{
// ╭──────────────────────────╮
// │ FactorPrefixAtomExponent │
// ╰──────────────────────────╯
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct FactorPrefixAtomExponent {
pub(crate) factor: Factor,
pub(crate) prefix: Prefix,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use super::{
// ╭────────────────────────────────────╮
// │ FactorPrefixAtomExponentAnnotation │
// ╰────────────────────────────────────╯
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct FactorPrefixAtomExponentAnnotation {
pub(crate) factor: Factor,
pub(crate) prefix: Prefix,
Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/term/variants/prefix_atom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use super::{
// ╭────────────╮
// │ PrefixAtom │
// ╰────────────╯
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct PrefixAtom {
pub(crate) prefix: Prefix,
pub(crate) atom: Atom,
Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/term/variants/prefix_atom_annotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use super::{
// ╭──────────────────────╮
// │ PrefixAtomAnnotation │
// ╰──────────────────────╯
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct PrefixAtomAnnotation {
pub(crate) prefix: Prefix,
pub(crate) atom: Atom,
Expand Down
2 changes: 1 addition & 1 deletion crates/api/src/term/variants/prefix_atom_exponent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use super::{
// ╭────────────────────╮
// │ PrefixAtomExponent │
// ╰────────────────────╯
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct PrefixAtomExponent {
pub(crate) prefix: Prefix,
pub(crate) atom: Atom,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use super::{
// ╭──────────────────────────────╮
// │ PrefixAtomExponentAnnotation │
// ╰──────────────────────────────╯
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct PrefixAtomExponentAnnotation {
pub(crate) prefix: Prefix,
pub(crate) atom: Atom,
Expand Down
66 changes: 63 additions & 3 deletions crates/api/src/unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,48 @@ impl Unit {
self.to_string()
}

/// If the unit terms are a fraction and can be reduced, this returns a new
/// `Unit` with those terms. Ex. terms that would normally render
/// `[acr_us].[in_i]/[acr_us]` would simply render `[in_i]`.
///
/// ```rust
/// use wise_units::{Unit, parse_unit};
///
/// let u = parse_unit!("[acr_us].[in_i]/[acr_us]");
/// assert_eq!(u.simplify(), parse_unit!("[in_i]"));
/// ```
///
#[must_use]
pub fn simplify(&self) -> Self {
fn reduce_head_tail(remaining_terms: &[Term]) -> Option<(Term, term_reducing::WhatToKeep)> {
if let Some((head, tail)) = remaining_terms.split_first() {
Some((
head.clone(),
term_reducing::simplify_one_to_many(head, tail),
))
} else {
None
}
}

let mut output: Vec<Term> = Vec::new();

if let Some((lhs, what_to_keep)) = reduce_head_tail(&self.terms) {
if what_to_keep.keep_lhs {
output.push(lhs);
}

output.extend(what_to_keep.new_terms);

Self::new(term_reducing::compare_and_cancel(
&output,
what_to_keep.kept_terms,
))
} else {
self.clone()
}
}

/// If the unit terms are a fraction and can be reduced, this returns those
/// as a string. Ex. terms that would normally render
/// `[acr_us].[in_i]/[acr_us]` would simply render `[in_i]`.
Expand All @@ -161,9 +203,7 @@ impl Unit {
#[inline]
#[must_use]
pub fn expression_reduced(&self) -> String {
let reduced = term_reducing::reduce_terms(&self.terms);

Self::new(reduced).to_string()
self.simplify().to_string()
}

pub fn numerator_terms(&self) -> impl Iterator<Item = &Term> {
Expand Down Expand Up @@ -232,6 +272,7 @@ mod tests {
#[test]
fn validate_expression_reduced() {
assert_eq!(METER.expression_reduced(), "m");
assert_eq!(UNITY.expression_reduced(), "1");
assert_eq!(parse_unit!("M").expression_reduced(), "m");
assert_eq!(parse_unit!("km/10m").expression_reduced(), "km/10m");
assert_eq!(parse_unit!("m-1").expression_reduced(), "/m");
Expand All @@ -248,6 +289,25 @@ mod tests {
assert_eq!(parse_unit!("MiBy").expression_reduced(), "MiBy");
assert_eq!(parse_unit!("GiBy").expression_reduced(), "GiBy");
assert_eq!(parse_unit!("TiBy").expression_reduced(), "TiBy");

assert_eq!(parse_unit!("42km3{foo}").expression_reduced(), "42km3{foo}");
assert_eq!(
parse_unit!("42km3{foo}.42kg2{bar}").expression_reduced(),
"42km3{foo}.42kg2{bar}"
);
assert_eq!(
parse_unit!("42km3{foo}/42km2{foo}").expression_reduced(),
"42km{foo}"
);
assert_eq!(parse_unit!("km3.km/km2").expression_reduced(), "km2");
assert_eq!(
parse_unit!("{meow}/m2.g/{meow}").expression_reduced(),
"1+2{meow}/m2.g"
);
assert_eq!(
parse_unit!("{meow}/m2/g/{meow}").expression_reduced(),
"g/m2"
);
}

#[cfg(feature = "cffi")]
Expand Down
36 changes: 24 additions & 12 deletions crates/api/src/unit/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl Div for Unit {

#[inline]
fn div(self, other: Self) -> Self::Output {
Self::new(term_reducing::meow(
Self::new(term_reducing::compare_and_cancel(
&self.terms,
other.terms.iter().map(Inv::inv).collect(),
))
Expand All @@ -33,9 +33,9 @@ impl<'a> Div<&'a Self> for Unit {

#[inline]
fn div(self, other: &'a Self) -> Self::Output {
Self::new(term_reducing::meow(
Self::new(term_reducing::compare_and_cancel(
&self.terms,
other.terms.into_iter().map(Inv::inv).collect(),
other.terms.iter().map(Inv::inv).collect(),
))
}
}
Expand All @@ -48,9 +48,9 @@ impl<'a> Div for &'a Unit {

#[inline]
fn div(self, other: &'a Unit) -> Self::Output {
Unit::new(term_reducing::meow(
Unit::new(term_reducing::compare_and_cancel(
&self.terms,
other.terms.into_iter().map(Inv::inv).collect(),
other.terms.iter().map(Inv::inv).collect(),
))
}
}
Expand All @@ -63,9 +63,9 @@ impl<'a> Div<Unit> for &'a Unit {

#[inline]
fn div(self, other: Unit) -> Self::Output {
Unit::new(term_reducing::meow(
Unit::new(term_reducing::compare_and_cancel(
&self.terms,
other.terms.into_iter().map(Inv::inv).collect(),
other.terms.iter().map(Inv::inv).collect(),
))
}
}
Expand All @@ -81,7 +81,10 @@ impl Mul for Unit {

#[inline]
fn mul(self, other: Self) -> Self::Output {
Self::new(term_reducing::meow(&self.terms, other.terms.to_vec()))
Self::new(term_reducing::compare_and_cancel(
&self.terms,
other.terms.to_vec(),
))
}
}

Expand All @@ -93,7 +96,10 @@ impl<'a> Mul<&'a Self> for Unit {

#[inline]
fn mul(self, other: &'a Self) -> Self::Output {
Self::new(term_reducing::meow(&self.terms, other.terms.to_vec()))
Self::new(term_reducing::compare_and_cancel(
&self.terms,
other.terms.to_vec(),
))
}
}

Expand All @@ -105,7 +111,10 @@ impl<'a> Mul for &'a Unit {

#[inline]
fn mul(self, other: &'a Unit) -> Self::Output {
Unit::new(term_reducing::meow(&self.terms, other.terms.to_vec()))
Unit::new(term_reducing::compare_and_cancel(
&self.terms,
other.terms.to_vec(),
))
}
}

Expand All @@ -117,7 +126,10 @@ impl<'a> Mul<Unit> for &'a Unit {

#[inline]
fn mul(self, other: Unit) -> Self::Output {
Unit::new(term_reducing::meow(&self.terms, other.terms.to_vec()))
Unit::new(term_reducing::compare_and_cancel(
&self.terms,
other.terms.to_vec(),
))
}
}

Expand Down Expand Up @@ -185,7 +197,7 @@ mod tests {
test_div!(test_factor_atom_div_factor_same_atom:
parse_unit!("10m"), parse_unit!("20m") => parse_unit!("10m/20m"));
test_div!(test_nondim_div_same_nondim:
seed(), seed() => parse_unit!("{seed}"));
seed(), seed() => UNITY);
test_div!(test_unity_div_same_nondim:
UNITY, seed() => Unit::new(vec![term!(factor: 1, exponent: -1, annotation: "seed")]));
test_div!(test_nondim_div_atom:
Expand Down
Loading

0 comments on commit 4717d16

Please sign in to comment.