From eb24192ee436e52f4cf980b75c20bab70a401f42 Mon Sep 17 00:00:00 2001 From: Steve Loveless Date: Mon, 26 Aug 2024 23:18:45 -0700 Subject: [PATCH] Add new Measurement mul/div test & fix reduction impl --- crates/api/src/annotation.rs | 64 +++++++- crates/api/src/atom/composable.rs | 61 ++++++- crates/api/src/composable.rs | 4 +- crates/api/src/measurement/ops/mul_div.rs | 52 ++++-- crates/api/src/term.rs | 2 +- crates/api/src/term/composable.rs | 48 +++++- crates/api/src/term/composably_eq.rs | 111 ------------- crates/api/src/term/term_reduce.rs | 71 ++++++++ .../api/src/term/variants/atom_annotation.rs | 103 ++++++++---- crates/api/src/term/variants/atom_exponent.rs | 89 ++++++++--- .../term/variants/atom_exponent_annotation.rs | 104 +++++++----- .../src/term/variants/factor_annotation.rs | 83 ++++++---- crates/api/src/term/variants/factor_atom.rs | 100 ++++++++---- .../term/variants/factor_atom_annotation.rs | 114 ++++++++----- .../src/term/variants/factor_atom_exponent.rs | 98 ++++++++---- .../factor_atom_exponent_annotation.rs | 114 ++++++++----- .../api/src/term/variants/factor_exponent.rs | 66 +++++--- .../variants/factor_exponent_annotation.rs | 85 ++++++---- .../src/term/variants/factor_prefix_atom.rs | 113 ++++++++----- .../variants/factor_prefix_atom_annotation.rs | 151 +++++++++++------- .../variants/factor_prefix_atom_exponent.rs | 111 ++++++++----- .../factor_prefix_atom_exponent_annotation.rs | 149 ++++++++++------- crates/api/src/term/variants/prefix_atom.rs | 103 +++++++----- .../term/variants/prefix_atom_annotation.rs | 126 +++++++++------ .../src/term/variants/prefix_atom_exponent.rs | 103 +++++++----- .../prefix_atom_exponent_annotation.rs | 124 ++++++++------ crates/api/src/unit/ops.rs | 69 +++----- crates/api/src/unit/term_reducing.rs | 110 ++++++++++++- 28 files changed, 1682 insertions(+), 846 deletions(-) delete mode 100644 crates/api/src/term/composably_eq.rs create mode 100644 crates/api/src/term/term_reduce.rs diff --git a/crates/api/src/annotation.rs b/crates/api/src/annotation.rs index 53944fdc..9bd12272 100644 --- a/crates/api/src/annotation.rs +++ b/crates/api/src/annotation.rs @@ -1,6 +1,13 @@ use std::fmt; -use crate::{Composable, IsCompatibleWith, Term}; +use crate::{ + composable::ComposablyEq, + term::{ + variants::{FactorAnnotation, FactorExponentAnnotation}, + Exponent, + }, + Composable, IsCompatibleWith, Term, +}; #[derive(Default, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct Annotation(String); @@ -33,6 +40,47 @@ where } } +impl ComposablyEq for Annotation { + fn composably_eq(&self, rhs: &Term) -> Option { + match rhs { + Term::Annotation(inner) => self.composably_eq(inner), + Term::FactorAnnotation(inner) => self.composably_eq(inner), + Term::FactorExponentAnnotation(inner) => self.composably_eq(inner), + _ => None, + } + } +} + +impl ComposablyEq for Annotation { + fn composably_eq(&self, rhs: &Self) -> Option { + if self == rhs { + Some(2) + } else { + None + } + } +} + +impl ComposablyEq for Annotation { + fn composably_eq(&self, rhs: &FactorAnnotation) -> Option { + if rhs.factor == 1 && self == &rhs.annotation { + Some(2) + } else { + None + } + } +} + +impl ComposablyEq for Annotation { + fn composably_eq(&self, rhs: &FactorExponentAnnotation) -> Option { + if rhs.factor == 1 && self == &rhs.annotation { + Some(1 + rhs.exponent) + } else { + None + } + } +} + impl Composable for Annotation { fn composition(&self) -> crate::Composition { crate::Composition::new_dimless() @@ -44,3 +92,17 @@ impl IsCompatibleWith for Annotation { self.composition() == rhs.composition() && Some(self.as_str()) == rhs.annotation() } } + +impl crate::term::term_reduce::TermReduce for Annotation { + fn build(&self, exponent: Exponent) -> Term { + if exponent == 1 { + Term::Annotation(self.clone()) + } else { + Term::FactorExponentAnnotation(FactorExponentAnnotation { + factor: 1, + exponent, + annotation: self.clone(), + }) + } + } +} diff --git a/crates/api/src/atom/composable.rs b/crates/api/src/atom/composable.rs index d9c4047f..0649c634 100644 --- a/crates/api/src/atom/composable.rs +++ b/crates/api/src/atom/composable.rs @@ -1,4 +1,11 @@ -use crate::{Atom, Composable, Composition, Dimension}; +use crate::{ + composable::ComposablyEq, + term::{ + variants::{AtomExponent, FactorAtom, FactorAtomExponent}, + Exponent, + }, + Atom, Composable, Composition, Dimension, Term, +}; impl Composable for Atom { fn composition(&self) -> Composition { @@ -14,3 +21,55 @@ impl Composable for Atom { } } } + +impl ComposablyEq for Atom { + fn composably_eq(&self, rhs: &Term) -> Option { + match rhs { + Term::Atom(inner) => self.composably_eq(inner), + Term::AtomExponent(inner) => self.composably_eq(inner), + Term::FactorAtom(inner) => self.composably_eq(inner), + Term::FactorAtomExponent(inner) => self.composably_eq(inner), + _ => None, + } + } +} + +impl ComposablyEq for Atom { + fn composably_eq(&self, rhs: &Self) -> Option { + if self == rhs { + Some(2) + } else { + None + } + } +} + +impl ComposablyEq for Atom { + fn composably_eq(&self, rhs: &AtomExponent) -> Option { + if *self == rhs.atom { + Some(1 + rhs.exponent) + } else { + None + } + } +} + +impl ComposablyEq for Atom { + fn composably_eq(&self, rhs: &FactorAtom) -> Option { + if rhs.factor == 1 && *self == rhs.atom { + Some(2) + } else { + None + } + } +} + +impl ComposablyEq for Atom { + fn composably_eq(&self, rhs: &FactorAtomExponent) -> Option { + if rhs.factor == 1 && *self == rhs.atom { + Some(1 + rhs.exponent) + } else { + None + } + } +} diff --git a/crates/api/src/composable.rs b/crates/api/src/composable.rs index b2c5595f..84f83cbc 100644 --- a/crates/api/src/composable.rs +++ b/crates/api/src/composable.rs @@ -43,6 +43,6 @@ pub trait Composable { /// - `m2{foo}` and `m2` are _not_ `ComposablyEq`. /// - `km{foo}` and `km` are _not_ `ComposablyEq`. /// -pub(crate) trait ComposablyEq { - fn composably_eq(&self, rhs: &crate::Term) -> bool; +pub(crate) trait ComposablyEq { + fn composably_eq(&self, rhs: &T) -> Option; } diff --git a/crates/api/src/measurement/ops/mul_div.rs b/crates/api/src/measurement/ops/mul_div.rs index c9ca17c7..177284d6 100644 --- a/crates/api/src/measurement/ops/mul_div.rs +++ b/crates/api/src/measurement/ops/mul_div.rs @@ -435,7 +435,7 @@ mod tests { validate_same_unit!( parse_unit!("{tree}"), mul_unit: unit!(term!(factor: 1, exponent: 2, annotation: "tree")), - div_unit: parse_unit!("{tree}") + div_unit: UNITY ); // TODO: https://telusagriculture.atlassian.net/browse/NAUM-122 @@ -496,14 +496,14 @@ mod tests { validate_same_unit!( parse_unit!("m{foo}"), mul_unit: parse_unit!("m2{foo}"), - div_unit: parse_unit!("{foo}") + div_unit: UNITY ); validate_same_unit!( validate_same_dimless, parse_unit!("[ppth]{foo}"), mul_unit: parse_unit!("[ppth]2{foo}"), - div_unit: parse_unit!("{foo}") + div_unit: UNITY ); validate_dim_and_dimless!( @@ -562,14 +562,14 @@ mod tests { validate_same_unit!( parse_unit!("m2{dirt}"), mul_unit: parse_unit!("m4{dirt}"), - div_unit: parse_unit!("{dirt}") + div_unit: UNITY ); validate_same_unit!( validate_same_dimless, parse_unit!("[ppth]2{dirt}"), mul_unit: parse_unit!("[ppth]4{dirt}"), - div_unit: parse_unit!("{dirt}") + div_unit: UNITY ); validate_dim_and_dimless!( @@ -616,7 +616,7 @@ mod tests { validate_same_unit!( parse_unit!("km{dirt}"), mul_unit: parse_unit!("km2{dirt}"), - div_unit: parse_unit!("{dirt}") + div_unit: UNITY ); } @@ -643,7 +643,7 @@ mod tests { validate_same_unit!( parse_unit!("km2{dirt}"), mul_unit: parse_unit!("km4{dirt}"), - div_unit: parse_unit!("{dirt}") + div_unit: UNITY ); } @@ -675,7 +675,7 @@ mod tests { validate_same_unit!( parse_unit!("2{rabbit}"), mul_unit: unit!(term!(factor: 2, exponent: 2, annotation: "rabbit")), - div_unit: parse_unit!("{rabbit}") + div_unit: UNITY ); validate_dim_and_dimless!( @@ -727,7 +727,7 @@ mod tests { validate_same_unit!( unit!(term!(factor: 2, exponent: 2, annotation: "rabbit")), mul_unit: unit!(term!(factor: 2, exponent: 4, annotation: "rabbit")), - div_unit: parse_unit!("{rabbit}") + div_unit: UNITY ); validate_dim_and_dimless!( @@ -804,14 +804,14 @@ mod tests { validate_same_unit!( parse_unit!("2m{raisin}"), mul_unit: parse_unit!("2m2{raisin}"), - div_unit: parse_unit!("{raisin}") + div_unit: UNITY ); validate_same_unit!( validate_same_dimless, parse_unit!("2[ppth]{foo}"), mul_unit: parse_unit!("2[ppth]2{foo}"), - div_unit: parse_unit!("{foo}") + div_unit: UNITY ); validate_dim_and_dimless!( @@ -870,14 +870,14 @@ mod tests { validate_same_unit!( parse_unit!("2m2{dirt}"), mul_unit: parse_unit!("2m4{dirt}"), - div_unit: parse_unit!("{dirt}") + div_unit: UNITY ); validate_same_unit!( validate_same_dimless, parse_unit!("2[ppth]2{dirt}"), mul_unit: parse_unit!("2[ppth]4{dirt}"), - div_unit: parse_unit!("{dirt}") + div_unit: UNITY ); validate_dim_and_dimless!( @@ -924,7 +924,7 @@ mod tests { validate_same_unit!( parse_unit!("2km{string}"), mul_unit: parse_unit!("2km2{string}"), - div_unit: parse_unit!("{string}") + div_unit: UNITY ); } @@ -951,7 +951,29 @@ mod tests { validate_same_unit!( parse_unit!("2km2{dirt}"), mul_unit: parse_unit!("2km4{dirt}"), - div_unit: parse_unit!("{dirt}") + div_unit: UNITY + ); + } + + mod combinations { + use super::*; + + validate_ok!( + same_annotation_in_numerator_and_denominator, + parse_unit!("{meow}/m2"), parse_unit!("g/{meow}"), + mul_values: 2.0, 2.0, + mul_unit: parse_unit!("g/m2"), + div_values: 0.5, 2.0, + div_unit1: unit!( + term!(factor: 1, exponent: 2, annotation: "meow"), + term!(Gram, exponent: -1), + term!(Meter, exponent: -2) + ), + div_unit2: unit!( + term!(factor: 1, exponent: -2, annotation: "meow"), + term!(Gram), + term!(Meter, exponent: 2) + ) ); } } diff --git a/crates/api/src/term.rs b/crates/api/src/term.rs index e51e80bc..8b07a5f5 100644 --- a/crates/api/src/term.rs +++ b/crates/api/src/term.rs @@ -1,7 +1,6 @@ mod annotation_composable; mod builder; mod composable; -mod composably_eq; mod display; mod field_eq; mod invert; @@ -10,6 +9,7 @@ pub(crate) mod num_traits; mod partial_eq; mod partial_ord; mod reducible; +pub(crate) mod term_reduce; mod ucum_unit; #[cfg(feature = "v2")] mod v2; diff --git a/crates/api/src/term/composable.rs b/crates/api/src/term/composable.rs index 270256da..0b2668a4 100644 --- a/crates/api/src/term/composable.rs +++ b/crates/api/src/term/composable.rs @@ -1,8 +1,8 @@ use std::borrow::Cow; -use crate::{Composable, Composition}; +use crate::{composable::ComposablyEq, term::variants::FactorExponent, Composable, Composition}; -use super::Term; +use super::{Exponent, Term}; impl Composable for Term { /// Combines the `Composition` from the `Term`'s `Atom` with its own `exponent` to build a @@ -45,6 +45,50 @@ impl<'a> Composable for Cow<'a, [Term]> { } } +impl ComposablyEq for Term { + fn composably_eq(&self, rhs: &Self) -> Option { + match self { + Self::Annotation(lhs_annotation) => lhs_annotation.composably_eq(rhs), + Self::Atom(lhs_atom) => lhs_atom.composably_eq(rhs), + Self::AtomAnnotation(lhs_inner) => lhs_inner.composably_eq(rhs), + Self::AtomExponent(lhs_inner) => lhs_inner.composably_eq(rhs), + Self::AtomExponentAnnotation(lhs_inner) => lhs_inner.composably_eq(rhs), + Self::PrefixAtom(lhs_inner) => lhs_inner.composably_eq(rhs), + Self::PrefixAtomAnnotation(lhs_inner) => lhs_inner.composably_eq(rhs), + Self::PrefixAtomExponent(lhs_inner) => lhs_inner.composably_eq(rhs), + Self::PrefixAtomExponentAnnotation(lhs_inner) => lhs_inner.composably_eq(rhs), + Self::Factor(lhs_factor) => match rhs { + Self::Factor(factor) => { + if lhs_factor == factor { + Some(2) + } else { + None + } + } + Self::FactorExponent(FactorExponent { factor, exponent }) => { + if lhs_factor == factor { + Some(exponent + 1) + } else { + None + } + } + _ => None, + }, + Self::FactorAnnotation(lhs_inner) => lhs_inner.composably_eq(rhs), + Self::FactorExponent(lhs_inner) => lhs_inner.composably_eq(rhs), + Self::FactorExponentAnnotation(lhs_inner) => lhs_inner.composably_eq(rhs), + Self::FactorAtom(lhs_inner) => lhs_inner.composably_eq(rhs), + Self::FactorAtomAnnotation(lhs_inner) => lhs_inner.composably_eq(rhs), + Self::FactorAtomExponent(lhs_inner) => lhs_inner.composably_eq(rhs), + Self::FactorAtomExponentAnnotation(lhs_inner) => lhs_inner.composably_eq(rhs), + Self::FactorPrefixAtom(lhs_inner) => lhs_inner.composably_eq(rhs), + Self::FactorPrefixAtomAnnotation(lhs_inner) => lhs_inner.composably_eq(rhs), + Self::FactorPrefixAtomExponent(lhs_inner) => lhs_inner.composably_eq(rhs), + Self::FactorPrefixAtomExponentAnnotation(lhs_inner) => lhs_inner.composably_eq(rhs), + } + } +} + #[cfg(test)] mod tests { use crate::Dimension; diff --git a/crates/api/src/term/composably_eq.rs b/crates/api/src/term/composably_eq.rs deleted file mode 100644 index 3d8338f8..00000000 --- a/crates/api/src/term/composably_eq.rs +++ /dev/null @@ -1,111 +0,0 @@ -use crate::{ - composable::ComposablyEq, - term::variants::{ - AtomExponent, FactorAnnotation, FactorAtom, FactorAtomExponent, FactorExponent, - FactorExponentAnnotation, - }, - Term, -}; - -impl ComposablyEq for Term { - fn composably_eq(&self, rhs: &Self) -> bool { - match self { - Self::Annotation(lhs_annotation) => match rhs { - Self::Annotation(rhs_annotation) => lhs_annotation == rhs_annotation, - Self::FactorAnnotation(FactorAnnotation { factor, annotation }) - | Self::FactorExponentAnnotation(FactorExponentAnnotation { - factor, - annotation, - .. - }) => lhs_annotation == annotation && *factor == 1, - Self::Atom(_) - | Self::AtomExponent(_) - | Self::AtomAnnotation(_) - | Self::AtomExponentAnnotation(_) - | Self::PrefixAtomAnnotation(_) - | Self::PrefixAtomExponentAnnotation(_) - | Self::PrefixAtom(_) - | Self::PrefixAtomExponent(_) - | Self::Factor(_) - | Self::FactorExponent(_) - | Self::FactorAtom(_) - | Self::FactorAtomExponent(_) - | Self::FactorPrefixAtom(_) - | Self::FactorAtomAnnotation(_) - | Self::FactorAtomExponentAnnotation(_) - | Self::FactorPrefixAtomAnnotation(_) - | Self::FactorPrefixAtomExponentAnnotation(_) - | Self::FactorPrefixAtomExponent(_) => false, - }, - Self::Atom(lhs_atom) => match rhs { - Self::Atom(atom) | Self::AtomExponent(AtomExponent { atom, .. }) => { - lhs_atom == atom - } - Self::FactorAtom(FactorAtom { factor, atom }) - | Self::FactorAtomExponent(FactorAtomExponent { factor, atom, .. }) => { - lhs_atom == atom && *factor == 1 - } - Self::Factor(_) - | Self::FactorExponent(_) - | Self::PrefixAtom(_) - | Self::PrefixAtomExponent(_) - | Self::FactorPrefixAtom(_) - | Self::FactorPrefixAtomExponent(_) - | Self::Annotation(_) - | Self::AtomAnnotation(_) - | Self::AtomExponentAnnotation(_) - | Self::PrefixAtomAnnotation(_) - | Self::PrefixAtomExponentAnnotation(_) - | Self::FactorAnnotation(_) - | Self::FactorExponentAnnotation(_) - | Self::FactorAtomAnnotation(_) - | Self::FactorAtomExponentAnnotation(_) - | Self::FactorPrefixAtomAnnotation(_) - | Self::FactorPrefixAtomExponentAnnotation(_) => false, - }, - Self::AtomAnnotation(lhs_inner) => lhs_inner.composably_eq(rhs), - Self::AtomExponent(lhs_inner) => lhs_inner.composably_eq(rhs), - Self::AtomExponentAnnotation(lhs_inner) => lhs_inner.composably_eq(rhs), - Self::PrefixAtom(lhs_inner) => lhs_inner.composably_eq(rhs), - Self::PrefixAtomAnnotation(lhs_inner) => lhs_inner.composably_eq(rhs), - Self::PrefixAtomExponent(lhs_inner) => lhs_inner.composably_eq(rhs), - Self::PrefixAtomExponentAnnotation(lhs_inner) => lhs_inner.composably_eq(rhs), - Self::Factor(lhs_factor) => match rhs { - Self::Factor(factor) | Self::FactorExponent(FactorExponent { factor, .. }) => { - lhs_factor == factor - } - - Self::Annotation(_) - | Self::Atom(_) - | Self::AtomAnnotation(_) - | Self::AtomExponent(_) - | Self::AtomExponentAnnotation(_) - | Self::PrefixAtom(_) - | Self::PrefixAtomAnnotation(_) - | Self::PrefixAtomExponent(_) - | Self::PrefixAtomExponentAnnotation(_) - | Self::FactorAnnotation(_) - | Self::FactorExponentAnnotation(_) - | Self::FactorAtom(_) - | Self::FactorAtomAnnotation(_) - | Self::FactorAtomExponent(_) - | Self::FactorAtomExponentAnnotation(_) - | Self::FactorPrefixAtom(_) - | Self::FactorPrefixAtomAnnotation(_) - | Self::FactorPrefixAtomExponent(_) - | Self::FactorPrefixAtomExponentAnnotation(_) => false, - }, - Self::FactorAnnotation(lhs_inner) => lhs_inner.composably_eq(rhs), - Self::FactorExponent(lhs_inner) => lhs_inner.composably_eq(rhs), - Self::FactorExponentAnnotation(lhs_inner) => lhs_inner.composably_eq(rhs), - Self::FactorAtom(lhs_inner) => lhs_inner.composably_eq(rhs), - Self::FactorAtomAnnotation(lhs_inner) => lhs_inner.composably_eq(rhs), - Self::FactorAtomExponent(lhs_inner) => lhs_inner.composably_eq(rhs), - Self::FactorAtomExponentAnnotation(lhs_inner) => lhs_inner.composably_eq(rhs), - Self::FactorPrefixAtom(lhs_inner) => lhs_inner.composably_eq(rhs), - Self::FactorPrefixAtomAnnotation(lhs_inner) => lhs_inner.composably_eq(rhs), - Self::FactorPrefixAtomExponent(lhs_inner) => lhs_inner.composably_eq(rhs), - Self::FactorPrefixAtomExponentAnnotation(lhs_inner) => lhs_inner.composably_eq(rhs), - } - } -} diff --git a/crates/api/src/term/term_reduce.rs b/crates/api/src/term/term_reduce.rs new file mode 100644 index 00000000..9ac87181 --- /dev/null +++ b/crates/api/src/term/term_reduce.rs @@ -0,0 +1,71 @@ +use crate::Term; + +use super::{ + variants::{AtomExponent, FactorExponent}, + Exponent, +}; + +pub(crate) enum ReducedTerm { + ReducedToTerm(Term), + ReducedAway, + NotReducible, +} + +pub(crate) trait TermReduce: crate::composable::ComposablyEq { + fn term_reduce(&self, rhs: &Term) -> ReducedTerm { + match self.composably_eq(rhs) { + Some(0) => ReducedTerm::ReducedAway, + Some(exponent) => ReducedTerm::ReducedToTerm(self.build(exponent).into()), + None => ReducedTerm::NotReducible, + } + } + fn build(&self, exponent: Exponent) -> Term; +} + +impl TermReduce for Term { + fn build(&self, exponent: Exponent) -> Term { + match self { + Self::Annotation(lhs) => lhs.build(exponent), + Self::Atom(lhs) => lhs.build(exponent), + Self::AtomAnnotation(lhs) => lhs.build(exponent), + Self::AtomExponent(lhs) => lhs.build(exponent), + Self::AtomExponentAnnotation(lhs) => lhs.build(exponent), + Self::PrefixAtom(lhs) => lhs.build(exponent), + Self::PrefixAtomAnnotation(lhs) => lhs.build(exponent), + Self::PrefixAtomExponent(lhs) => lhs.build(exponent), + Self::PrefixAtomExponentAnnotation(lhs) => lhs.build(exponent), + Self::Factor(factor) => { + let factor = *factor; + if exponent == 1 { + Self::Factor(factor) + } else { + Self::FactorExponent(FactorExponent { factor, exponent }) + } + } + Self::FactorAnnotation(lhs) => lhs.build(exponent), + Self::FactorExponent(lhs) => lhs.build(exponent), + Self::FactorExponentAnnotation(lhs) => lhs.build(exponent), + Self::FactorAtom(lhs) => lhs.build(exponent), + Self::FactorAtomAnnotation(lhs) => lhs.build(exponent), + Self::FactorAtomExponent(lhs) => lhs.build(exponent), + Self::FactorAtomExponentAnnotation(lhs) => lhs.build(exponent), + Self::FactorPrefixAtom(lhs) => lhs.build(exponent), + Self::FactorPrefixAtomAnnotation(lhs) => lhs.build(exponent), + Self::FactorPrefixAtomExponent(lhs) => lhs.build(exponent), + Self::FactorPrefixAtomExponentAnnotation(lhs) => lhs.build(exponent), + } + } +} + +impl TermReduce for crate::Atom { + fn build(&self, exponent: Exponent) -> Term { + if exponent == 1 { + Term::Atom(*self) + } else { + Term::AtomExponent(AtomExponent { + atom: *self, + exponent, + }) + } + } +} diff --git a/crates/api/src/term/variants/atom_annotation.rs b/crates/api/src/term/variants/atom_annotation.rs index bfaf693a..2fd5ccc1 100644 --- a/crates/api/src/term/variants/atom_annotation.rs +++ b/crates/api/src/term/variants/atom_annotation.rs @@ -2,7 +2,10 @@ use std::{fmt, mem}; use num_traits::{Inv, Pow}; -use crate::{composable::ComposablyEq, Atom, Composable, IsCompatibleWith, UcumUnit}; +use crate::{ + composable::ComposablyEq, term::term_reduce::TermReduce, Atom, Composable, IsCompatibleWith, + UcumUnit, +}; use super::{ Annotation, AssignFactor, AtomExponentAnnotation, Exponent, Factor, FactorAtomAnnotation, @@ -158,41 +161,54 @@ impl<'a> SetAnnotation for &'a mut AtomAnnotation { } } -impl ComposablyEq for AtomAnnotation { - fn composably_eq(&self, rhs: &Term) -> bool { +impl ComposablyEq for AtomAnnotation { + fn composably_eq(&self, rhs: &Term) -> Option { match rhs { - Term::AtomAnnotation(Self { atom, annotation }) - | Term::AtomExponentAnnotation(AtomExponentAnnotation { - atom, annotation, .. - }) => self.atom == *atom && &self.annotation == annotation, - Term::FactorAtomAnnotation(FactorAtomAnnotation { - factor, - atom, - annotation, - }) - | Term::FactorAtomExponentAnnotation(FactorAtomExponentAnnotation { - factor, - atom, - annotation, - .. - }) => *factor == 1 && self.atom == *atom && &self.annotation == annotation, - Term::Annotation(_) - | Term::Atom(_) - | Term::AtomExponent(_) - | Term::PrefixAtom(_) - | Term::PrefixAtomAnnotation(_) - | Term::PrefixAtomExponent(_) - | Term::PrefixAtomExponentAnnotation(_) - | Term::Factor(_) - | Term::FactorAnnotation(_) - | Term::FactorExponent(_) - | Term::FactorExponentAnnotation(_) - | Term::FactorAtom(_) - | Term::FactorAtomExponent(_) - | Term::FactorPrefixAtom(_) - | Term::FactorPrefixAtomAnnotation(_) - | Term::FactorPrefixAtomExponent(_) - | Term::FactorPrefixAtomExponentAnnotation(_) => false, + Term::AtomAnnotation(inner) => self.composably_eq(inner), + Term::AtomExponentAnnotation(inner) => self.composably_eq(inner), + Term::FactorAtomAnnotation(inner) => self.composably_eq(inner), + Term::FactorAtomExponentAnnotation(inner) => self.composably_eq(inner), + _ => None, + } + } +} + +impl ComposablyEq for AtomAnnotation { + fn composably_eq(&self, rhs: &Self) -> Option { + if self.atom == rhs.atom && self.annotation == rhs.annotation { + Some(2) + } else { + None + } + } +} + +impl ComposablyEq for AtomAnnotation { + fn composably_eq(&self, rhs: &AtomExponentAnnotation) -> Option { + if self.atom == rhs.atom && self.annotation == rhs.annotation { + Some(1 + rhs.exponent) + } else { + None + } + } +} + +impl ComposablyEq for AtomAnnotation { + fn composably_eq(&self, rhs: &FactorAtomAnnotation) -> Option { + if rhs.factor == 1 && self.atom == rhs.atom && self.annotation == rhs.annotation { + Some(2) + } else { + None + } + } +} + +impl ComposablyEq for AtomAnnotation { + fn composably_eq(&self, rhs: &FactorAtomExponentAnnotation) -> Option { + if rhs.factor == 1 && self.atom == rhs.atom && self.annotation == rhs.annotation { + Some(1 + rhs.exponent) + } else { + None } } } @@ -209,3 +225,20 @@ impl IsCompatibleWith for AtomAnnotation { && Some(self.annotation.as_str()) == rhs.annotation() } } + +impl TermReduce for AtomAnnotation { + fn build(&self, exponent: Exponent) -> Term { + if exponent == 1 { + Term::AtomAnnotation(Self { + atom: self.atom, + annotation: self.annotation.clone(), + }) + } else { + Term::AtomExponentAnnotation(AtomExponentAnnotation { + atom: self.atom, + exponent, + annotation: self.annotation.clone(), + }) + } + } +} diff --git a/crates/api/src/term/variants/atom_exponent.rs b/crates/api/src/term/variants/atom_exponent.rs index 7a29dd15..1d55c10c 100644 --- a/crates/api/src/term/variants/atom_exponent.rs +++ b/crates/api/src/term/variants/atom_exponent.rs @@ -2,7 +2,10 @@ use std::fmt; use num_traits::{Inv, Pow}; -use crate::{composable::ComposablyEq, Annotation, Atom, Composable, IsCompatibleWith, UcumUnit}; +use crate::{ + composable::ComposablyEq, term::term_reduce::TermReduce, Annotation, Atom, Composable, + IsCompatibleWith, UcumUnit, +}; use super::{ AssignFactor, AtomExponentAnnotation, Exponent, Factor, FactorAtom, FactorAtomExponent, @@ -142,31 +145,54 @@ impl SetAnnotation for AtomExponent { } } -impl ComposablyEq for AtomExponent { - fn composably_eq(&self, rhs: &Term) -> bool { +impl ComposablyEq for AtomExponent { + fn composably_eq(&self, rhs: &Term) -> Option { match rhs { - Term::Atom(atom) | Term::AtomExponent(Self { atom, .. }) => self.atom == *atom, - Term::FactorAtom(FactorAtom { factor, atom }) - | Term::FactorAtomExponent(FactorAtomExponent { factor, atom, .. }) => { - self.atom == *atom && *factor == 1 - } - Term::Annotation(_) - | Term::AtomAnnotation(_) - | Term::AtomExponentAnnotation(_) - | Term::PrefixAtom(_) - | Term::PrefixAtomExponent(_) - | Term::PrefixAtomAnnotation(_) - | Term::PrefixAtomExponentAnnotation(_) - | Term::Factor(_) - | Term::FactorExponent(_) - | Term::FactorAnnotation(_) - | Term::FactorExponentAnnotation(_) - | Term::FactorAtomAnnotation(_) - | Term::FactorAtomExponentAnnotation(_) - | Term::FactorPrefixAtom(_) - | Term::FactorPrefixAtomExponent(_) - | Term::FactorPrefixAtomAnnotation(_) - | Term::FactorPrefixAtomExponentAnnotation(_) => false, + Term::Atom(atom) => self.composably_eq(atom), + Term::AtomExponent(inner) => self.composably_eq(inner), + Term::FactorAtom(inner) => self.composably_eq(inner), + Term::FactorAtomExponent(inner) => self.composably_eq(inner), + _ => None, + } + } +} + +impl ComposablyEq for AtomExponent { + fn composably_eq(&self, rhs: &Atom) -> Option { + if self.atom == *rhs { + Some(self.exponent + 1) + } else { + None + } + } +} + +impl ComposablyEq for AtomExponent { + fn composably_eq(&self, rhs: &Self) -> Option { + if self.atom == rhs.atom { + Some(self.exponent + rhs.exponent) + } else { + None + } + } +} + +impl ComposablyEq for AtomExponent { + fn composably_eq(&self, rhs: &FactorAtom) -> Option { + if rhs.factor == 1 && self.atom == rhs.atom { + Some(self.exponent + 1) + } else { + None + } + } +} + +impl ComposablyEq for AtomExponent { + fn composably_eq(&self, rhs: &FactorAtomExponent) -> Option { + if rhs.factor == 1 && self.atom == rhs.atom { + Some(self.exponent + rhs.exponent) + } else { + None } } } @@ -182,3 +208,16 @@ impl IsCompatibleWith for AtomExponent { self.composition() == rhs.composition() && rhs.annotation().is_none() } } + +impl TermReduce for AtomExponent { + fn build(&self, exponent: Exponent) -> Term { + if exponent == 1 { + Term::Atom(self.atom) + } else { + Term::AtomExponent(Self { + atom: self.atom, + exponent, + }) + } + } +} diff --git a/crates/api/src/term/variants/atom_exponent_annotation.rs b/crates/api/src/term/variants/atom_exponent_annotation.rs index 5d5db197..dcf9f11e 100644 --- a/crates/api/src/term/variants/atom_exponent_annotation.rs +++ b/crates/api/src/term/variants/atom_exponent_annotation.rs @@ -2,7 +2,10 @@ use std::{fmt, mem}; use num_traits::{Inv, Pow}; -use crate::{composable::ComposablyEq, Atom, Composable, IsCompatibleWith, UcumUnit}; +use crate::{ + composable::ComposablyEq, term::term_reduce::TermReduce, Atom, Composable, IsCompatibleWith, + UcumUnit, +}; use super::{ Annotation, AssignFactor, AtomAnnotation, Exponent, Factor, FactorAtomAnnotation, @@ -182,42 +185,54 @@ impl<'a> SetAnnotation for &'a mut AtomExponentAnnotation { } } -impl ComposablyEq for AtomExponentAnnotation { - fn composably_eq(&self, rhs: &Term) -> bool { +impl ComposablyEq for AtomExponentAnnotation { + fn composably_eq(&self, rhs: &Term) -> Option { match rhs { - Term::AtomAnnotation(AtomAnnotation { atom, annotation }) - | Term::AtomExponentAnnotation(Self { - atom, annotation, .. - }) => self.atom == *atom && &self.annotation == annotation, - Term::FactorAtomAnnotation(FactorAtomAnnotation { - factor, - atom, - annotation, - }) - | Term::FactorAtomExponentAnnotation(FactorAtomExponentAnnotation { - factor, - atom, - annotation, - .. - }) => *factor == 1 && self.atom == *atom && &self.annotation == annotation, - - Term::Annotation(_) - | Term::Atom(_) - | Term::AtomExponent(_) - | Term::PrefixAtom(_) - | Term::PrefixAtomAnnotation(_) - | Term::PrefixAtomExponent(_) - | Term::PrefixAtomExponentAnnotation(_) - | Term::Factor(_) - | Term::FactorAnnotation(_) - | Term::FactorExponent(_) - | Term::FactorExponentAnnotation(_) - | Term::FactorAtom(_) - | Term::FactorAtomExponent(_) - | Term::FactorPrefixAtom(_) - | Term::FactorPrefixAtomAnnotation(_) - | Term::FactorPrefixAtomExponent(_) - | Term::FactorPrefixAtomExponentAnnotation(_) => false, + Term::AtomAnnotation(inner) => self.composably_eq(inner), + Term::AtomExponentAnnotation(inner) => self.composably_eq(inner), + Term::FactorAtomAnnotation(inner) => self.composably_eq(inner), + Term::FactorAtomExponentAnnotation(inner) => self.composably_eq(inner), + _ => None, + } + } +} + +impl ComposablyEq for AtomExponentAnnotation { + fn composably_eq(&self, rhs: &AtomAnnotation) -> Option { + if self.atom == rhs.atom && self.annotation == rhs.annotation { + Some(self.exponent + 1) + } else { + None + } + } +} + +impl ComposablyEq for AtomExponentAnnotation { + fn composably_eq(&self, rhs: &Self) -> Option { + if self.atom == rhs.atom && self.annotation == rhs.annotation { + Some(self.exponent + rhs.exponent) + } else { + None + } + } +} + +impl ComposablyEq for AtomExponentAnnotation { + fn composably_eq(&self, rhs: &FactorAtomAnnotation) -> Option { + if rhs.factor == 1 && self.atom == rhs.atom && self.annotation == rhs.annotation { + Some(self.exponent + 1) + } else { + None + } + } +} + +impl ComposablyEq for AtomExponentAnnotation { + fn composably_eq(&self, rhs: &FactorAtomExponentAnnotation) -> Option { + if rhs.factor == 1 && self.atom == rhs.atom && self.annotation == rhs.annotation { + Some(self.exponent + rhs.exponent) + } else { + None } } } @@ -234,3 +249,20 @@ impl IsCompatibleWith for AtomExponentAnnotation { && Some(self.annotation.as_str()) == rhs.annotation() } } + +impl TermReduce for AtomExponentAnnotation { + fn build(&self, exponent: Exponent) -> Term { + if exponent == 1 { + Term::AtomAnnotation(AtomAnnotation { + atom: self.atom, + annotation: self.annotation.clone(), + }) + } else { + Term::AtomExponentAnnotation(Self { + atom: self.atom, + exponent, + annotation: self.annotation.clone(), + }) + } + } +} diff --git a/crates/api/src/term/variants/factor_annotation.rs b/crates/api/src/term/variants/factor_annotation.rs index 5cac284e..a2558e48 100644 --- a/crates/api/src/term/variants/factor_annotation.rs +++ b/crates/api/src/term/variants/factor_annotation.rs @@ -2,7 +2,9 @@ use std::{fmt, mem}; use num_traits::{Inv, Pow}; -use crate::{composable::ComposablyEq, Composable, IsCompatibleWith}; +use crate::{ + composable::ComposablyEq, term::term_reduce::TermReduce, Composable, IsCompatibleWith, +}; use super::{ Annotation, Exponent, Factor, FactorExponentAnnotation, PowOutput, SetAnnotation, SetExponent, @@ -143,33 +145,43 @@ impl<'a> SetAnnotation for &'a mut FactorAnnotation { } } -impl ComposablyEq for FactorAnnotation { - fn composably_eq(&self, rhs: &Term) -> bool { +impl ComposablyEq for FactorAnnotation { + fn composably_eq(&self, rhs: &Term) -> Option { match rhs { - Term::Annotation(annotation) => self.factor == 1 && &self.annotation == annotation, - Term::FactorAnnotation(rhs_inner) => self == rhs_inner, - Term::FactorExponentAnnotation(FactorExponentAnnotation { - factor, annotation, .. - }) => self.factor == *factor && &self.annotation == annotation, - - Term::Atom(_) - | Term::AtomAnnotation(_) - | Term::AtomExponent(_) - | Term::AtomExponentAnnotation(_) - | Term::PrefixAtom(_) - | Term::PrefixAtomAnnotation(_) - | Term::PrefixAtomExponent(_) - | Term::PrefixAtomExponentAnnotation(_) - | Term::Factor(_) - | Term::FactorExponent(_) - | Term::FactorAtom(_) - | Term::FactorAtomAnnotation(_) - | Term::FactorAtomExponent(_) - | Term::FactorAtomExponentAnnotation(_) - | Term::FactorPrefixAtom(_) - | Term::FactorPrefixAtomAnnotation(_) - | Term::FactorPrefixAtomExponent(_) - | Term::FactorPrefixAtomExponentAnnotation(_) => false, + Term::Annotation(annotation) => self.composably_eq(annotation), + Term::FactorAnnotation(inner) => self.composably_eq(inner), + Term::FactorExponentAnnotation(inner) => self.composably_eq(inner), + _ => None, + } + } +} + +impl ComposablyEq for FactorAnnotation { + fn composably_eq(&self, rhs: &Annotation) -> Option { + if self.factor == 1 && &self.annotation == rhs { + Some(2) + } else { + None + } + } +} + +impl ComposablyEq for FactorAnnotation { + fn composably_eq(&self, rhs: &Self) -> Option { + if self == rhs { + Some(2) + } else { + None + } + } +} + +impl ComposablyEq for FactorAnnotation { + fn composably_eq(&self, rhs: &FactorExponentAnnotation) -> Option { + if self.factor == rhs.factor && self.annotation == rhs.annotation { + Some(1 + rhs.exponent) + } else { + None } } } @@ -186,3 +198,20 @@ impl IsCompatibleWith for FactorAnnotation { && Some(self.annotation.as_str()) == rhs.annotation() } } + +impl TermReduce for FactorAnnotation { + fn build(&self, exponent: Exponent) -> Term { + match (self.factor, exponent) { + (1, 1) => Term::Annotation(self.annotation.clone()), + (_, 1) => Term::FactorAnnotation(Self { + factor: self.factor, + annotation: self.annotation.clone(), + }), + (_, _) => Term::FactorExponentAnnotation(FactorExponentAnnotation { + factor: self.factor, + exponent, + annotation: self.annotation.clone(), + }), + } + } +} diff --git a/crates/api/src/term/variants/factor_atom.rs b/crates/api/src/term/variants/factor_atom.rs index d4cabf8b..5f34be8a 100644 --- a/crates/api/src/term/variants/factor_atom.rs +++ b/crates/api/src/term/variants/factor_atom.rs @@ -2,7 +2,10 @@ use std::fmt; use num_traits::{Inv, Pow}; -use crate::{composable::ComposablyEq, Annotation, Atom, Composable, IsCompatibleWith, UcumUnit}; +use crate::{ + composable::ComposablyEq, term::term_reduce::TermReduce, Annotation, Atom, Composable, + IsCompatibleWith, UcumUnit, +}; use super::{ AtomExponent, Exponent, Factor, FactorAtomAnnotation, FactorAtomExponent, PowOutput, @@ -121,34 +124,54 @@ impl SetAnnotation for FactorAtom { } } -impl ComposablyEq for FactorAtom { - fn composably_eq(&self, rhs: &Term) -> bool { +impl ComposablyEq for FactorAtom { + fn composably_eq(&self, rhs: &Term) -> Option { match rhs { - Term::Atom(atom) | Term::AtomExponent(AtomExponent { atom, .. }) => { - self.factor == 1 && self.atom == *atom - } - Term::FactorAtom(rhs_inner) => self == rhs_inner, - Term::FactorAtomExponent(FactorAtomExponent { factor, atom, .. }) => { - self.factor == *factor && self.atom == *atom - } - - Term::Annotation(_) - | Term::AtomAnnotation(_) - | Term::AtomExponentAnnotation(_) - | Term::PrefixAtom(_) - | Term::PrefixAtomAnnotation(_) - | Term::PrefixAtomExponent(_) - | Term::PrefixAtomExponentAnnotation(_) - | Term::Factor(_) - | Term::FactorAnnotation(_) - | Term::FactorExponent(_) - | Term::FactorExponentAnnotation(_) - | Term::FactorAtomAnnotation(_) - | Term::FactorAtomExponentAnnotation(_) - | Term::FactorPrefixAtom(_) - | Term::FactorPrefixAtomAnnotation(_) - | Term::FactorPrefixAtomExponent(_) - | Term::FactorPrefixAtomExponentAnnotation(_) => false, + Term::Atom(atom) => self.composably_eq(atom), + Term::AtomExponent(inner) => self.composably_eq(inner), + Term::FactorAtom(inner) => self.composably_eq(inner), + Term::FactorAtomExponent(inner) => self.composably_eq(inner), + _ => None, + } + } +} + +impl ComposablyEq for FactorAtom { + fn composably_eq(&self, rhs: &Atom) -> Option { + if self.factor == 1 && self.atom == *rhs { + Some(2) + } else { + None + } + } +} + +impl ComposablyEq for FactorAtom { + fn composably_eq(&self, rhs: &AtomExponent) -> Option { + if self.factor == 1 && self.atom == rhs.atom { + Some(1 + rhs.exponent) + } else { + None + } + } +} + +impl ComposablyEq for FactorAtom { + fn composably_eq(&self, rhs: &Self) -> Option { + if self == rhs { + Some(2) + } else { + None + } + } +} + +impl ComposablyEq for FactorAtom { + fn composably_eq(&self, rhs: &FactorAtomExponent) -> Option { + if self.factor == rhs.factor && self.atom == rhs.atom { + Some(1 + rhs.exponent) + } else { + None } } } @@ -164,3 +187,24 @@ impl IsCompatibleWith for FactorAtom { self.composition() == rhs.composition() && rhs.annotation().is_none() } } + +impl TermReduce for FactorAtom { + fn build(&self, exponent: Exponent) -> Term { + match (self.factor, exponent) { + (1, 1) => Term::Atom(self.atom), + (1, _) => Term::AtomExponent(AtomExponent { + atom: self.atom, + exponent, + }), + (_, 1) => Term::FactorAtom(Self { + factor: self.factor, + atom: self.atom, + }), + (_, _) => Term::FactorAtomExponent(FactorAtomExponent { + factor: self.factor, + atom: self.atom, + exponent, + }), + } + } +} diff --git a/crates/api/src/term/variants/factor_atom_annotation.rs b/crates/api/src/term/variants/factor_atom_annotation.rs index 8a9e92ca..fd22e817 100644 --- a/crates/api/src/term/variants/factor_atom_annotation.rs +++ b/crates/api/src/term/variants/factor_atom_annotation.rs @@ -2,7 +2,10 @@ use std::{fmt, mem}; use num_traits::{Inv, Pow}; -use crate::{composable::ComposablyEq, Atom, Composable, IsCompatibleWith, UcumUnit}; +use crate::{ + composable::ComposablyEq, term::term_reduce::TermReduce, Atom, Composable, IsCompatibleWith, + UcumUnit, +}; use super::{ Annotation, AtomAnnotation, AtomExponentAnnotation, Exponent, Factor, @@ -154,42 +157,54 @@ impl<'a> SetAnnotation for &'a mut FactorAtomAnnotation { } } -impl ComposablyEq for FactorAtomAnnotation { - fn composably_eq(&self, rhs: &Term) -> bool { +impl ComposablyEq for FactorAtomAnnotation { + fn composably_eq(&self, rhs: &Term) -> Option { match rhs { - Term::AtomAnnotation(AtomAnnotation { atom, annotation }) - | Term::AtomExponentAnnotation(AtomExponentAnnotation { - atom, annotation, .. - }) => self.factor == 1 && self.atom == *atom && &self.annotation == annotation, - Term::FactorAtomAnnotation(Self { - factor, - atom, - annotation, - }) - | Term::FactorAtomExponentAnnotation(FactorAtomExponentAnnotation { - factor, - atom, - annotation, - .. - }) => self.factor == *factor && self.atom == *atom && &self.annotation == annotation, - - Term::Annotation(_) - | Term::Atom(_) - | Term::AtomExponent(_) - | Term::PrefixAtom(_) - | Term::PrefixAtomAnnotation(_) - | Term::PrefixAtomExponent(_) - | Term::PrefixAtomExponentAnnotation(_) - | Term::Factor(_) - | Term::FactorAnnotation(_) - | Term::FactorExponent(_) - | Term::FactorExponentAnnotation(_) - | Term::FactorAtom(_) - | Term::FactorAtomExponent(_) - | Term::FactorPrefixAtom(_) - | Term::FactorPrefixAtomAnnotation(_) - | Term::FactorPrefixAtomExponent(_) - | Term::FactorPrefixAtomExponentAnnotation(_) => false, + Term::AtomAnnotation(inner) => self.composably_eq(inner), + Term::AtomExponentAnnotation(inner) => self.composably_eq(inner), + Term::FactorAtomAnnotation(inner) => self.composably_eq(inner), + Term::FactorAtomExponentAnnotation(inner) => self.composably_eq(inner), + _ => None, + } + } +} + +impl ComposablyEq for FactorAtomAnnotation { + fn composably_eq(&self, rhs: &AtomAnnotation) -> Option { + if self.factor == 1 && self.atom == rhs.atom && self.annotation == rhs.annotation { + Some(2) + } else { + None + } + } +} + +impl ComposablyEq for FactorAtomAnnotation { + fn composably_eq(&self, rhs: &AtomExponentAnnotation) -> Option { + if self.factor == 1 && self.atom == rhs.atom && self.annotation == rhs.annotation { + Some(1 + rhs.exponent) + } else { + None + } + } +} + +impl ComposablyEq for FactorAtomAnnotation { + fn composably_eq(&self, rhs: &Self) -> Option { + if self == rhs { + Some(2) + } else { + None + } + } +} + +impl ComposablyEq for FactorAtomAnnotation { + fn composably_eq(&self, rhs: &FactorAtomExponentAnnotation) -> Option { + if self.factor == rhs.factor && self.atom == rhs.atom && self.annotation == rhs.annotation { + Some(1 + rhs.exponent) + } else { + None } } } @@ -206,3 +221,30 @@ impl IsCompatibleWith for FactorAtomAnnotation { && Some(self.annotation.as_str()) == rhs.annotation() } } + +impl TermReduce for FactorAtomAnnotation { + fn build(&self, exponent: Exponent) -> Term { + match (self.factor, exponent) { + (1, 1) => Term::AtomAnnotation(AtomAnnotation { + atom: self.atom, + annotation: self.annotation.clone(), + }), + (1, _) => Term::AtomExponentAnnotation(AtomExponentAnnotation { + atom: self.atom, + exponent, + annotation: self.annotation.clone(), + }), + (_, 1) => Term::FactorAtomAnnotation(Self { + factor: self.factor, + atom: self.atom, + annotation: self.annotation.clone(), + }), + (_, _) => Term::FactorAtomExponentAnnotation(FactorAtomExponentAnnotation { + factor: self.factor, + atom: self.atom, + exponent, + annotation: self.annotation.clone(), + }), + } + } +} diff --git a/crates/api/src/term/variants/factor_atom_exponent.rs b/crates/api/src/term/variants/factor_atom_exponent.rs index a14cde32..4ab9226e 100644 --- a/crates/api/src/term/variants/factor_atom_exponent.rs +++ b/crates/api/src/term/variants/factor_atom_exponent.rs @@ -2,7 +2,10 @@ use std::fmt; use num_traits::{Inv, Pow}; -use crate::{composable::ComposablyEq, Annotation, Atom, Composable, IsCompatibleWith, UcumUnit}; +use crate::{ + composable::ComposablyEq, term::term_reduce::TermReduce, Annotation, Atom, Composable, + IsCompatibleWith, UcumUnit, +}; use super::{ AtomExponent, Exponent, Factor, FactorAtom, FactorAtomExponentAnnotation, InvOutput, PowOutput, @@ -155,34 +158,54 @@ impl SetAnnotation for FactorAtomExponent { } } -impl ComposablyEq for FactorAtomExponent { - fn composably_eq(&self, rhs: &Term) -> bool { +impl ComposablyEq for FactorAtomExponent { + fn composably_eq(&self, rhs: &Term) -> Option { match rhs { - Term::Atom(atom) | Term::AtomExponent(AtomExponent { atom, .. }) => { - self.factor == 1 && self.atom == *atom - } - Term::FactorAtom(FactorAtom { factor, atom }) - | Term::FactorAtomExponent(Self { factor, atom, .. }) => { - self.factor == *factor && self.atom == *atom - } + Term::Atom(inner) => self.composably_eq(inner), + Term::AtomExponent(inner) => self.composably_eq(inner), + Term::FactorAtom(inner) => self.composably_eq(inner), + Term::FactorAtomExponent(inner) => self.composably_eq(inner), + _ => None, + } + } +} + +impl ComposablyEq for FactorAtomExponent { + fn composably_eq(&self, rhs: &Atom) -> Option { + if self.factor == 1 && self.atom == *rhs { + Some(self.exponent + 1) + } else { + None + } + } +} + +impl ComposablyEq for FactorAtomExponent { + fn composably_eq(&self, rhs: &AtomExponent) -> Option { + if self.factor == 1 && self.atom == rhs.atom { + Some(self.exponent + rhs.exponent) + } else { + None + } + } +} + +impl ComposablyEq for FactorAtomExponent { + fn composably_eq(&self, rhs: &FactorAtom) -> Option { + if self.factor == rhs.factor && self.atom == rhs.atom { + Some(self.exponent + 1) + } else { + None + } + } +} - Term::Annotation(_) - | Term::AtomAnnotation(_) - | Term::AtomExponentAnnotation(_) - | Term::PrefixAtom(_) - | Term::PrefixAtomAnnotation(_) - | Term::PrefixAtomExponent(_) - | Term::PrefixAtomExponentAnnotation(_) - | Term::Factor(_) - | Term::FactorAnnotation(_) - | Term::FactorExponent(_) - | Term::FactorExponentAnnotation(_) - | Term::FactorAtomAnnotation(_) - | Term::FactorAtomExponentAnnotation(_) - | Term::FactorPrefixAtom(_) - | Term::FactorPrefixAtomAnnotation(_) - | Term::FactorPrefixAtomExponent(_) - | Term::FactorPrefixAtomExponentAnnotation(_) => false, +impl ComposablyEq for FactorAtomExponent { + fn composably_eq(&self, rhs: &Self) -> Option { + if self.factor == rhs.factor && self.atom == rhs.atom { + Some(self.exponent + rhs.exponent) + } else { + None } } } @@ -198,3 +221,24 @@ impl IsCompatibleWith for FactorAtomExponent { self.composition() == rhs.composition() && rhs.annotation().is_none() } } + +impl TermReduce for FactorAtomExponent { + fn build(&self, exponent: Exponent) -> Term { + match (self.factor, exponent) { + (1, 1) => Term::Atom(self.atom), + (1, _) => Term::AtomExponent(AtomExponent { + atom: self.atom, + exponent, + }), + (_, 1) => Term::FactorAtom(FactorAtom { + factor: self.factor, + atom: self.atom, + }), + (_, _) => Term::FactorAtomExponent(Self { + factor: self.factor, + atom: self.atom, + exponent, + }), + } + } +} diff --git a/crates/api/src/term/variants/factor_atom_exponent_annotation.rs b/crates/api/src/term/variants/factor_atom_exponent_annotation.rs index 71e94894..048c3739 100644 --- a/crates/api/src/term/variants/factor_atom_exponent_annotation.rs +++ b/crates/api/src/term/variants/factor_atom_exponent_annotation.rs @@ -2,7 +2,10 @@ use std::{fmt, mem}; use num_traits::{Inv, Pow}; -use crate::{composable::ComposablyEq, Atom, Composable, IsCompatibleWith, UcumUnit}; +use crate::{ + composable::ComposablyEq, term::term_reduce::TermReduce, Atom, Composable, IsCompatibleWith, + UcumUnit, +}; use super::{ Annotation, AtomAnnotation, AtomExponentAnnotation, Exponent, Factor, FactorAtomAnnotation, @@ -210,42 +213,54 @@ impl<'a> SetAnnotation for &'a mut FactorAtomExponentAnnotation { } } -impl ComposablyEq for FactorAtomExponentAnnotation { - fn composably_eq(&self, rhs: &Term) -> bool { +impl ComposablyEq for FactorAtomExponentAnnotation { + fn composably_eq(&self, rhs: &Term) -> Option { match rhs { - Term::AtomAnnotation(AtomAnnotation { atom, annotation }) - | Term::AtomExponentAnnotation(AtomExponentAnnotation { - atom, annotation, .. - }) => self.factor == 1 && self.atom == *atom && &self.annotation == annotation, - Term::FactorAtomAnnotation(FactorAtomAnnotation { - factor, - atom, - annotation, - }) - | Term::FactorAtomExponentAnnotation(Self { - factor, - atom, - annotation, - .. - }) => self.factor == *factor && self.atom == *atom && &self.annotation == annotation, - - Term::Annotation(_) - | Term::Atom(_) - | Term::AtomExponent(_) - | Term::PrefixAtom(_) - | Term::PrefixAtomAnnotation(_) - | Term::PrefixAtomExponent(_) - | Term::PrefixAtomExponentAnnotation(_) - | Term::Factor(_) - | Term::FactorAnnotation(_) - | Term::FactorExponent(_) - | Term::FactorExponentAnnotation(_) - | Term::FactorAtom(_) - | Term::FactorAtomExponent(_) - | Term::FactorPrefixAtom(_) - | Term::FactorPrefixAtomAnnotation(_) - | Term::FactorPrefixAtomExponent(_) - | Term::FactorPrefixAtomExponentAnnotation(_) => false, + Term::AtomAnnotation(inner) => self.composably_eq(inner), + Term::AtomExponentAnnotation(inner) => self.composably_eq(inner), + Term::FactorAtomAnnotation(inner) => self.composably_eq(inner), + Term::FactorAtomExponentAnnotation(inner) => self.composably_eq(inner), + _ => None, + } + } +} + +impl ComposablyEq for FactorAtomExponentAnnotation { + fn composably_eq(&self, rhs: &AtomAnnotation) -> Option { + if self.factor == 1 && self.atom == rhs.atom && self.annotation == rhs.annotation { + Some(self.exponent + 1) + } else { + None + } + } +} + +impl ComposablyEq for FactorAtomExponentAnnotation { + fn composably_eq(&self, rhs: &AtomExponentAnnotation) -> Option { + if self.factor == 1 && self.atom == rhs.atom && self.annotation == rhs.annotation { + Some(self.exponent + rhs.exponent) + } else { + None + } + } +} + +impl ComposablyEq for FactorAtomExponentAnnotation { + fn composably_eq(&self, rhs: &FactorAtomAnnotation) -> Option { + if self.factor == rhs.factor && self.atom == rhs.atom && self.annotation == rhs.annotation { + Some(self.exponent + 1) + } else { + None + } + } +} + +impl ComposablyEq for FactorAtomExponentAnnotation { + fn composably_eq(&self, rhs: &Self) -> Option { + if self.factor == rhs.factor && self.atom == rhs.atom && self.annotation == rhs.annotation { + Some(self.exponent + rhs.exponent) + } else { + None } } } @@ -262,3 +277,30 @@ impl IsCompatibleWith for FactorAtomExponentAnnotation { && Some(self.annotation.as_str()) == rhs.annotation() } } + +impl TermReduce for FactorAtomExponentAnnotation { + fn build(&self, exponent: Exponent) -> Term { + match (self.factor, exponent) { + (1, 1) => Term::AtomAnnotation(AtomAnnotation { + atom: self.atom, + annotation: self.annotation.clone(), + }), + (1, _) => Term::AtomExponentAnnotation(AtomExponentAnnotation { + atom: self.atom, + exponent, + annotation: self.annotation.clone(), + }), + (_, 1) => Term::FactorAtomAnnotation(FactorAtomAnnotation { + factor: self.factor, + atom: self.atom, + annotation: self.annotation.clone(), + }), + (_, _) => Term::FactorAtomExponentAnnotation(Self { + factor: self.factor, + atom: self.atom, + exponent, + annotation: self.annotation.clone(), + }), + } + } +} diff --git a/crates/api/src/term/variants/factor_exponent.rs b/crates/api/src/term/variants/factor_exponent.rs index e73a8250..811bdd2c 100644 --- a/crates/api/src/term/variants/factor_exponent.rs +++ b/crates/api/src/term/variants/factor_exponent.rs @@ -2,7 +2,10 @@ use std::fmt; use num_traits::{Inv, Pow}; -use crate::{composable::ComposablyEq, Annotation, Composable, IsCompatibleWith}; +use crate::{ + composable::ComposablyEq, term::term_reduce::TermReduce, Annotation, Composable, + IsCompatibleWith, +}; use super::{ Exponent, Factor, FactorExponentAnnotation, InvOutput, PowOutput, SetAnnotation, SetExponent, @@ -138,32 +141,32 @@ impl SetAnnotation for FactorExponent { } } -impl ComposablyEq for FactorExponent { - fn composably_eq(&self, rhs: &Term) -> bool { +impl ComposablyEq for FactorExponent { + fn composably_eq(&self, rhs: &Term) -> Option { match rhs { - Term::Factor(factor) | Term::FactorExponent(Self { factor, .. }) => { - self.factor == *factor - } + Term::Factor(factor) => self.composably_eq(factor), + Term::FactorExponent(inner) => self.composably_eq(inner), + _ => None, + } + } +} + +impl ComposablyEq for FactorExponent { + fn composably_eq(&self, rhs: &Factor) -> Option { + if self.factor == *rhs { + Some(self.exponent + 1) + } else { + None + } + } +} - Term::Annotation(_) - | Term::Atom(_) - | Term::AtomAnnotation(_) - | Term::AtomExponent(_) - | Term::AtomExponentAnnotation(_) - | Term::PrefixAtom(_) - | Term::PrefixAtomAnnotation(_) - | Term::PrefixAtomExponent(_) - | Term::PrefixAtomExponentAnnotation(_) - | Term::FactorAnnotation(_) - | Term::FactorExponentAnnotation(_) - | Term::FactorAtom(_) - | Term::FactorAtomAnnotation(_) - | Term::FactorAtomExponent(_) - | Term::FactorAtomExponentAnnotation(_) - | Term::FactorPrefixAtom(_) - | Term::FactorPrefixAtomAnnotation(_) - | Term::FactorPrefixAtomExponent(_) - | Term::FactorPrefixAtomExponentAnnotation(_) => false, +impl ComposablyEq for FactorExponent { + fn composably_eq(&self, rhs: &Self) -> Option { + if self.factor == rhs.factor { + Some(self.exponent + rhs.exponent) + } else { + None } } } @@ -179,3 +182,16 @@ impl IsCompatibleWith for FactorExponent { self.composition() == rhs.composition() && rhs.annotation().is_none() } } + +impl TermReduce for FactorExponent { + fn build(&self, exponent: Exponent) -> Term { + if exponent == 1 { + Term::Factor(self.factor) + } else { + Term::FactorExponent(Self { + factor: self.factor, + exponent, + }) + } + } +} diff --git a/crates/api/src/term/variants/factor_exponent_annotation.rs b/crates/api/src/term/variants/factor_exponent_annotation.rs index 1daa76ef..fcaa171d 100644 --- a/crates/api/src/term/variants/factor_exponent_annotation.rs +++ b/crates/api/src/term/variants/factor_exponent_annotation.rs @@ -2,7 +2,9 @@ use std::{fmt, mem}; use num_traits::{Inv, Pow}; -use crate::{composable::ComposablyEq, Composable, IsCompatibleWith}; +use crate::{ + composable::ComposablyEq, term::term_reduce::TermReduce, Composable, IsCompatibleWith, +}; use super::{ Annotation, Exponent, Factor, FactorAnnotation, InvOutput, PowOutput, SetAnnotation, @@ -63,7 +65,7 @@ impl fmt::Display for FactorExponentAnnotation { (factor, exponent) if exponent.is_negative() => { write!( f, - "{factor}-{exponent}{annotation}", + "{factor}{exponent}{annotation}", exponent = self.exponent, annotation = self.annotation ) @@ -186,33 +188,43 @@ impl<'a> SetAnnotation for &'a mut FactorExponentAnnotation { } } -impl ComposablyEq for FactorExponentAnnotation { - fn composably_eq(&self, rhs: &Term) -> bool { +impl ComposablyEq for FactorExponentAnnotation { + fn composably_eq(&self, rhs: &Term) -> Option { match rhs { - Term::FactorAnnotation(FactorAnnotation { factor, annotation }) - | Term::FactorExponentAnnotation(Self { - factor, annotation, .. - }) => self.factor == *factor && &self.annotation == annotation, - - Term::Annotation(_) - | Term::Atom(_) - | Term::AtomAnnotation(_) - | Term::AtomExponent(_) - | Term::AtomExponentAnnotation(_) - | Term::PrefixAtom(_) - | Term::PrefixAtomAnnotation(_) - | Term::PrefixAtomExponent(_) - | Term::PrefixAtomExponentAnnotation(_) - | Term::Factor(_) - | Term::FactorExponent(_) - | Term::FactorAtom(_) - | Term::FactorAtomAnnotation(_) - | Term::FactorAtomExponent(_) - | Term::FactorAtomExponentAnnotation(_) - | Term::FactorPrefixAtom(_) - | Term::FactorPrefixAtomAnnotation(_) - | Term::FactorPrefixAtomExponent(_) - | Term::FactorPrefixAtomExponentAnnotation(_) => false, + Term::Annotation(inner) => self.composably_eq(inner), + Term::FactorAnnotation(inner) => self.composably_eq(inner), + Term::FactorExponentAnnotation(inner) => self.composably_eq(inner), + _ => None, + } + } +} + +impl ComposablyEq for FactorExponentAnnotation { + fn composably_eq(&self, rhs: &Annotation) -> Option { + if self.factor == 1 && &self.annotation == rhs { + Some(self.exponent + 1) + } else { + None + } + } +} + +impl ComposablyEq for FactorExponentAnnotation { + fn composably_eq(&self, rhs: &FactorAnnotation) -> Option { + if self.factor == rhs.factor && self.annotation == rhs.annotation { + Some(self.exponent + 1) + } else { + None + } + } +} + +impl ComposablyEq for FactorExponentAnnotation { + fn composably_eq(&self, rhs: &Self) -> Option { + if self.factor == rhs.factor && self.annotation == rhs.annotation { + Some(self.exponent + rhs.exponent) + } else { + None } } } @@ -229,3 +241,20 @@ impl IsCompatibleWith for FactorExponentAnnotation { && Some(self.annotation.as_str()) == rhs.annotation() } } + +impl TermReduce for FactorExponentAnnotation { + fn build(&self, exponent: Exponent) -> Term { + match (self.factor, exponent) { + (1, 1) => Term::Annotation(self.annotation.clone()), + (_, 1) => Term::FactorAnnotation(FactorAnnotation { + factor: self.factor, + annotation: self.annotation.clone(), + }), + (_, _) => Term::FactorExponentAnnotation(Self { + factor: self.factor, + exponent, + annotation: self.annotation.clone(), + }), + } + } +} diff --git a/crates/api/src/term/variants/factor_prefix_atom.rs b/crates/api/src/term/variants/factor_prefix_atom.rs index e723d185..183949f5 100644 --- a/crates/api/src/term/variants/factor_prefix_atom.rs +++ b/crates/api/src/term/variants/factor_prefix_atom.rs @@ -3,8 +3,8 @@ use std::fmt; use num_traits::{Inv, Pow}; use crate::{ - composable::ComposablyEq, Annotation, Atom, Composable, IsCompatibleWith, Prefix, UcumSymbol, - UcumUnit, + composable::ComposablyEq, term::term_reduce::TermReduce, Annotation, Atom, Composable, + IsCompatibleWith, Prefix, UcumSymbol, UcumUnit, }; use super::{ @@ -146,42 +146,54 @@ impl SetAnnotation for FactorPrefixAtom { } } -impl ComposablyEq for FactorPrefixAtom { - fn composably_eq(&self, rhs: &Term) -> bool { +impl ComposablyEq for FactorPrefixAtom { + fn composably_eq(&self, rhs: &Term) -> Option { match rhs { - Term::PrefixAtom(PrefixAtom { prefix, atom }) - | Term::PrefixAtomExponent(PrefixAtomExponent { prefix, atom, .. }) => { - self.factor == 1 && self.prefix == *prefix && self.atom == *atom - } - Term::FactorPrefixAtom(Self { - factor, - prefix, - atom, - }) - | Term::FactorPrefixAtomExponent(FactorPrefixAtomExponent { - factor, - prefix, - atom, - .. - }) => self.factor == *factor && self.prefix == *prefix && self.atom == *atom, - - Term::Annotation(_) - | Term::Atom(_) - | Term::AtomAnnotation(_) - | Term::AtomExponent(_) - | Term::AtomExponentAnnotation(_) - | Term::PrefixAtomAnnotation(_) - | Term::PrefixAtomExponentAnnotation(_) - | Term::Factor(_) - | Term::FactorAnnotation(_) - | Term::FactorExponent(_) - | Term::FactorExponentAnnotation(_) - | Term::FactorAtom(_) - | Term::FactorAtomAnnotation(_) - | Term::FactorAtomExponent(_) - | Term::FactorAtomExponentAnnotation(_) - | Term::FactorPrefixAtomAnnotation(_) - | Term::FactorPrefixAtomExponentAnnotation(_) => false, + Term::PrefixAtom(inner) => self.composably_eq(inner), + Term::PrefixAtomExponent(inner) => self.composably_eq(inner), + Term::FactorPrefixAtom(inner) => self.composably_eq(inner), + Term::FactorPrefixAtomExponent(inner) => self.composably_eq(inner), + _ => None, + } + } +} + +impl ComposablyEq for FactorPrefixAtom { + fn composably_eq(&self, rhs: &PrefixAtom) -> Option { + if self.factor == 1 && self.prefix == rhs.prefix && self.atom == rhs.atom { + Some(2) + } else { + None + } + } +} + +impl ComposablyEq for FactorPrefixAtom { + fn composably_eq(&self, rhs: &PrefixAtomExponent) -> Option { + if self.factor == 1 && self.prefix == rhs.prefix && self.atom == rhs.atom { + Some(1 + rhs.exponent) + } else { + None + } + } +} + +impl ComposablyEq for FactorPrefixAtom { + fn composably_eq(&self, rhs: &Self) -> Option { + if self == rhs { + Some(2) + } else { + None + } + } +} + +impl ComposablyEq for FactorPrefixAtom { + fn composably_eq(&self, rhs: &FactorPrefixAtomExponent) -> Option { + if self.factor == rhs.factor && self.prefix == rhs.prefix && self.atom == rhs.atom { + Some(1 + rhs.exponent) + } else { + None } } } @@ -197,3 +209,30 @@ impl IsCompatibleWith for FactorPrefixAtom { self.composition() == rhs.composition() && rhs.annotation().is_none() } } + +impl TermReduce for FactorPrefixAtom { + fn build(&self, exponent: Exponent) -> Term { + match (self.factor, exponent) { + (1, 1) => Term::PrefixAtom(PrefixAtom { + prefix: self.prefix, + atom: self.atom, + }), + (1, _) => Term::PrefixAtomExponent(PrefixAtomExponent { + prefix: self.prefix, + atom: self.atom, + exponent, + }), + (_, 1) => Term::FactorPrefixAtom(Self { + factor: self.factor, + prefix: self.prefix, + atom: self.atom, + }), + (_, _) => Term::FactorPrefixAtomExponent(FactorPrefixAtomExponent { + factor: self.factor, + prefix: self.prefix, + atom: self.atom, + exponent, + }), + } + } +} diff --git a/crates/api/src/term/variants/factor_prefix_atom_annotation.rs b/crates/api/src/term/variants/factor_prefix_atom_annotation.rs index 6ffc36d7..78debf2b 100644 --- a/crates/api/src/term/variants/factor_prefix_atom_annotation.rs +++ b/crates/api/src/term/variants/factor_prefix_atom_annotation.rs @@ -3,7 +3,8 @@ use std::{fmt, mem}; use num_traits::{Inv, Pow}; use crate::{ - composable::ComposablyEq, Atom, Composable, IsCompatibleWith, Prefix, UcumSymbol, UcumUnit, + composable::ComposablyEq, term::term_reduce::TermReduce, Atom, Composable, IsCompatibleWith, + Prefix, UcumSymbol, UcumUnit, }; use super::{ @@ -178,61 +179,70 @@ impl<'a> SetAnnotation for &'a mut FactorPrefixAtomAnnotation { } } -impl ComposablyEq for FactorPrefixAtomAnnotation { - fn composably_eq(&self, rhs: &Term) -> bool { +impl ComposablyEq for FactorPrefixAtomAnnotation { + fn composably_eq(&self, rhs: &Term) -> Option { match rhs { - Term::PrefixAtomAnnotation(PrefixAtomAnnotation { - prefix, - atom, - annotation, - }) - | Term::PrefixAtomExponentAnnotation(PrefixAtomExponentAnnotation { - prefix, - atom, - annotation, - .. - }) => { - self.factor == 1 - && self.prefix == *prefix - && self.atom == *atom - && &self.annotation == annotation - } - Term::FactorPrefixAtomAnnotation(Self { - factor, - prefix, - atom, - annotation, - }) - | Term::FactorPrefixAtomExponentAnnotation(FactorPrefixAtomExponentAnnotation { - factor, - prefix, - atom, - annotation, - .. - }) => { - self.factor == *factor - && self.prefix == *prefix - && self.atom == *atom - && &self.annotation == annotation - } + Term::PrefixAtomAnnotation(inner) => self.composably_eq(inner), + Term::PrefixAtomExponentAnnotation(inner) => self.composably_eq(inner), + Term::FactorPrefixAtomAnnotation(inner) => self.composably_eq(inner), + Term::FactorPrefixAtomExponentAnnotation(inner) => self.composably_eq(inner), + _ => None, + } + } +} - Term::Annotation(_) - | Term::Atom(_) - | Term::AtomAnnotation(_) - | Term::AtomExponent(_) - | Term::AtomExponentAnnotation(_) - | Term::PrefixAtom(_) - | Term::PrefixAtomExponent(_) - | Term::Factor(_) - | Term::FactorAnnotation(_) - | Term::FactorExponent(_) - | Term::FactorExponentAnnotation(_) - | Term::FactorAtom(_) - | Term::FactorAtomAnnotation(_) - | Term::FactorAtomExponent(_) - | Term::FactorAtomExponentAnnotation(_) - | Term::FactorPrefixAtom(_) - | Term::FactorPrefixAtomExponent(_) => false, +impl ComposablyEq for FactorPrefixAtomAnnotation { + fn composably_eq(&self, rhs: &PrefixAtomAnnotation) -> Option { + if self.factor == 1 + && self.prefix == rhs.prefix + && self.atom == rhs.atom + && self.annotation == rhs.annotation + { + Some(2) + } else { + None + } + } +} + +impl ComposablyEq for FactorPrefixAtomAnnotation { + fn composably_eq(&self, rhs: &PrefixAtomExponentAnnotation) -> Option { + if self.factor == 1 + && self.prefix == rhs.prefix + && self.atom == rhs.atom + && self.annotation == rhs.annotation + { + Some(1 + rhs.exponent) + } else { + None + } + } +} + +impl ComposablyEq for FactorPrefixAtomAnnotation { + fn composably_eq(&self, rhs: &Self) -> Option { + if self.factor == rhs.factor + && self.prefix == rhs.prefix + && self.atom == rhs.atom + && self.annotation == rhs.annotation + { + Some(2) + } else { + None + } + } +} + +impl ComposablyEq for FactorPrefixAtomAnnotation { + fn composably_eq(&self, rhs: &FactorPrefixAtomExponentAnnotation) -> Option { + if self.factor == rhs.factor + && self.prefix == rhs.prefix + && self.atom == rhs.atom + && self.annotation == rhs.annotation + { + Some(1 + rhs.exponent) + } else { + None } } } @@ -249,3 +259,36 @@ impl IsCompatibleWith for FactorPrefixAtomAnnotation { && Some(self.annotation.as_str()) == rhs.annotation() } } + +impl TermReduce for FactorPrefixAtomAnnotation { + fn build(&self, exponent: Exponent) -> Term { + match (self.factor, exponent) { + (1, 1) => Term::PrefixAtomAnnotation(PrefixAtomAnnotation { + prefix: self.prefix, + atom: self.atom, + annotation: self.annotation.clone(), + }), + (1, _) => Term::PrefixAtomExponentAnnotation(PrefixAtomExponentAnnotation { + prefix: self.prefix, + atom: self.atom, + exponent, + annotation: self.annotation.clone(), + }), + (_, 1) => Term::FactorPrefixAtomAnnotation(Self { + factor: self.factor, + prefix: self.prefix, + atom: self.atom, + annotation: self.annotation.clone(), + }), + (_, _) => { + Term::FactorPrefixAtomExponentAnnotation(FactorPrefixAtomExponentAnnotation { + factor: self.factor, + prefix: self.prefix, + atom: self.atom, + exponent, + annotation: self.annotation.clone(), + }) + } + } + } +} diff --git a/crates/api/src/term/variants/factor_prefix_atom_exponent.rs b/crates/api/src/term/variants/factor_prefix_atom_exponent.rs index 95438c75..f8ff66c6 100644 --- a/crates/api/src/term/variants/factor_prefix_atom_exponent.rs +++ b/crates/api/src/term/variants/factor_prefix_atom_exponent.rs @@ -3,8 +3,8 @@ use std::fmt; use num_traits::{Inv, Pow}; use crate::{ - composable::ComposablyEq, Annotation, Atom, Composable, IsCompatibleWith, Prefix, UcumSymbol, - UcumUnit, + composable::ComposablyEq, term::term_reduce::TermReduce, Annotation, Atom, Composable, + IsCompatibleWith, Prefix, UcumSymbol, UcumUnit, }; use super::{ @@ -184,42 +184,54 @@ impl SetAnnotation for FactorPrefixAtomExponent { } } -impl ComposablyEq for FactorPrefixAtomExponent { - fn composably_eq(&self, rhs: &Term) -> bool { +impl ComposablyEq for FactorPrefixAtomExponent { + fn composably_eq(&self, rhs: &Term) -> Option { match rhs { - Term::FactorPrefixAtom(FactorPrefixAtom { - factor, - prefix, - atom, - }) - | Term::FactorPrefixAtomExponent(Self { - factor, - prefix, - atom, - .. - }) => self.factor == *factor && self.prefix == *prefix && self.atom == *atom, - Term::PrefixAtom(PrefixAtom { prefix, atom }) - | Term::PrefixAtomExponent(PrefixAtomExponent { prefix, atom, .. }) => { - self.factor == 1 && self.prefix == *prefix && self.atom == *atom - } + Term::FactorPrefixAtom(inner) => self.composably_eq(inner), + Term::FactorPrefixAtomExponent(inner) => self.composably_eq(inner), + Term::PrefixAtom(inner) => self.composably_eq(inner), + Term::PrefixAtomExponent(inner) => self.composably_eq(inner), + _ => None, + } + } +} - Term::Annotation(_) - | Term::Atom(_) - | Term::AtomAnnotation(_) - | Term::AtomExponent(_) - | Term::AtomExponentAnnotation(_) - | Term::PrefixAtomAnnotation(_) - | Term::PrefixAtomExponentAnnotation(_) - | Term::Factor(_) - | Term::FactorAnnotation(_) - | Term::FactorExponent(_) - | Term::FactorExponentAnnotation(_) - | Term::FactorAtom(_) - | Term::FactorAtomAnnotation(_) - | Term::FactorAtomExponent(_) - | Term::FactorAtomExponentAnnotation(_) - | Term::FactorPrefixAtomAnnotation(_) - | Term::FactorPrefixAtomExponentAnnotation(_) => false, +impl ComposablyEq for FactorPrefixAtomExponent { + fn composably_eq(&self, rhs: &FactorPrefixAtom) -> Option { + if self.factor == rhs.factor && self.prefix == rhs.prefix && self.atom == rhs.atom { + Some(self.exponent + 1) + } else { + None + } + } +} + +impl ComposablyEq for FactorPrefixAtomExponent { + fn composably_eq(&self, rhs: &Self) -> Option { + if self.factor == rhs.factor && self.prefix == rhs.prefix && self.atom == rhs.atom { + Some(self.exponent + rhs.exponent) + } else { + None + } + } +} + +impl ComposablyEq for FactorPrefixAtomExponent { + fn composably_eq(&self, rhs: &PrefixAtom) -> Option { + if self.factor == 1 && self.prefix == rhs.prefix && self.atom == rhs.atom { + Some(self.exponent + 1) + } else { + None + } + } +} + +impl ComposablyEq for FactorPrefixAtomExponent { + fn composably_eq(&self, rhs: &PrefixAtomExponent) -> Option { + if self.factor == 1 && self.prefix == rhs.prefix && self.atom == rhs.atom { + Some(self.exponent + rhs.exponent) + } else { + None } } } @@ -235,3 +247,30 @@ impl IsCompatibleWith for FactorPrefixAtomExponent { self.composition() == rhs.composition() && rhs.annotation().is_none() } } + +impl TermReduce for FactorPrefixAtomExponent { + fn build(&self, exponent: Exponent) -> Term { + match (self.factor, exponent) { + (1, 1) => Term::PrefixAtom(PrefixAtom { + prefix: self.prefix, + atom: self.atom, + }), + (1, _) => Term::PrefixAtomExponent(PrefixAtomExponent { + prefix: self.prefix, + atom: self.atom, + exponent, + }), + (_, 1) => Term::FactorPrefixAtom(FactorPrefixAtom { + factor: self.factor, + prefix: self.prefix, + atom: self.atom, + }), + (_, _) => Term::FactorPrefixAtomExponent(Self { + factor: self.factor, + prefix: self.prefix, + atom: self.atom, + exponent, + }), + } + } +} diff --git a/crates/api/src/term/variants/factor_prefix_atom_exponent_annotation.rs b/crates/api/src/term/variants/factor_prefix_atom_exponent_annotation.rs index 5855fa31..86966e39 100644 --- a/crates/api/src/term/variants/factor_prefix_atom_exponent_annotation.rs +++ b/crates/api/src/term/variants/factor_prefix_atom_exponent_annotation.rs @@ -3,7 +3,8 @@ use std::{fmt, mem}; use num_traits::{Inv, Pow}; use crate::{ - composable::ComposablyEq, Atom, Composable, IsCompatibleWith, Prefix, UcumSymbol, UcumUnit, + composable::ComposablyEq, term::term_reduce::TermReduce, Atom, Composable, IsCompatibleWith, + Prefix, UcumSymbol, UcumUnit, }; use super::{ @@ -227,61 +228,70 @@ impl<'a> SetAnnotation for &'a mut FactorPrefixAtomExponentAnnotation { } } -impl ComposablyEq for FactorPrefixAtomExponentAnnotation { - fn composably_eq(&self, rhs: &Term) -> bool { +impl ComposablyEq for FactorPrefixAtomExponentAnnotation { + fn composably_eq(&self, rhs: &Term) -> Option { match rhs { - Term::FactorPrefixAtomAnnotation(FactorPrefixAtomAnnotation { - factor, - prefix, - atom, - annotation, - }) - | Term::FactorPrefixAtomExponentAnnotation(Self { - factor, - prefix, - atom, - annotation, - .. - }) => { - self.factor == *factor - && self.prefix == *prefix - && self.atom == *atom - && &self.annotation == annotation - } - Term::PrefixAtomAnnotation(PrefixAtomAnnotation { - prefix, - atom, - annotation, - }) - | Term::PrefixAtomExponentAnnotation(PrefixAtomExponentAnnotation { - prefix, - atom, - annotation, - .. - }) => { - self.factor == 1 - && self.prefix == *prefix - && self.atom == *atom - && &self.annotation == annotation - } + Term::FactorPrefixAtomAnnotation(inner) => self.composably_eq(inner), + Term::FactorPrefixAtomExponentAnnotation(inner) => self.composably_eq(inner), + Term::PrefixAtomAnnotation(inner) => self.composably_eq(inner), + Term::PrefixAtomExponentAnnotation(inner) => self.composably_eq(inner), + _ => None, + } + } +} + +impl ComposablyEq for FactorPrefixAtomExponentAnnotation { + fn composably_eq(&self, rhs: &FactorPrefixAtomAnnotation) -> Option { + if self.factor == rhs.factor + && self.prefix == rhs.prefix + && self.atom == rhs.atom + && self.annotation == rhs.annotation + { + Some(self.exponent + 1) + } else { + None + } + } +} - Term::Annotation(_) - | Term::Atom(_) - | Term::AtomAnnotation(_) - | Term::AtomExponent(_) - | Term::AtomExponentAnnotation(_) - | Term::PrefixAtom(_) - | Term::PrefixAtomExponent(_) - | Term::Factor(_) - | Term::FactorAnnotation(_) - | Term::FactorExponent(_) - | Term::FactorExponentAnnotation(_) - | Term::FactorAtom(_) - | Term::FactorAtomAnnotation(_) - | Term::FactorAtomExponent(_) - | Term::FactorAtomExponentAnnotation(_) - | Term::FactorPrefixAtom(_) - | Term::FactorPrefixAtomExponent(_) => false, +impl ComposablyEq for FactorPrefixAtomExponentAnnotation { + fn composably_eq(&self, rhs: &Self) -> Option { + if self.factor == rhs.factor + && self.prefix == rhs.prefix + && self.atom == rhs.atom + && self.annotation == rhs.annotation + { + Some(self.exponent + rhs.exponent) + } else { + None + } + } +} + +impl ComposablyEq for FactorPrefixAtomExponentAnnotation { + fn composably_eq(&self, rhs: &PrefixAtomAnnotation) -> Option { + if self.factor == 1 + && self.prefix == rhs.prefix + && self.atom == rhs.atom + && self.annotation == rhs.annotation + { + Some(self.exponent + 1) + } else { + None + } + } +} + +impl ComposablyEq for FactorPrefixAtomExponentAnnotation { + fn composably_eq(&self, rhs: &PrefixAtomExponentAnnotation) -> Option { + if self.factor == 1 + && self.prefix == rhs.prefix + && self.atom == rhs.atom + && self.annotation == rhs.annotation + { + Some(self.exponent + rhs.exponent) + } else { + None } } } @@ -298,3 +308,34 @@ impl IsCompatibleWith for FactorPrefixAtomExponentAnnotation { && Some(self.annotation.as_str()) == rhs.annotation() } } + +impl TermReduce for FactorPrefixAtomExponentAnnotation { + fn build(&self, exponent: Exponent) -> Term { + match (self.factor, exponent) { + (1, 1) => Term::PrefixAtomAnnotation(PrefixAtomAnnotation { + prefix: self.prefix, + atom: self.atom, + annotation: self.annotation.clone(), + }), + (1, _) => Term::PrefixAtomExponentAnnotation(PrefixAtomExponentAnnotation { + prefix: self.prefix, + atom: self.atom, + exponent, + annotation: self.annotation.clone(), + }), + (_, 1) => Term::FactorPrefixAtomAnnotation(FactorPrefixAtomAnnotation { + factor: self.factor, + prefix: self.prefix, + atom: self.atom, + annotation: self.annotation.clone(), + }), + (_, _) => Term::FactorPrefixAtomExponentAnnotation(Self { + factor: self.factor, + prefix: self.prefix, + atom: self.atom, + exponent, + annotation: self.annotation.clone(), + }), + } + } +} diff --git a/crates/api/src/term/variants/prefix_atom.rs b/crates/api/src/term/variants/prefix_atom.rs index fa857d91..d152fbcc 100644 --- a/crates/api/src/term/variants/prefix_atom.rs +++ b/crates/api/src/term/variants/prefix_atom.rs @@ -3,8 +3,8 @@ use std::fmt; use num_traits::{Inv, Pow}; use crate::{ - composable::ComposablyEq, Annotation, Atom, Composable, IsCompatibleWith, Prefix, UcumSymbol, - UcumUnit, + composable::ComposablyEq, term::term_reduce::TermReduce, Annotation, Atom, Composable, + IsCompatibleWith, Prefix, UcumSymbol, UcumUnit, }; use super::{ @@ -141,42 +141,54 @@ impl SetAnnotation for PrefixAtom { } } -impl ComposablyEq for PrefixAtom { - fn composably_eq(&self, rhs: &Term) -> bool { +impl ComposablyEq for PrefixAtom { + fn composably_eq(&self, rhs: &Term) -> Option { match rhs { - Term::PrefixAtom(Self { prefix, atom }) - | Term::PrefixAtomExponent(PrefixAtomExponent { prefix, atom, .. }) => { - self.prefix == *prefix && self.atom == *atom - } - Term::FactorPrefixAtom(FactorPrefixAtom { - factor, - prefix, - atom, - }) - | Term::FactorPrefixAtomExponent(FactorPrefixAtomExponent { - factor, - prefix, - atom, - .. - }) => *factor == 1 && self.prefix == *prefix && self.atom == *atom, - - Term::Annotation(_) - | Term::Atom(_) - | Term::AtomAnnotation(_) - | Term::AtomExponent(_) - | Term::AtomExponentAnnotation(_) - | Term::PrefixAtomAnnotation(_) - | Term::PrefixAtomExponentAnnotation(_) - | Term::Factor(_) - | Term::FactorAnnotation(_) - | Term::FactorExponent(_) - | Term::FactorExponentAnnotation(_) - | Term::FactorAtom(_) - | Term::FactorAtomAnnotation(_) - | Term::FactorAtomExponent(_) - | Term::FactorAtomExponentAnnotation(_) - | Term::FactorPrefixAtomAnnotation(_) - | Term::FactorPrefixAtomExponentAnnotation(_) => false, + Term::PrefixAtom(inner) => self.composably_eq(inner), + Term::PrefixAtomExponent(inner) => self.composably_eq(inner), + Term::FactorPrefixAtom(inner) => self.composably_eq(inner), + Term::FactorPrefixAtomExponent(inner) => self.composably_eq(inner), + _ => None, + } + } +} + +impl ComposablyEq for PrefixAtom { + fn composably_eq(&self, rhs: &Self) -> Option { + if self == rhs { + Some(2) + } else { + None + } + } +} + +impl ComposablyEq for PrefixAtom { + fn composably_eq(&self, rhs: &PrefixAtomExponent) -> Option { + if self.prefix == rhs.prefix && self.atom == rhs.atom { + Some(1 + rhs.exponent) + } else { + None + } + } +} + +impl ComposablyEq for PrefixAtom { + fn composably_eq(&self, rhs: &FactorPrefixAtom) -> Option { + if rhs.factor == 1 && self.prefix == rhs.prefix && self.atom == rhs.atom { + Some(2) + } else { + None + } + } +} + +impl ComposablyEq for PrefixAtom { + fn composably_eq(&self, rhs: &FactorPrefixAtomExponent) -> Option { + if rhs.factor == 1 && self.prefix == rhs.prefix && self.atom == rhs.atom { + Some(1 + rhs.exponent) + } else { + None } } } @@ -192,3 +204,20 @@ impl IsCompatibleWith for PrefixAtom { self.composition() == rhs.composition() && rhs.annotation().is_none() } } + +impl TermReduce for PrefixAtom { + fn build(&self, exponent: Exponent) -> Term { + if exponent == 1 { + Term::PrefixAtom(Self { + prefix: self.prefix, + atom: self.atom, + }) + } else { + Term::PrefixAtomExponent(PrefixAtomExponent { + prefix: self.prefix, + atom: self.atom, + exponent, + }) + } + } +} diff --git a/crates/api/src/term/variants/prefix_atom_annotation.rs b/crates/api/src/term/variants/prefix_atom_annotation.rs index ed8eda56..86a31b02 100644 --- a/crates/api/src/term/variants/prefix_atom_annotation.rs +++ b/crates/api/src/term/variants/prefix_atom_annotation.rs @@ -3,7 +3,8 @@ use std::{fmt, mem}; use num_traits::{Inv, Pow}; use crate::{ - composable::ComposablyEq, Atom, Composable, IsCompatibleWith, Prefix, UcumSymbol, UcumUnit, + composable::ComposablyEq, term::term_reduce::TermReduce, Atom, Composable, IsCompatibleWith, + Prefix, UcumSymbol, UcumUnit, }; use super::{ @@ -176,56 +177,62 @@ impl<'a> SetAnnotation for &'a mut PrefixAtomAnnotation { } } -impl ComposablyEq for PrefixAtomAnnotation { - fn composably_eq(&self, rhs: &Term) -> bool { +impl ComposablyEq for PrefixAtomAnnotation { + fn composably_eq(&self, rhs: &Term) -> Option { match rhs { - Term::PrefixAtomAnnotation(Self { - prefix, - atom, - annotation, - }) - | Term::PrefixAtomExponentAnnotation(PrefixAtomExponentAnnotation { - prefix, - atom, - annotation, - .. - }) => self.prefix == *prefix && self.atom == *atom && &self.annotation == annotation, - Term::FactorPrefixAtomAnnotation(FactorPrefixAtomAnnotation { - factor, - prefix, - atom, - annotation, - }) - | Term::FactorPrefixAtomExponentAnnotation(FactorPrefixAtomExponentAnnotation { - factor, - prefix, - atom, - annotation, - .. - }) => { - *factor == 1 - && self.prefix == *prefix - && self.atom == *atom - && &self.annotation == annotation - } - - Term::Annotation(_) - | Term::Atom(_) - | Term::AtomAnnotation(_) - | Term::AtomExponent(_) - | Term::AtomExponentAnnotation(_) - | Term::PrefixAtom(_) - | Term::PrefixAtomExponent(_) - | Term::Factor(_) - | Term::FactorAnnotation(_) - | Term::FactorExponent(_) - | Term::FactorExponentAnnotation(_) - | Term::FactorAtom(_) - | Term::FactorAtomAnnotation(_) - | Term::FactorAtomExponent(_) - | Term::FactorAtomExponentAnnotation(_) - | Term::FactorPrefixAtom(_) - | Term::FactorPrefixAtomExponent(_) => false, + Term::PrefixAtomAnnotation(inner) => self.composably_eq(inner), + Term::PrefixAtomExponentAnnotation(inner) => self.composably_eq(inner), + Term::FactorPrefixAtomAnnotation(inner) => self.composably_eq(inner), + Term::FactorPrefixAtomExponentAnnotation(inner) => self.composably_eq(inner), + _ => None, + } + } +} + +impl ComposablyEq for PrefixAtomAnnotation { + fn composably_eq(&self, rhs: &Self) -> Option { + if self == rhs { + Some(2) + } else { + None + } + } +} + +impl ComposablyEq for PrefixAtomAnnotation { + fn composably_eq(&self, rhs: &PrefixAtomExponentAnnotation) -> Option { + if self.prefix == rhs.prefix && self.atom == rhs.atom && self.annotation == rhs.annotation { + Some(1 + rhs.exponent) + } else { + None + } + } +} + +impl ComposablyEq for PrefixAtomAnnotation { + fn composably_eq(&self, rhs: &FactorPrefixAtomAnnotation) -> Option { + if rhs.factor == 1 + && self.prefix == rhs.prefix + && self.atom == rhs.atom + && self.annotation == rhs.annotation + { + Some(2) + } else { + None + } + } +} + +impl ComposablyEq for PrefixAtomAnnotation { + fn composably_eq(&self, rhs: &FactorPrefixAtomExponentAnnotation) -> Option { + if rhs.factor == 1 + && self.prefix == rhs.prefix + && self.atom == rhs.atom + && self.annotation == rhs.annotation + { + Some(1 + rhs.exponent) + } else { + None } } } @@ -242,3 +249,22 @@ impl IsCompatibleWith for PrefixAtomAnnotation { && Some(self.annotation.as_str()) == rhs.annotation() } } + +impl TermReduce for PrefixAtomAnnotation { + fn build(&self, exponent: Exponent) -> Term { + if exponent == 1 { + Term::PrefixAtomAnnotation(Self { + prefix: self.prefix, + atom: self.atom, + annotation: self.annotation.clone(), + }) + } else { + Term::PrefixAtomExponentAnnotation(PrefixAtomExponentAnnotation { + prefix: self.prefix, + atom: self.atom, + exponent, + annotation: self.annotation.clone(), + }) + } + } +} diff --git a/crates/api/src/term/variants/prefix_atom_exponent.rs b/crates/api/src/term/variants/prefix_atom_exponent.rs index 93bbf7cb..fe722b82 100644 --- a/crates/api/src/term/variants/prefix_atom_exponent.rs +++ b/crates/api/src/term/variants/prefix_atom_exponent.rs @@ -3,8 +3,8 @@ use std::fmt; use num_traits::{Inv, Pow}; use crate::{ - composable::ComposablyEq, Annotation, Atom, Composable, IsCompatibleWith, Prefix, UcumSymbol, - UcumUnit, + composable::ComposablyEq, term::term_reduce::TermReduce, Annotation, Atom, Composable, + IsCompatibleWith, Prefix, UcumSymbol, UcumUnit, }; use super::{ @@ -159,42 +159,54 @@ impl SetAnnotation for PrefixAtomExponent { } } -impl ComposablyEq for PrefixAtomExponent { - fn composably_eq(&self, rhs: &Term) -> bool { +impl ComposablyEq for PrefixAtomExponent { + fn composably_eq(&self, rhs: &Term) -> Option { match rhs { - Term::PrefixAtom(PrefixAtom { prefix, atom }) - | Term::PrefixAtomExponent(Self { prefix, atom, .. }) => { - self.prefix == *prefix && self.atom == *atom - } - Term::FactorPrefixAtom(FactorPrefixAtom { - factor, - prefix, - atom, - }) - | Term::FactorPrefixAtomExponent(FactorPrefixAtomExponent { - factor, - prefix, - atom, - .. - }) => *factor == 1 && self.prefix == *prefix && self.atom == *atom, - - Term::Annotation(_) - | Term::Atom(_) - | Term::AtomAnnotation(_) - | Term::AtomExponent(_) - | Term::AtomExponentAnnotation(_) - | Term::PrefixAtomAnnotation(_) - | Term::PrefixAtomExponentAnnotation(_) - | Term::Factor(_) - | Term::FactorAnnotation(_) - | Term::FactorExponent(_) - | Term::FactorExponentAnnotation(_) - | Term::FactorAtom(_) - | Term::FactorAtomAnnotation(_) - | Term::FactorAtomExponent(_) - | Term::FactorAtomExponentAnnotation(_) - | Term::FactorPrefixAtomAnnotation(_) - | Term::FactorPrefixAtomExponentAnnotation(_) => false, + Term::PrefixAtom(inner) => self.composably_eq(inner), + Term::PrefixAtomExponent(inner) => self.composably_eq(inner), + Term::FactorPrefixAtom(inner) => self.composably_eq(inner), + Term::FactorPrefixAtomExponent(inner) => self.composably_eq(inner), + _ => None, + } + } +} + +impl ComposablyEq for PrefixAtomExponent { + fn composably_eq(&self, rhs: &PrefixAtom) -> Option { + if self.prefix == rhs.prefix && self.atom == rhs.atom { + Some(self.exponent + 1) + } else { + None + } + } +} + +impl ComposablyEq for PrefixAtomExponent { + fn composably_eq(&self, rhs: &Self) -> Option { + if self.prefix == rhs.prefix && self.atom == rhs.atom { + Some(self.exponent + rhs.exponent) + } else { + None + } + } +} + +impl ComposablyEq for PrefixAtomExponent { + fn composably_eq(&self, rhs: &FactorPrefixAtom) -> Option { + if rhs.factor == 1 && self.prefix == rhs.prefix && self.atom == rhs.atom { + Some(self.exponent + 1) + } else { + None + } + } +} + +impl ComposablyEq for PrefixAtomExponent { + fn composably_eq(&self, rhs: &FactorPrefixAtomExponent) -> Option { + if rhs.factor == 1 && self.prefix == rhs.prefix && self.atom == rhs.atom { + Some(self.exponent + rhs.exponent) + } else { + None } } } @@ -210,3 +222,20 @@ impl IsCompatibleWith for PrefixAtomExponent { self.composition() == rhs.composition() && rhs.annotation().is_none() } } + +impl TermReduce for PrefixAtomExponent { + fn build(&self, exponent: Exponent) -> Term { + if exponent == 1 { + Term::PrefixAtom(PrefixAtom { + prefix: self.prefix, + atom: self.atom, + }) + } else { + Term::PrefixAtomExponent(Self { + prefix: self.prefix, + atom: self.atom, + exponent, + }) + } + } +} diff --git a/crates/api/src/term/variants/prefix_atom_exponent_annotation.rs b/crates/api/src/term/variants/prefix_atom_exponent_annotation.rs index a785d3ed..49b09470 100644 --- a/crates/api/src/term/variants/prefix_atom_exponent_annotation.rs +++ b/crates/api/src/term/variants/prefix_atom_exponent_annotation.rs @@ -3,7 +3,8 @@ use std::{fmt, mem}; use num_traits::{Inv, Pow}; use crate::{ - composable::ComposablyEq, Atom, Composable, IsCompatibleWith, Prefix, UcumSymbol, UcumUnit, + composable::ComposablyEq, term::term_reduce::TermReduce, Atom, Composable, IsCompatibleWith, + Prefix, UcumSymbol, UcumUnit, }; use super::{ @@ -212,56 +213,62 @@ impl<'a> SetAnnotation for &'a mut PrefixAtomExponentAnnotation { } } -impl ComposablyEq for PrefixAtomExponentAnnotation { - fn composably_eq(&self, rhs: &Term) -> bool { +impl ComposablyEq for PrefixAtomExponentAnnotation { + fn composably_eq(&self, rhs: &Term) -> Option { match rhs { - Term::PrefixAtomAnnotation(PrefixAtomAnnotation { - prefix, - atom, - annotation, - }) - | Term::PrefixAtomExponentAnnotation(Self { - prefix, - atom, - annotation, - .. - }) => self.prefix == *prefix && self.atom == *atom && &self.annotation == annotation, - Term::FactorPrefixAtomAnnotation(FactorPrefixAtomAnnotation { - factor, - prefix, - atom, - annotation, - }) - | Term::FactorPrefixAtomExponentAnnotation(FactorPrefixAtomExponentAnnotation { - factor, - prefix, - atom, - annotation, - .. - }) => { - *factor == 1 - && self.prefix == *prefix - && self.atom == *atom - && &self.annotation == annotation - } + Term::PrefixAtomAnnotation(inner) => self.composably_eq(inner), + Term::PrefixAtomExponentAnnotation(inner) => self.composably_eq(inner), + Term::FactorPrefixAtomAnnotation(inner) => self.composably_eq(inner), + Term::FactorPrefixAtomExponentAnnotation(inner) => self.composably_eq(inner), + _ => None, + } + } +} + +impl ComposablyEq for PrefixAtomExponentAnnotation { + fn composably_eq(&self, rhs: &PrefixAtomAnnotation) -> Option { + if self.prefix == rhs.prefix && self.atom == rhs.atom && self.annotation == rhs.annotation { + Some(self.exponent + 1) + } else { + None + } + } +} - Term::Annotation(_) - | Term::Atom(_) - | Term::AtomAnnotation(_) - | Term::AtomExponent(_) - | Term::AtomExponentAnnotation(_) - | Term::PrefixAtom(_) - | Term::PrefixAtomExponent(_) - | Term::Factor(_) - | Term::FactorAnnotation(_) - | Term::FactorExponent(_) - | Term::FactorExponentAnnotation(_) - | Term::FactorAtom(_) - | Term::FactorAtomAnnotation(_) - | Term::FactorAtomExponent(_) - | Term::FactorAtomExponentAnnotation(_) - | Term::FactorPrefixAtom(_) - | Term::FactorPrefixAtomExponent(_) => false, +impl ComposablyEq for PrefixAtomExponentAnnotation { + fn composably_eq(&self, rhs: &Self) -> Option { + if self.prefix == rhs.prefix && self.atom == rhs.atom && self.annotation == rhs.annotation { + Some(self.exponent + rhs.exponent) + } else { + None + } + } +} + +impl ComposablyEq for PrefixAtomExponentAnnotation { + fn composably_eq(&self, rhs: &FactorPrefixAtomAnnotation) -> Option { + if rhs.factor == 1 + && self.prefix == rhs.prefix + && self.atom == rhs.atom + && self.annotation == rhs.annotation + { + Some(self.exponent + 1) + } else { + None + } + } +} + +impl ComposablyEq for PrefixAtomExponentAnnotation { + fn composably_eq(&self, rhs: &FactorPrefixAtomExponentAnnotation) -> Option { + if rhs.factor == 1 + && self.prefix == rhs.prefix + && self.atom == rhs.atom + && self.annotation == rhs.annotation + { + Some(self.exponent + rhs.exponent) + } else { + None } } } @@ -278,3 +285,22 @@ impl IsCompatibleWith for PrefixAtomExponentAnnotation { && Some(self.annotation.as_str()) == rhs.annotation() } } + +impl TermReduce for PrefixAtomExponentAnnotation { + fn build(&self, exponent: Exponent) -> Term { + if exponent == 1 { + Term::PrefixAtomAnnotation(PrefixAtomAnnotation { + prefix: self.prefix, + atom: self.atom, + annotation: self.annotation.clone(), + }) + } else { + Term::PrefixAtomExponentAnnotation(Self { + prefix: self.prefix, + atom: self.atom, + exponent, + annotation: self.annotation.clone(), + }) + } + } +} diff --git a/crates/api/src/unit/ops.rs b/crates/api/src/unit/ops.rs index e996bffd..5c918706 100644 --- a/crates/api/src/unit/ops.rs +++ b/crates/api/src/unit/ops.rs @@ -18,11 +18,10 @@ impl Div for Unit { #[inline] fn div(self, other: Self) -> Self::Output { - let mut lhs = self.terms.to_vec(); - lhs.reserve_exact(other.terms.len()); - lhs.extend(other.terms.iter().map(Inv::inv)); - - Self::new(term_reducing::reduce_terms(&lhs)) + Self::new(term_reducing::meow( + &self.terms, + other.terms.iter().map(Inv::inv).collect(), + )) } } @@ -34,12 +33,10 @@ impl<'a> Div<&'a Self> for Unit { #[inline] fn div(self, other: &'a Self) -> Self::Output { - let mut lhs = self.terms.to_vec(); - - lhs.reserve_exact(other.terms.len()); - lhs.extend(other.terms.iter().map(Inv::inv)); - - Self::new(term_reducing::reduce_terms(&lhs)) + Self::new(term_reducing::meow( + &self.terms, + other.terms.into_iter().map(Inv::inv).collect(), + )) } } @@ -51,12 +48,10 @@ impl<'a> Div for &'a Unit { #[inline] fn div(self, other: &'a Unit) -> Self::Output { - let mut lhs = self.terms.to_vec(); - - lhs.reserve_exact(other.terms.len()); - lhs.extend(other.terms.iter().map(Inv::inv)); - - Unit::new(term_reducing::reduce_terms(&lhs)) + Unit::new(term_reducing::meow( + &self.terms, + other.terms.into_iter().map(Inv::inv).collect(), + )) } } @@ -68,12 +63,10 @@ impl<'a> Div for &'a Unit { #[inline] fn div(self, other: Unit) -> Self::Output { - let mut lhs = self.terms.to_vec(); - - lhs.reserve_exact(other.terms.len()); - lhs.extend(other.terms.iter().map(Inv::inv)); - - Unit::new(term_reducing::reduce_terms(&lhs)) + Unit::new(term_reducing::meow( + &self.terms, + other.terms.into_iter().map(Inv::inv).collect(), + )) } } @@ -88,15 +81,7 @@ impl Mul for Unit { #[inline] fn mul(self, other: Self) -> Self::Output { - let mut lhs = self.terms.to_vec(); - - { - let mut rhs_unit = other; - lhs.reserve_exact(rhs_unit.terms.len()); - lhs.append(rhs_unit.terms.to_mut()); - } - - Self::new(term_reducing::reduce_terms(&lhs)) + Self::new(term_reducing::meow(&self.terms, other.terms.to_vec())) } } @@ -108,10 +93,7 @@ impl<'a> Mul<&'a Self> for Unit { #[inline] fn mul(self, other: &'a Self) -> Self::Output { - let mut lhs = self.terms.to_vec(); - lhs.extend_from_slice(&other.terms); - - Self::new(term_reducing::reduce_terms(&lhs)) + Self::new(term_reducing::meow(&self.terms, other.terms.to_vec())) } } @@ -123,10 +105,7 @@ impl<'a> Mul for &'a Unit { #[inline] fn mul(self, other: &'a Unit) -> Self::Output { - let mut lhs = self.terms.to_vec(); - lhs.extend_from_slice(&other.terms); - - Unit::new(term_reducing::reduce_terms(&lhs)) + Unit::new(term_reducing::meow(&self.terms, other.terms.to_vec())) } } @@ -138,15 +117,7 @@ impl<'a> Mul for &'a Unit { #[inline] fn mul(self, other: Unit) -> Self::Output { - let mut lhs = self.terms.to_vec(); - - { - let mut rhs_unit = other; - lhs.reserve_exact(rhs_unit.terms.len()); - lhs.append(rhs_unit.terms.to_mut()); - } - - Unit::new(term_reducing::reduce_terms(&lhs)) + Unit::new(term_reducing::meow(&self.terms, other.terms.to_vec())) } } diff --git a/crates/api/src/unit/term_reducing.rs b/crates/api/src/unit/term_reducing.rs index a72f1b25..edea9b9c 100644 --- a/crates/api/src/unit/term_reducing.rs +++ b/crates/api/src/unit/term_reducing.rs @@ -14,7 +14,11 @@ //! use std::borrow::Cow; -use crate::{composable::ComposablyEq, FieldEq, Term}; +use crate::{ + composable::ComposablyEq, + term::term_reduce::{ReducedTerm, TermReduce}, + FieldEq, Term, +}; /// Function used in `Unit` for reducing its `Term`s. /// @@ -29,7 +33,7 @@ pub(super) fn reduce_terms(terms: &[Term]) -> Cow<'static, [Term]> { let mut ids_to_remove = vec![]; let mut output = vec![]; - for (i, lhs) in terms.iter().enumerate() { + 'outer: for (i, lhs) in terms.iter().enumerate() { if ids_to_remove.contains(&i) { continue; } @@ -42,19 +46,30 @@ pub(super) fn reduce_terms(terms: &[Term]) -> Cow<'static, [Term]> { continue 'inner; } - if lhs.composably_eq(rhs) { - let new_exponent = new_term.effective_exponent() + rhs.effective_exponent(); + match lhs.composably_eq(rhs) { + Some(0) => { + ids_to_remove.push(i); + ids_to_remove.push(offset); + continue 'outer; + } + Some(exponent) => { + let _ = new_term.set_exponent(exponent); - let _ = new_term.set_exponent(new_exponent); - - ids_to_remove.push(offset); + ids_to_remove.push(offset); + } + None => (), } + offset += 1; } output.push(new_term); } + cleanup(output) +} + +fn cleanup(mut output: Vec) -> Cow<'static, [Term]> { // If everything is reduced away, the effective Unit should be "1". if output.is_empty() { Cow::Borrowed(crate::term::UNITY_ARRAY_REF) @@ -66,6 +81,87 @@ pub(super) fn reduce_terms(terms: &[Term]) -> Cow<'static, [Term]> { } } +/// This is the algorithm for determining if & how to combine or cancel out Terms when multiplying +/// and dividing Units/Measurements. +/// +/// * `lhs_terms`: The `Term`s from the left-hand side of the operation. +/// * `rhs_terms`: The `Term`s from the right-hand side of the operation. +/// +pub(super) fn meow(lhs_terms: &[Term], rhs_terms: Vec) -> Cow<'static, [Term]> { + let mut output: Vec = vec![]; + let mut remaining_rhs = rhs_terms; + + for lhs in lhs_terms { + let what_to_keep = lhs_single_rhs(lhs, &remaining_rhs); + + if what_to_keep.keep_lhs { + output.push(lhs.clone()); + } + + output.extend(what_to_keep.new_terms); + remaining_rhs = what_to_keep.kept_terms; + + // Break if there is nothing left on the RHS to compare the LHS to. + if remaining_rhs.is_empty() { + break; + } + } + + output.extend_from_slice(&remaining_rhs); + + cleanup(output) +} + +#[derive(Debug)] +struct WhatToKeep { + keep_lhs: bool, + new_terms: Vec, + kept_terms: Vec, +} + +impl Default for WhatToKeep { + fn default() -> Self { + Self { + keep_lhs: true, + new_terms: Vec::default(), + kept_terms: Vec::default(), + } + } +} + +// TODO: Change back to Cow +fn lhs_single_rhs(lhs: &Term, rhs_terms: &[Term]) -> WhatToKeep { + let mut what_to_keep = WhatToKeep::default(); + + for (i, rhs) in rhs_terms.iter().enumerate() { + match lhs.term_reduce(rhs) { + ReducedTerm::ReducedToTerm(new_term) => { + what_to_keep.new_terms.push(new_term); + what_to_keep.keep_lhs = false; + + if let Some(things) = rhs_terms.get((i + 1)..) { + what_to_keep.kept_terms.extend_from_slice(things); + } + + break; + } + ReducedTerm::ReducedAway => { + what_to_keep.keep_lhs = false; + + if let Some(things) = rhs_terms.get((i + 1)..) { + what_to_keep.kept_terms.extend_from_slice(things); + } + break; + } + ReducedTerm::NotReducible => { + what_to_keep.kept_terms.push(rhs.clone()); + } + } + } + + what_to_keep +} + #[cfg(test)] mod tests { use crate::{