237 lines
4.9 KiB
Rust
237 lines
4.9 KiB
Rust
use num::traits::{One, Zero};
|
|
use rand::distr::{Distribution, StandardUniform};
|
|
use rand::Rng;
|
|
use std::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
|
pub struct F3 {
|
|
s: i8,
|
|
}
|
|
|
|
impl F3 {
|
|
pub const ELEMENTS: [F3; 3] = [F3 { s: 0 }, F3 { s: 1 }, F3 { s: 2 }];
|
|
}
|
|
|
|
impl From<F3> for usize {
|
|
fn from(f: F3) -> usize {
|
|
f.s as usize
|
|
}
|
|
}
|
|
|
|
impl TryFrom<u8> for F3 {
|
|
type Error = &'static str;
|
|
|
|
fn try_from(i: u8) -> Result<Self, Self::Error> {
|
|
if i > 2 {
|
|
Err("out of range")
|
|
} else {
|
|
Ok(F3 { s: i as i8 })
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Add for F3 {
|
|
type Output = F3;
|
|
|
|
fn add(self, rhs: Self) -> Self::Output {
|
|
F3 {
|
|
s: (self.s + rhs.s).rem_euclid(3),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl AddAssign for F3 {
|
|
fn add_assign(&mut self, rhs: Self) {
|
|
*self = *self + rhs;
|
|
}
|
|
}
|
|
|
|
impl Zero for F3 {
|
|
fn zero() -> Self {
|
|
F3 { s: 0 }
|
|
}
|
|
|
|
fn is_zero(&self) -> bool {
|
|
*self == Self::zero()
|
|
}
|
|
}
|
|
|
|
impl Sub for F3 {
|
|
type Output = F3;
|
|
|
|
fn sub(self, rhs: Self) -> Self::Output {
|
|
F3 {
|
|
s: (self.s - rhs.s).rem_euclid(3),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl SubAssign for F3 {
|
|
fn sub_assign(&mut self, rhs: Self) {
|
|
*self = *self - rhs;
|
|
}
|
|
}
|
|
|
|
impl Mul for F3 {
|
|
type Output = F3;
|
|
|
|
fn mul(self, rhs: Self) -> Self::Output {
|
|
F3 {
|
|
s: (self.s * rhs.s).rem_euclid(3),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl MulAssign for F3 {
|
|
fn mul_assign(&mut self, rhs: Self) {
|
|
*self = *self * rhs;
|
|
}
|
|
}
|
|
|
|
impl One for F3 {
|
|
fn one() -> Self {
|
|
F3 { s: 1 }
|
|
}
|
|
|
|
fn is_one(&self) -> bool {
|
|
*self == Self::one()
|
|
}
|
|
}
|
|
|
|
impl Distribution<F3> for StandardUniform {
|
|
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> F3 {
|
|
F3 {
|
|
s: rng.random_range(0..3),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn add_associative() {
|
|
for a in F3::ELEMENTS {
|
|
for b in F3::ELEMENTS {
|
|
for c in F3::ELEMENTS {
|
|
assert_eq!((a + b) + c, a + (b + c));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn add_identity() {
|
|
for a in F3::ELEMENTS {
|
|
assert_eq!(F3::zero() + a, a);
|
|
assert_eq!(a + F3::zero(), a);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn add_inverse() {
|
|
for a in F3::ELEMENTS {
|
|
let mut has_inverse = false;
|
|
for b in F3::ELEMENTS {
|
|
if a + b == F3::zero() {
|
|
assert!(!has_inverse);
|
|
has_inverse = true;
|
|
}
|
|
}
|
|
assert!(has_inverse);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn sub_is_add_inverse() {
|
|
for a in F3::ELEMENTS {
|
|
for b in F3::ELEMENTS {
|
|
assert_eq!(a + b - b, a);
|
|
assert_eq!(a - b + b, a);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn add_commutative() {
|
|
for a in F3::ELEMENTS {
|
|
for b in F3::ELEMENTS {
|
|
assert_eq!(a + b, b + a);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn mul_associative() {
|
|
for a in F3::ELEMENTS {
|
|
for b in F3::ELEMENTS {
|
|
for c in F3::ELEMENTS {
|
|
assert_eq!((a * b) * c, a * (b * c));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn mul_identity() {
|
|
for a in F3::ELEMENTS {
|
|
assert_eq!(F3::one() * a, a);
|
|
assert_eq!(a * F3::one(), a);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn mul_inverse() {
|
|
for a in F3::ELEMENTS {
|
|
if !a.is_zero() {
|
|
let mut has_inverse = false;
|
|
for b in F3::ELEMENTS {
|
|
if a * b == F3::one() {
|
|
assert!(!has_inverse);
|
|
has_inverse = true;
|
|
}
|
|
}
|
|
assert!(has_inverse);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn mul_commutative() {
|
|
for a in F3::ELEMENTS {
|
|
for b in F3::ELEMENTS {
|
|
assert_eq!(a * b, b * a);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn distributive() {
|
|
for a in F3::ELEMENTS {
|
|
for b in F3::ELEMENTS {
|
|
for c in F3::ELEMENTS {
|
|
assert_eq!(a * (b + c), a * b + a * c);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn add_is_like_set() {
|
|
let e = F3::ELEMENTS;
|
|
|
|
assert_eq!(e[0] + e[0] + e[0], F3::zero());
|
|
assert_eq!(e[1] + e[1] + e[1], F3::zero());
|
|
assert_eq!(e[2] + e[2] + e[2], F3::zero());
|
|
assert_eq!(e[0] + e[1] + e[2], F3::zero());
|
|
|
|
assert_ne!(e[0] + e[0] + e[1], F3::zero());
|
|
assert_ne!(e[0] + e[0] + e[2], F3::zero());
|
|
assert_ne!(e[1] + e[1] + e[0], F3::zero());
|
|
assert_ne!(e[1] + e[1] + e[2], F3::zero());
|
|
assert_ne!(e[2] + e[2] + e[0], F3::zero());
|
|
assert_ne!(e[2] + e[2] + e[1], F3::zero());
|
|
}
|
|
}
|