use std::ops::{AddAssign, DivAssign, MulAssign, SubAssign};
use rug::{
ops::{AddAssignRound, DivAssignRound, MulAssignRound, NegAssign, SubAssignRound},
Complete,
};
use super::{One, Zero};
pub trait FromRational: Sized {
fn from_rational(nominator: &str, denominator: &str) -> Self;
}
pub trait Field: PseudoField {}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum Round {
Nearest,
Zero,
Up,
Down,
}
pub trait SparseField: Sized + Clone + Ord + Eq + Zero + One + FromRational + Into<f64> {
fn neg_assign(&mut self);
fn abs_assign(&mut self);
fn add_assign(&mut self, rhs: &Self, round: Round);
fn sub_assign(&mut self, rhs: &Self, round: Round);
fn mul_assign(&mut self, rhs: &Self, round: Round);
fn div_assign(&mut self, rhs: &Self, round: Round);
}
pub trait PseudoField: Sized + Clone + PartialOrd + PartialEq + Zero + One + FromRational {
fn neg_assign(&mut self);
fn abs_assign(&mut self);
fn add_assign(&mut self, rhs: &Self);
fn sub_assign(&mut self, rhs: &Self);
fn mul_assign(&mut self, rhs: &Self);
fn div_assign(&mut self, rhs: &Self);
}
impl<T: SparseField> PseudoField for T {
fn neg_assign(&mut self) {
self.neg_assign()
}
fn abs_assign(&mut self) {
self.abs_assign()
}
fn add_assign(&mut self, rhs: &Self) {
self.add_assign(rhs, Round::Nearest)
}
fn sub_assign(&mut self, rhs: &Self) {
self.sub_assign(rhs, Round::Nearest)
}
fn mul_assign(&mut self, rhs: &Self) {
self.mul_assign(rhs, Round::Nearest)
}
fn div_assign(&mut self, rhs: &Self) {
self.div_assign(rhs, Round::Nearest)
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct Float64(rug::float::OrdFloat);
impl FromRational for Float64 {
fn from_rational(nominator: &str, denominator: &str) -> Self {
let nominator = nominator.parse::<f64>().unwrap();
let denominator = denominator.parse::<f64>().unwrap();
Self(rug::Float::with_val(53, nominator / denominator).into())
}
}
impl One for Float64 {
fn one() -> Self {
Self(rug::Float::with_val(53, 1.0).into())
}
fn is_one(&self) -> bool {
*self.0.as_float() == 1.0
}
}
impl Zero for Float64 {
fn zero() -> Self {
Self(rug::Float::with_val(53, 0.0).into())
}
fn is_zero(&self) -> bool {
self.0.as_float().is_zero()
}
}
impl From<Float64> for f64 {
fn from(float: Float64) -> Self {
float.0.as_float().to_f64()
}
}
fn round_to_rug_round(round: Round) -> rug::float::Round {
match round {
Round::Nearest => rug::float::Round::Nearest,
Round::Zero => rug::float::Round::Zero,
Round::Up => rug::float::Round::Up,
Round::Down => rug::float::Round::Down,
}
}
impl SparseField for Float64 {
fn neg_assign(&mut self) {
self.0.as_float_mut().neg_assign()
}
fn abs_assign(&mut self) {
self.0.as_float_mut().abs_mut();
}
fn add_assign(&mut self, rhs: &Self, round: Round) {
self.0
.as_float_mut()
.add_assign_round(rhs.0.as_float(), round_to_rug_round(round));
}
fn sub_assign(&mut self, rhs: &Self, round: Round) {
self.0
.as_float_mut()
.sub_assign_round(rhs.0.as_float(), round_to_rug_round(round));
}
fn mul_assign(&mut self, rhs: &Self, round: Round) {
self.0
.as_float_mut()
.mul_assign_round(rhs.0.as_float(), round_to_rug_round(round));
}
fn div_assign(&mut self, rhs: &Self, round: Round) {
self.0
.as_float_mut()
.div_assign_round(rhs.0.as_float(), round_to_rug_round(round));
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Rational(rug::Rational);
impl From<Rational> for f64 {
fn from(rational: Rational) -> Self {
rational.0.to_f64()
}
}
impl One for Rational {
fn one() -> Self {
Self(rug::Rational::from_f64(1.0).unwrap())
}
fn is_one(&self) -> bool {
self.0 == 1.0
}
}
impl Zero for Rational {
fn zero() -> Self {
Self(rug::Rational::from_f64(0.0).unwrap())
}
fn is_zero(&self) -> bool {
self.0 == 0.0
}
}
impl FromRational for Rational {
fn from_rational(nominator: &str, denominator: &str) -> Self {
let result = rug::Rational::parse(format!("{nominator}/{denominator}"))
.map(|incomplete| incomplete.complete());
if result.is_err() && denominator == "1" {
Rational(
nominator
.parse()
.map(|value| rug::Rational::from_f64(value).unwrap())
.unwrap(),
)
} else {
Rational(result.unwrap())
}
}
}
impl PseudoField for Rational {
fn neg_assign(&mut self) {
self.0.neg_assign();
}
fn abs_assign(&mut self) {
self.0.abs_mut();
}
fn add_assign(&mut self, rhs: &Self) {
self.0.add_assign(&rhs.0);
}
fn sub_assign(&mut self, rhs: &Self) {
self.0.sub_assign(&rhs.0);
}
fn mul_assign(&mut self, rhs: &Self) {
self.0.mul_assign(&rhs.0);
}
fn div_assign(&mut self, rhs: &Self) {
self.0.div_assign(&rhs.0);
}
}
#[derive(Clone, PartialEq, Debug)]
pub struct IntervalField<F: SparseField> {
lower: F,
upper: F,
}
impl<F: SparseField> One for IntervalField<F> {
fn one() -> Self {
Self {
lower: F::one(),
upper: F::one(),
}
}
fn is_one(&self) -> bool {
self.lower.is_one() && self.upper.is_one()
}
}
impl<F: SparseField> Zero for IntervalField<F> {
fn zero() -> Self {
Self {
lower: F::zero(),
upper: F::zero(),
}
}
fn is_zero(&self) -> bool {
self.lower.is_zero() && self.upper.is_zero()
}
}
impl<F: SparseField> PartialOrd for IntervalField<F> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
use std::cmp::Ordering::*;
match (
self.upper.partial_cmp(&other.lower)?,
self.lower.partial_cmp(&other.upper)?,
) {
(Equal, Equal) => Some(Equal),
(Less, Less) => Some(Less),
(Greater, Greater) => Some(Greater),
(Equal, Less) => None,
(Greater, Less) => None,
(Greater, Equal) => None,
_ => unreachable!(),
}
}
}