use super::*;
use std::ops::{AddAssign, Sub, SubAssign};
impl SubAssign<&Function> for Function {
fn sub_assign(&mut self, rhs: &Function) {
match rhs {
Function::Zero => {}
Function::Constant(c) => self.sub_assign(*c),
Function::Linear(l) => self.sub_assign(l),
Function::Quadratic(q) => self.sub_assign(q),
Function::Polynomial(p) => self.sub_assign(p),
}
}
}
impl SubAssign for Function {
fn sub_assign(&mut self, rhs: Self) {
match rhs {
Function::Zero => {}
Function::Constant(c) => self.sub_assign(c),
Function::Linear(l) => self.sub_assign(l),
Function::Quadratic(q) => self.sub_assign(q),
Function::Polynomial(p) => self.sub_assign(p),
}
}
}
impl SubAssign<Coefficient> for Function {
fn sub_assign(&mut self, rhs: Coefficient) {
match self {
Function::Zero => *self = Function::from(-rhs),
Function::Constant(c) => {
*self = (*c - rhs).map(Function::from).unwrap_or(Function::Zero)
}
Function::Linear(l) => l.sub_assign(rhs),
Function::Quadratic(q) => q.sub_assign(rhs),
Function::Polynomial(p) => p.sub_assign(rhs),
}
}
}
impl SubAssign<&Linear> for Function {
fn sub_assign(&mut self, rhs: &Linear) {
match self {
Function::Linear(l) => l.sub_assign(rhs),
Function::Quadratic(q) => q.sub_assign(rhs),
Function::Polynomial(p) => p.sub_assign(rhs),
_ => self.sub_assign(rhs.clone()),
}
}
}
impl SubAssign<Linear> for Function {
fn sub_assign(&mut self, mut rhs: Linear) {
match self {
Function::Zero => *self = Function::from(-rhs),
Function::Constant(c) => {
rhs = -rhs;
rhs += *c;
*self = Function::from(rhs);
}
Function::Linear(l) => l.sub_assign(rhs),
Function::Quadratic(q) => q.sub_assign(&rhs),
Function::Polynomial(p) => p.sub_assign(&rhs),
}
}
}
impl SubAssign<&Quadratic> for Function {
fn sub_assign(&mut self, rhs: &Quadratic) {
match self {
Function::Quadratic(q) => q.sub_assign(rhs),
Function::Polynomial(p) => p.sub_assign(rhs),
_ => self.sub_assign(rhs.clone()),
}
}
}
impl SubAssign<Quadratic> for Function {
fn sub_assign(&mut self, mut rhs: Quadratic) {
match self {
Function::Zero => *self = Function::from(-rhs),
Function::Constant(c) => {
rhs = -rhs;
rhs += *c;
*self = Function::from(rhs);
}
Function::Linear(l) => {
let mut q = -rhs;
q += &*l;
*self = Function::from(q);
}
Function::Quadratic(q1) => q1.sub_assign(rhs),
Function::Polynomial(p) => p.sub_assign(&rhs),
}
}
}
impl SubAssign<&Polynomial> for Function {
fn sub_assign(&mut self, rhs: &Polynomial) {
match self {
Function::Polynomial(p) => p.sub_assign(rhs),
_ => self.sub_assign(rhs.clone()),
}
}
}
impl SubAssign<Polynomial> for Function {
fn sub_assign(&mut self, mut rhs: Polynomial) {
match self {
Function::Zero => *self = Function::from(-rhs),
Function::Constant(c) => {
rhs = -rhs;
rhs += *c;
*self = Function::from(rhs);
}
Function::Linear(l) => {
rhs = -rhs;
rhs += &*l;
*self = Function::from(rhs);
}
Function::Quadratic(q) => {
rhs = -rhs;
rhs += &*q;
*self = Function::from(rhs);
}
Function::Polynomial(p) => p.sub_assign(rhs),
}
}
}
macro_rules! impl_sub_via_sub_assign {
($RHS:ty) => {
impl Sub<$RHS> for Function {
type Output = Self;
fn sub(mut self, rhs: $RHS) -> Self::Output {
self.sub_assign(rhs);
self
}
}
};
}
impl_sub_via_sub_assign!(Coefficient);
impl_sub_via_sub_assign!(Linear);
impl_sub_via_sub_assign!(&Linear);
impl_sub_via_sub_assign!(Quadratic);
impl_sub_via_sub_assign!(&Quadratic);
impl_sub_via_sub_assign!(Polynomial);
impl_sub_via_sub_assign!(&Polynomial);
impl_sub_via_sub_assign!(&Function);
impl Sub for Function {
type Output = Self;
fn sub(mut self, rhs: Self) -> Self::Output {
self.sub_assign(rhs);
self
}
}
impl Sub for &Function {
type Output = Function;
fn sub(self, rhs: Self) -> Self::Output {
if self.degree() < rhs.degree() {
-rhs.clone() + self.clone()
} else {
self.clone() - rhs.clone()
}
}
}
impl Sub<Function> for &Function {
type Output = Function;
fn sub(self, rhs: Function) -> Self::Output {
let mut out = -rhs;
out.add_assign(self);
out
}
}
#[cfg(test)]
mod tests {
use super::*;
use ::approx::assert_abs_diff_eq;
use proptest::prelude::*;
proptest! {
#[test]
fn sub_ref(a in any::<Function>(), b in any::<Function>()) {
let expected = a.clone() - b.clone();
assert_abs_diff_eq!(&a - &b, expected);
assert_abs_diff_eq!(&a - b.clone(), expected);
assert_abs_diff_eq!(a.clone() - &b, expected);
}
#[test]
fn zero_sub(a in any::<Function>()) {
assert_abs_diff_eq!(&a - Function::zero(), a.clone());
assert_abs_diff_eq!(Function::zero() - &a, -a.clone());
}
#[test]
fn sub_via_add_neg(a in any::<Function>(), b in any::<Function>()) {
assert_abs_diff_eq!(a.clone() - b.clone(), a + (-b.clone()));
}
#[test]
fn neg_sub(a in any::<Function>(), b in any::<Function>()) {
assert_abs_diff_eq!(-(a.clone() - b.clone()), b - a);
}
}
}