代数 - (乗法)群と加法群
積に関する群 \((X,\times,1)\) を Group
の名前で モノイド の拡張として定義する.
- 演算:
std::ops::Mul
- 単位元:
Monoid::one()
- 逆元:
Group::inv()
和に関する群を AGroup
(Additive Group) の名前で定義する.
- 演算:
std::ops::Add
- 単位元:
AGroup::zero()
- 逆元:
std::ops::neg
マクロ agroup!
はユーザーが定義した型を手早く加法群にする.
agroup! {
MyStruct<X> where [X: Copy + ...] ;
zero = MyStruct(0) ;
add(self, other) = { ... } ;
neg(self) = { ... } ;
}
agroup!
は add_assign
, sub
, sub_assign
, sum
を自動で定義する.
/// Algebra - Group (*, 1, inv)
use crate::algebra::monoid::*;
pub trait Group: Monoid {
fn inv(self) -> Self;
}
/// Algebra - AGroup (Additive Group) (+, -, 0)
pub trait AGroup:
std::ops::Add<Output = Self>
+ std::ops::Sub<Output = Self>
+ std::ops::Neg<Output = Self>
+ std::iter::Sum
where
Self: std::marker::Sized,
{
fn zero() -> Self;
}
#[macro_export]
macro_rules! agroup {
(
$type:ty where [ $( $params:tt )* ] ;
zero = $zero:expr ;
add($self:ident, $y:ident) = $code:block ;
neg($self_neg:ident) = $code_neg:block
$(;)*
) => {
impl<$($params)*> std::ops::Add for $type {
type Output = Self;
fn add($self, $y: Self) -> Self { $code }
}
impl<$($params)*> std::ops::Neg for $type {
type Output = Self;
fn neg($self_neg) -> Self { $code_neg }
}
impl<$($params)*> std::ops::Sub for $type {
type Output = Self;
fn sub($self, other: Self) -> Self { ($self) + (-other) }
}
impl<$($params)*> std::ops::AddAssign for $type where Self: Clone {
fn add_assign(&mut $self, $y: Self) {
*$self = (*$self).clone() + $y;
}
}
impl<$($params)*> std::ops::SubAssign for $type where Self: Clone {
fn sub_assign(&mut $self, $y: Self) {
*$self = (*$self).clone() - $y;
}
}
impl<$($params)*> std::iter::Sum for $type {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::zero(), std::ops::Add::add)
}
}
impl<$($params)*> AGroup for $type {
fn zero() -> Self { $zero }
}
};
(
$type:ty ;
zero = $zero:expr ;
add($self:ident, $y:ident) = $code:block ;
neg($self_neg:ident) = $code_neg:block
$(;)*
) => {
agroup! { $type where []; zero = $zero; add($self, $y) = $code; neg($self_neg) = $code_neg; }
};
}
impl AGroup for i64 {
fn zero() -> Self {
0
}
}
impl AGroup for f64 {
fn zero() -> Self {
0.0
}
}
#[cfg(test)]
mod test_group {
use crate::algebra::group_additive::*;
#[test]
fn test_agroup_intish() {
assert_eq!(i64::zero(), 0);
assert_eq!(i64::zero() + 3, 3);
assert_eq!(3 - 3, i64::zero());
}
#[test]
fn test_agroup_realish() {
assert_eq!(f64::zero(), 0.0);
assert_eq!(f64::zero() + 3.0, 3.0);
assert_eq!(3.0 - 3.0, f64::zero());
}
}