#![allow(clippy::should_implement_trait)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Trit(pub(crate) u8);
pub const Z: Trit = Trit(0b00); pub const N: Trit = Trit(0b01); pub const P: Trit = Trit(0b10); pub const INV: Trit = Trit(0b11);
impl Trit {
#[inline]
pub fn is_valid(self) -> bool {
self.0 != 0b11
}
#[inline]
pub fn is_zero(self) -> bool {
self.0 == 0b00
}
#[inline]
pub fn is_inv(self) -> bool {
self.0 == 0b11
}
#[inline]
pub fn neg(self) -> Trit {
match self.0 {
0b01 => P,
0b10 => N,
_ => self, }
}
#[inline]
pub fn mul(self, rhs: Trit) -> Trit {
if self.0 == 0b11 || rhs.0 == 0b11 {
return INV;
}
if self.0 == 0b00 || rhs.0 == 0b00 {
return Z;
}
if self.0 == rhs.0 {
P
} else {
N
}
}
#[inline]
pub fn sign(self) -> Trit {
self
}
pub fn to_i8(self) -> Option<i8> {
match self.0 {
0b00 => Some(0),
0b01 => Some(-1),
0b10 => Some(1),
0b11 => None,
_ => None, }
}
pub fn from_i8(v: i8) -> Trit {
match v {
-1 => N,
0 => Z,
1 => P,
_ => INV,
}
}
#[inline]
pub fn bits(self) -> u8 {
self.0
}
}
impl std::ops::Mul for Trit {
type Output = Trit;
#[inline]
fn mul(self, rhs: Trit) -> Trit {
Trit::mul(self, rhs)
}
}
impl std::ops::Neg for Trit {
type Output = Trit;
#[inline]
fn neg(self) -> Trit {
Trit::neg(self)
}
}
impl std::fmt::Debug for Trit {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.0 {
0b00 => write!(f, "Z"),
0b01 => write!(f, "N"),
0b10 => write!(f, "P"),
0b11 => write!(f, "INV"),
_ => write!(f, "?"),
}
}
}
impl std::fmt::Display for Trit {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.0 {
0b00 => write!(f, "0"),
0b01 => write!(f, "-"),
0b10 => write!(f, "+"),
0b11 => write!(f, "!"),
_ => write!(f, "?"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mul_z_z() {
assert_eq!(Z * Z, Z);
}
#[test]
fn mul_z_n() {
assert_eq!(Z * N, Z);
}
#[test]
fn mul_z_p() {
assert_eq!(Z * P, Z);
}
#[test]
fn mul_n_z() {
assert_eq!(N * Z, Z);
}
#[test]
fn mul_n_n() {
assert_eq!(N * N, P);
} #[test]
fn mul_n_p() {
assert_eq!(N * P, N);
}
#[test]
fn mul_p_z() {
assert_eq!(P * Z, Z);
}
#[test]
fn mul_p_n() {
assert_eq!(P * N, N);
}
#[test]
fn mul_p_p() {
assert_eq!(P * P, P);
}
#[test]
fn inv_propagates_left() {
assert_eq!(INV * P, INV);
}
#[test]
fn inv_propagates_right() {
assert_eq!(P * INV, INV);
}
#[test]
fn inv_times_z() {
assert_eq!(INV * Z, INV);
}
#[test]
fn inv_times_inv() {
assert_eq!(INV * INV, INV);
}
#[test]
fn neg_n() {
assert_eq!(-N, P);
}
#[test]
fn neg_p() {
assert_eq!(-P, N);
}
#[test]
fn neg_z() {
assert_eq!(-Z, Z);
}
#[test]
fn neg_inv() {
assert_eq!(-INV, INV);
}
#[test]
fn double_neg_n() {
assert_eq!(-(-N), N);
}
#[test]
fn double_neg_p() {
assert_eq!(-(-P), P);
}
#[test]
fn z_is_zero_bits() {
assert_eq!(Z.bits(), 0b00);
}
#[test]
fn n_is_01_bits() {
assert_eq!(N.bits(), 0b01);
}
#[test]
fn p_is_10_bits() {
assert_eq!(P.bits(), 0b10);
}
#[test]
fn inv_is_11_bits() {
assert_eq!(INV.bits(), 0b11);
}
#[test]
fn z_is_zero_i8() {
assert_eq!(Z.to_i8(), Some(0));
}
#[test]
fn n_is_neg1_i8() {
assert_eq!(N.to_i8(), Some(-1));
}
#[test]
fn p_is_pos1_i8() {
assert_eq!(P.to_i8(), Some(1));
}
#[test]
fn inv_is_none_i8() {
assert_eq!(INV.to_i8(), None);
}
#[test]
fn p_is_multiplicative_identity() {
for t in [Z, N, P] {
assert_eq!(t * P, t);
assert_eq!(P * t, t);
}
}
#[test]
fn z_is_annihilator() {
for t in [Z, N, P] {
assert_eq!(t * Z, Z);
assert_eq!(Z * t, Z);
}
}
#[test]
fn commutativity() {
let trits = [Z, N, P, INV];
for &a in &trits {
for &b in &trits {
assert_eq!(a * b, b * a);
}
}
}
#[test]
fn associativity() {
let trits = [Z, N, P]; for &a in &trits {
for &b in &trits {
for &c in &trits {
assert_eq!((a * b) * c, a * (b * c));
}
}
}
}
#[test]
fn zero_bits_is_z() {
assert!(Z.is_zero());
assert!(!Z.is_inv());
assert_eq!(Z.bits(), 0b00); }
#[test]
fn inv_is_all_bits_set() {
assert_eq!(INV.bits(), 0b11);
assert_eq!(INV.bits() | Z.bits(), 0b11);
assert_eq!(INV.bits() | N.bits(), 0b11);
assert_eq!(INV.bits() | P.bits(), 0b11);
}
#[test]
fn clifford_basis_group_via_trit() {
assert_eq!(N * N, P); assert_eq!(Trit::from_i8(-1), N);
assert_eq!(Trit::from_i8(0), Z);
assert_eq!(Trit::from_i8(1), P);
}
}