From dd37d10595c11fdc4c4277b27986518ece1708df Mon Sep 17 00:00:00 2001 From: static Date: Wed, 9 Oct 2024 16:55:01 +0000 Subject: [PATCH] Assignment 6 Done --- src/assignments/assignment06/semiring.rs | 115 +++++++++++--- .../assignment06/symbolic_differentiation.rs | 149 +++++++++++++++--- 2 files changed, 221 insertions(+), 43 deletions(-) diff --git a/src/assignments/assignment06/semiring.rs b/src/assignments/assignment06/semiring.rs index cc8c3d0..ac7dc80 100644 --- a/src/assignments/assignment06/semiring.rs +++ b/src/assignments/assignment06/semiring.rs @@ -33,55 +33,55 @@ pub fn from_usize(value: usize) -> T { impl Semiring for u64 { fn zero() -> Self { - todo!() + 0 } fn one() -> Self { - todo!() + 1 } fn add(&self, rhs: &Self) -> Self { - todo!() + self + rhs } fn mul(&self, rhs: &Self) -> Self { - todo!() + self * rhs } } impl Semiring for i64 { fn zero() -> Self { - todo!() + 0 } fn one() -> Self { - todo!() + 1 } fn add(&self, rhs: &Self) -> Self { - todo!() + self + rhs } fn mul(&self, rhs: &Self) -> Self { - todo!() + self * rhs } } impl Semiring for f64 { fn zero() -> Self { - todo!() + 0.0 } fn one() -> Self { - todo!() + 1.0 } fn add(&self, rhs: &Self) -> Self { - todo!() + self + rhs } fn mul(&self, rhs: &Self) -> Self { - todo!() + self * rhs } } @@ -105,42 +105,91 @@ pub struct Polynomial { impl Semiring for Polynomial { fn zero() -> Self { - todo!() + Self { + coefficients: HashMap::new(), + } } fn one() -> Self { - todo!() + Self { + coefficients: HashMap::from([(0, C::one())]), + } } fn add(&self, rhs: &Self) -> Self { - todo!() + let mut coefficients = self.coefficients.clone(); + + for (deg, coef) in &rhs.coefficients { + _ = coefficients + .entry(*deg) + .and_modify(|value| *value = value.add(coef)) + .or_insert(coef.clone()); + } + + coefficients.retain(|_, coef| *coef != C::zero()); + + Self { coefficients } } fn mul(&self, rhs: &Self) -> Self { - todo!() + let mut coefficients: HashMap = HashMap::new(); + + for (ldeg, lcoef) in &self.coefficients { + for (rdeg, rcoef) in &rhs.coefficients { + let coef = lcoef.mul(rcoef); + _ = coefficients + .entry(ldeg + rdeg) + .and_modify(|value| *value = value.add(&coef)) + .or_insert(coef); + } + } + + coefficients.retain(|_, coef| *coef != C::zero()); + + Self { coefficients } } } impl Polynomial { /// Constructs polynomial `x`. pub fn x() -> Self { - todo!() + Self { + coefficients: HashMap::from([(1, C::one())]), + } } /// Evaluates the polynomial with the given value. pub fn eval(&self, value: C) -> C { - todo!() + let mut result = C::zero(); + + for (deg, coef) in &self.coefficients { + let mut xn = C::one(); + let mut n = 0; + + while n < *deg { + xn = xn.mul(&value); + n += 1; + } + + result = result.add(&coef.mul(&xn)); + } + + result } /// Constructs polynomial `ax^n`. pub fn term(a: C, n: u64) -> Self { - todo!() + Self { + coefficients: HashMap::from([(n, a)]), + } } } impl From for Polynomial { fn from(value: C) -> Self { - todo!() + Self { + coefficients: HashMap::from([(0, value)]), + } } } @@ -164,6 +213,30 @@ impl std::str::FromStr for Polynomial { type Err = (); // Ignore this for now... fn from_str(s: &str) -> Result { - todo!() + let mut coefficients: HashMap = HashMap::new(); + + for term in s.split(" + ") { + let has_x: bool = term.contains('x'); + let has_power = term.contains('^'); + + let deg: u64 = if has_power { + term.split("^").nth(1).unwrap().parse().unwrap() + } else if has_x { + 1 + } else { + 0 + }; + let coef: usize = if has_x && term.find("x").unwrap() == 0 { + 1 + } else if has_x { + term.split("x").nth(0).unwrap().parse().unwrap() + } else { + term.parse().unwrap() + }; + + let _unused = coefficients.insert(deg, from_usize(coef)); + } + + Ok(Self { coefficients }) } } diff --git a/src/assignments/assignment06/symbolic_differentiation.rs b/src/assignments/assignment06/symbolic_differentiation.rs index a109e40..abaa658 100644 --- a/src/assignments/assignment06/symbolic_differentiation.rs +++ b/src/assignments/assignment06/symbolic_differentiation.rs @@ -38,11 +38,39 @@ impl Rational { } } +fn gcd(a: isize, b: isize) -> isize { + if b == 0 { + a + } else { + gcd(b, a % b) + } +} + +fn lcm(a: isize, b: isize) -> isize { + (a * b) / gcd(a, b) +} + +fn normalize(r: &Rational) -> Rational { + let factor = if r.denominator < 0 { -1 } else { 1 }; + Rational { + numerator: r.numerator * factor, + denominator: r.denominator * factor, + } +} + impl Add for Rational { type Output = Self; fn add(self, rhs: Self) -> Self::Output { - todo!() + let lcm = lcm(self.denominator, rhs.denominator); + let num = + self.numerator * (lcm / self.denominator) + rhs.numerator * (lcm / rhs.denominator); + let gcd = gcd(num, lcm); + + normalize(&Self { + numerator: num / gcd, + denominator: lcm / gcd, + }) } } @@ -50,7 +78,14 @@ impl Mul for Rational { type Output = Self; fn mul(self, rhs: Self) -> Self::Output { - todo!() + let num = self.numerator * rhs.numerator; + let den = self.denominator * rhs.denominator; + let gcd = gcd(num, den) * (if den < 0 { -1 } else { 1 }); + + normalize(&Self { + numerator: num / gcd, + denominator: den / gcd, + }) } } @@ -58,7 +93,7 @@ impl Sub for Rational { type Output = Self; fn sub(self, rhs: Self) -> Self::Output { - todo!() + self + (MINUS_ONE * rhs) } } @@ -66,7 +101,10 @@ impl Div for Rational { type Output = Self; fn div(self, rhs: Self) -> Self::Output { - todo!() + self.mul(Self { + numerator: rhs.denominator, + denominator: rhs.numerator, + }) } } @@ -84,7 +122,7 @@ pub trait Differentiable: Clone { impl Differentiable for Rational { /// HINT: Consult fn diff(&self) -> Self { - todo!() + ZERO } } @@ -108,19 +146,31 @@ pub enum SingletonPolynomial { impl SingletonPolynomial { /// Creates a new const polynomial. pub fn new_c(r: Rational) -> Self { - todo!() + SingletonPolynomial::Const(r) } /// Creates a new polynomial. pub fn new_poly(coeff: Rational, power: Rational) -> Self { - todo!() + SingletonPolynomial::Polynomial { coeff, power } } } impl Differentiable for SingletonPolynomial { /// HINT: Consult fn diff(&self) -> Self { - todo!() + match self { + Self::Const(_) => Self::Const(ZERO), + Self::Polynomial { coeff, power } => { + if *power == ONE { + Self::Const(*coeff) + } else { + Self::Polynomial { + coeff: *coeff * *power, + power: *power - ONE, + } + } + } + } } } @@ -131,7 +181,7 @@ pub struct Exp; impl Exp { /// Creates a new exponential function. pub fn new() -> Self { - todo!() + Exp {} } } @@ -144,7 +194,7 @@ impl Default for Exp { impl Differentiable for Exp { /// HINT: Consult fn diff(&self) -> Self { - todo!() + *self } } @@ -168,19 +218,24 @@ pub enum Trignometric { impl Trignometric { /// Creates a new sine function. pub fn new_sine(coeff: Rational) -> Self { - todo!() + Trignometric::Sine { coeff } } /// Creates a new cosine function. pub fn new_cosine(coeff: Rational) -> Self { - todo!() + Trignometric::Cosine { coeff } } } impl Differentiable for Trignometric { /// HINT: Consult fn diff(&self) -> Self { - todo!() + match self { + Self::Sine { coeff } => Self::Cosine { coeff: *coeff }, + Self::Cosine { coeff } => Self::Sine { + coeff: MINUS_ONE * *coeff, + }, + } } } @@ -199,7 +254,12 @@ pub enum BaseFuncs { impl Differentiable for BaseFuncs { fn diff(&self) -> Self { - todo!() + match self { + Self::Const(_) => Self::Const(ZERO), + Self::Poly(p) => Self::Poly(p.diff()), + Self::Exp(e) => Self::Exp(e.diff()), + Self::Trig(t) => Self::Trig(t.diff()), + } } } @@ -222,14 +282,41 @@ pub enum ComplexFuncs { impl Differentiable for Box { fn diff(&self) -> Self { - todo!() + Box::new(self.deref().diff()) } } impl Differentiable for ComplexFuncs { /// HINT: Consult fn diff(&self) -> Self { - todo!() + match self { + Self::Func(f) => Self::Func(f.diff()), + Self::Add(lhs, rhs) => Self::Add(lhs.diff(), rhs.diff()), + Self::Sub(lhs, rhs) => Self::Sub(lhs.diff(), rhs.diff()), + Self::Mul(lhs, rhs) => { + let diff_lhs = lhs.diff(); + let diff_rhs = rhs.diff(); + Self::Add( + Box::new(Self::Mul(diff_lhs, rhs.clone())), + Box::new(Self::Mul(lhs.clone(), diff_rhs)), + ) + } + Self::Div(lhs, rhs) => { + let diff_lhs = lhs.diff(); + let diff_rhs = rhs.diff(); + Self::Div( + Box::new(Self::Sub( + Box::new(Self::Mul(diff_lhs, rhs.clone())), + Box::new(Self::Mul(lhs.clone(), diff_rhs)), + )), + Box::new(Self::Mul(rhs.clone(), rhs.clone())), + ) + } + Self::Comp(outer, inner) => Self::Mul( + Box::new(Self::Comp(outer.diff(), inner.clone())), + inner.diff(), + ), + } } } @@ -241,37 +328,55 @@ pub trait Evaluate { impl Evaluate for Rational { fn evaluate(&self, x: f64) -> f64 { - todo!() + (self.numerator as f64) / (self.denominator as f64) } } impl Evaluate for SingletonPolynomial { fn evaluate(&self, x: f64) -> f64 { - todo!() + match self { + Self::Const(r) => r.evaluate(x), + Self::Polynomial { coeff, power } => x.powf(power.evaluate(x)) * coeff.evaluate(x), + } } } impl Evaluate for Exp { fn evaluate(&self, x: f64) -> f64 { - todo!() + x.exp() } } impl Evaluate for Trignometric { fn evaluate(&self, x: f64) -> f64 { - todo!() + match self { + Self::Sine { coeff } => coeff.evaluate(x) * x.sin(), + Self::Cosine { coeff } => coeff.evaluate(x) * x.cos(), + } } } impl Evaluate for BaseFuncs { fn evaluate(&self, x: f64) -> f64 { - todo!() + match self { + Self::Const(r) => r.evaluate(x), + Self::Poly(p) => p.evaluate(x), + Self::Exp(e) => e.evaluate(x), + Self::Trig(t) => t.evaluate(x), + } } } impl Evaluate for ComplexFuncs { fn evaluate(&self, x: f64) -> f64 { - todo!() + match self { + Self::Func(f) => f.evaluate(x), + Self::Add(lhs, rhs) => lhs.evaluate(x) + rhs.evaluate(x), + Self::Sub(lhs, rhs) => lhs.evaluate(x) - rhs.evaluate(x), + Self::Mul(lhs, rhs) => lhs.evaluate(x) * rhs.evaluate(x), + Self::Div(lhs, rhs) => lhs.evaluate(x) / rhs.evaluate(x), + Self::Comp(outer, inner) => outer.evaluate(inner.evaluate(x)), + } } }