代数 - 超数
全順序付き群(整数など)に \(\pm \infty\) を付加した数. 台数 X
がモノイド/加法群/環の場合, Hyper<X>
もそのように定義でき, 自動で演算を定義する.
/// Algebra - Hyper Numbers (numbers with infinity)
use crate::agroup; // IGNORE
use crate::algebra::group_additive::*;
use crate::algebra::monoid::*;
use crate::algebra::ring::*;
use crate::monoid; // IGNORE
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Hyper<X> {
NegInf,
Real(X),
Inf,
}
use Hyper::{Inf, NegInf, Real};
impl<X> Hyper<X> {
pub fn unwrap(self) -> X {
if let Hyper::Real(x) = self {
x
} else {
panic!("Could not unwrap Hyper")
}
}
}
agroup! {
Hyper<X> where [X: AGroup];
zero = Real(X::zero());
add(self, other) = {
match (self, other) {
(Real(x), Real(y)) => Real(x + y),
(Inf, _) => Inf,
(_, Inf) => Inf,
_ => NegInf,
}
};
neg(self) = {
match self {
Inf => NegInf,
NegInf => Inf,
Real(x) => Real(-x),
}
};
}
monoid! {
Hyper<X> where [X: Monoid];
one = Real(X::one());
mul(self, other) = {
match (self, other) {
(Real(x), Real(y)) => Real(x * y),
(Inf, Inf) | (NegInf, NegInf) => Inf,
_ => NegInf,
}
};
}
impl<X: AGroup + Monoid> Ring for Hyper<X> {}
impl<X: std::ops::Add<Output = X>> std::ops::Add<X> for Hyper<X> {
type Output = Self;
fn add(self, y: X) -> Hyper<X> {
match (self, y) {
(Real(x), y) => Real(x + y),
(Inf, _) => Inf,
_ => NegInf,
}
}
}
impl<X: Clone + AGroup> std::ops::AddAssign<X> for Hyper<X> {
fn add_assign(&mut self, y: X) {
*self = (*self).clone() + Real(y);
}
}
#[cfg(test)]
mod test_hyper {
use crate::algebra::hyper::*;
#[test]
fn it_works() {
assert_eq!(Hyper::<i64>::zero(), Hyper::Real(0));
assert_eq!(Hyper::Real(42).unwrap(), 42);
assert!(Hyper::Real(0_i64) < Hyper::Real(1));
assert!(Hyper::NegInf < Hyper::Real(1));
assert!(Hyper::Real(0) < Hyper::Inf);
assert!(Hyper::<i64>::NegInf < Hyper::Inf);
assert_eq!(Hyper::Real(1) + 3, Hyper::Real(4));
}
#[test]
fn assign_op() {
{
let mut a = Hyper::Real(0_i64);
a += Hyper::Real(3);
assert_eq!(a, Hyper::Real(3));
a -= Hyper::Real(6);
assert_eq!(a, Hyper::Real(-3));
a += Hyper::Inf;
assert_eq!(a, Hyper::Inf);
a -= Hyper::Inf;
assert_eq!(a, Hyper::Inf);
}
}
#[test]
#[should_panic]
fn test_inf_cannot_unwrap() {
Hyper::<i64>::Inf.unwrap();
}
#[test]
#[should_panic]
fn test_neginf_cannot_unwrap() {
Hyper::<i64>::NegInf.unwrap();
}
}