use noether::{
AdditiveAbelianGroup, AdditiveGroup, AdditiveMagma, AdditiveMonoid, AdditiveSemigroup,
AssociativeAddition, AssociativeMultiplication, CommutativeAddition, CommutativeMultiplication,
MultiplicativeAbelianGroup, MultiplicativeGroup, MultiplicativeMagma, MultiplicativeMonoid,
MultiplicativeSemigroup,
};
use num_traits::{One, Zero};
use std::fmt::{Debug, Display};
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CyclicGroup<const N: u32> {
value: u32,
}
impl<const N: u32> CyclicGroup<N> {
pub fn new(value: u32) -> Self {
assert!(N > 0, "Group order must be positive");
Self { value: value % N }
}
pub fn value(&self) -> u32 {
self.value
}
pub fn order() -> u32 {
N
}
pub fn additive_order(&self) -> u32 {
if self.value == 0 {
return 1; }
let mut result = *self;
let mut order = 1;
while result.value != 0 {
result += Self::new(self.value);
order += 1;
}
order
}
pub fn multiplicative_order(&self) -> u32 {
if self.value == 0 {
return u32::MAX; }
let mut result = *self;
let mut order = 1;
while result.value != 1 {
result *= Self::new(self.value);
order += 1;
if order > N {
return u32::MAX; }
}
order
}
pub fn add_n(&self, n: u32) -> Self {
if n == 0 {
return Self::zero();
}
Self::new((self.value * n) % N)
}
pub fn pow(&self, n: u32) -> Self {
if n == 0 {
return Self::one();
}
let mut result = Self::one();
let mut base = *self;
let mut exp = n;
while exp > 0 {
if exp % 2 == 1 {
result *= base;
}
base = base * base;
exp /= 2;
}
result
}
pub fn is_generator(&self) -> bool {
if N == 1 {
return self.value == 0; }
if self.value == 0 {
return false;
}
let mut a = self.value;
let mut b = N;
while b != 0 {
let t = b;
b = a % b;
a = t;
}
a == 1
}
pub fn generators() -> Vec<Self> {
let mut result = Vec::new();
for i in 0..N {
let elem = Self::new(i);
if elem.is_generator() {
result.push(elem);
}
}
result
}
pub fn all_elements() -> Vec<Self> {
(0..N).map(Self::new).collect()
}
pub fn verify_group_axioms<T>()
where
T: AdditiveAbelianGroup + MultiplicativeAbelianGroup,
{
}
}
impl<const N: u32> Add for CyclicGroup<N> {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self::new(self.value + rhs.value)
}
}
impl<const N: u32> AddAssign for CyclicGroup<N> {
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs;
}
}
impl<const N: u32> Neg for CyclicGroup<N> {
type Output = Self;
fn neg(self) -> Self::Output {
if self.value == 0 {
self } else {
Self::new(N - self.value)
}
}
}
impl<const N: u32> Sub for CyclicGroup<N> {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
self + (-rhs)
}
}
impl<const N: u32> SubAssign for CyclicGroup<N> {
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}
impl<const N: u32> Zero for CyclicGroup<N> {
fn zero() -> Self {
Self::new(0)
}
fn is_zero(&self) -> bool {
self.value == 0
}
}
impl<const N: u32> Mul for CyclicGroup<N> {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self::new((self.value * rhs.value) % N)
}
}
impl<const N: u32> MulAssign for CyclicGroup<N> {
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs;
}
}
impl<const N: u32> One for CyclicGroup<N> {
fn one() -> Self {
Self::new(1)
}
}
impl<const N: u32> Div for CyclicGroup<N> {
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
if rhs.value == 0 {
panic!("Division by zero in cyclic group");
}
for i in 1..N {
if (rhs.value * i) % N == 1 {
return Self::new((self.value * i) % N);
}
}
panic!("No multiplicative inverse exists");
}
}
impl<const N: u32> DivAssign for CyclicGroup<N> {
fn div_assign(&mut self, rhs: Self) {
*self = *self / rhs;
}
}
impl<const N: u32> Display for CyclicGroup<N> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.value)
}
}
impl<const N: u32> num_traits::Inv for CyclicGroup<N> {
type Output = Self;
fn inv(self) -> Self::Output {
if self.value == 0 {
panic!("Attempt to invert zero in cyclic group");
}
for i in 1..N {
if (self.value * i) % N == 1 {
return Self::new(i);
}
}
panic!("No multiplicative inverse exists");
}
}
impl<const N: u32> CommutativeAddition for CyclicGroup<N> {}
impl<const N: u32> AssociativeAddition for CyclicGroup<N> {}
impl<const N: u32> CommutativeMultiplication for CyclicGroup<N> {}
impl<const N: u32> AssociativeMultiplication for CyclicGroup<N> {}
fn _static_assert_additive_group_traits<const N: u32>()
where
CyclicGroup<N>:
AdditiveMagma + AdditiveSemigroup + AdditiveMonoid + AdditiveGroup + AdditiveAbelianGroup,
{
}
fn _static_assert_multiplicative_group_traits<const N: u32>()
where
CyclicGroup<N>: MultiplicativeMagma
+ MultiplicativeSemigroup
+ MultiplicativeMonoid
+ MultiplicativeGroup
+ MultiplicativeAbelianGroup,
{
}
fn print_addition_table<const N: u32>() {
println!("\nAddition Table for Cyclic Group of Order {}:", N);
print!("+ | ");
for i in 0..N {
print!("{:2} ", i);
}
println!("\n--+-{}", "-".repeat(3 * N as usize));
for i in 0..N {
print!("{:1} | ", i);
for j in 0..N {
let sum = CyclicGroup::<N>::new(i) + CyclicGroup::<N>::new(j);
print!("{:2} ", sum.value());
}
println!();
}
}
fn print_multiplication_table<const N: u32>() {
println!("\nMultiplication Table for Cyclic Group of Order {}:", N);
print!("× | ");
for i in 0..N {
print!("{:2} ", i);
}
println!("\n--+-{}", "-".repeat(3 * N as usize));
for i in 0..N {
print!("{:1} | ", i);
for j in 0..N {
let product = CyclicGroup::<N>::new(i) * CyclicGroup::<N>::new(j);
print!("{:2} ", product.value());
}
println!();
}
}
fn demonstrate_cyclic_group<const N: u32>() {
println!("=== Cyclic Group of Order {} Example ===", N);
CyclicGroup::<N>::verify_group_axioms::<CyclicGroup<N>>();
let elements = CyclicGroup::<N>::all_elements();
print!("Group elements: ");
for (i, e) in elements.iter().enumerate() {
if i > 0 {
print!(", ");
}
print!("{}", e);
}
println!();
let generators = CyclicGroup::<N>::generators();
print!("Generators: ");
for (i, g) in generators.iter().enumerate() {
if i > 0 {
print!(", ");
}
print!("{}", g);
}
println!();
println!("\nDemonstrating group operations:");
let zero = CyclicGroup::<N>::zero();
println!("Additive identity: {}", zero);
let one = CyclicGroup::<N>::one();
println!("Multiplicative identity: {}", one);
if !generators.is_empty() {
let g = generators[0];
println!("\nUsing generator g = {}:", g);
println!("Additive subgroup generated by g:");
for i in 0..N {
print!("{}g = {}, ", i, g.add_n(i));
}
println!();
let neg_g = -g;
println!("Additive inverse: -g = {}", neg_g);
println!("g + (-g) = {}", g + neg_g);
if g.value != 0 {
println!("\nMultiplicative subgroup generated by g:");
for i in 0..N {
print!("g^{} = {}, ", i, g.pow(i));
}
println!();
let inv_g = one / g;
println!("Multiplicative inverse: 1/g = {}", inv_g);
println!("g * (1/g) = {}", g * inv_g);
}
}
print_addition_table::<N>();
print_multiplication_table::<N>();
}
fn main() {
demonstrate_cyclic_group::<5>();
println!("\n\n");
demonstrate_cyclic_group::<6>();
println!("\n\n=== Applications of Cyclic Groups ===");
println!("1. Cryptography: Cyclic groups underpin many cryptographic protocols");
println!("2. Error-correcting codes: Cyclic codes are based on cyclic groups");
println!("3. Number theory: The multiplicative group (Z/nZ)* is important in number theory");
println!("4. Group theory: Cyclic groups are the building blocks of abelian groups");
println!("\nNoether's trait system for algebraic structures makes it possible to write");
println!("generic algorithms that work with any type satisfying group or ring axioms.");
println!("This example shows how cyclic groups implement both additive and multiplicative");
println!("group structures, allowing them to be used with Noether's group traits.");
}