use crate::core::{FactorizationStateSpace, FactorizationError};
use std::fmt;
use std::collections::HashSet;
use thiserror::Error;
use serde::{Deserialize, Serialize};
#[derive(Error, Debug, Clone, PartialEq)]
pub enum StateSpaceIdealError {
#[error("Factorization error: {0}")]
FactorizationError(#[from] FactorizationError),
#[error("Invalid ideal operation: {0}")]
InvalidOperation(String),
#[error("Incompatible ideals for operation")]
IncompatibleIdeals,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StateSpaceIdeal {
generator: i64,
state_space: FactorizationStateSpace,
cached_elements: Option<Vec<i64>>,
}
impl StateSpaceIdeal {
pub fn new(n: i64) -> Result<Self, StateSpaceIdealError> {
let state_space = FactorizationStateSpace::new(n)?;
Ok(StateSpaceIdeal {
generator: n,
state_space,
cached_elements: None,
})
}
pub fn generator(&self) -> i64 {
self.generator
}
pub fn state_space(&self) -> &FactorizationStateSpace {
&self.state_space
}
pub fn dimension(&self) -> usize {
self.state_space.size()
}
pub fn is_quantum(&self) -> bool {
self.generator < 0
}
pub fn is_classical(&self) -> bool {
self.generator > 0
}
pub fn principal_ideal_elements(&mut self, bound: i64) -> &[i64] {
if self.cached_elements.is_none() || self.cached_elements.as_ref().unwrap().is_empty() {
let mut elements = Vec::new();
let n = self.generator;
if n == 0 {
elements.push(0);
} else {
let max_k = bound / n.abs();
for k in -max_k..=max_k {
if k != 0 {
elements.push(n * k);
}
}
elements.push(n); elements.sort_by_key(|&x| x.abs());
elements.dedup();
}
self.cached_elements = Some(elements);
}
self.cached_elements.as_ref().unwrap()
}
pub fn contains(&self, element: i64) -> bool {
if self.generator == 0 {
element == 0
} else {
element % self.generator == 0
}
}
pub fn multiply(&self, other: &StateSpaceIdeal) -> Result<StateSpaceIdeal, StateSpaceIdealError> {
let product_generator = self.generator.checked_mul(other.generator)
.ok_or_else(|| StateSpaceIdealError::InvalidOperation("Product overflow".to_string()))?;
StateSpaceIdeal::new(product_generator)
}
pub fn add(&self, other: &StateSpaceIdeal) -> Result<StateSpaceIdeal, StateSpaceIdealError> {
let gcd = gcd(self.generator.abs() as u64, other.generator.abs() as u64);
let sum_generator = if self.is_quantum() && other.is_quantum() {
-(gcd as i64)
} else {
gcd as i64
};
StateSpaceIdeal::new(sum_generator)
}
pub fn intersect(&self, other: &StateSpaceIdeal) -> Result<StateSpaceIdeal, StateSpaceIdealError> {
let lcm_val = lcm(self.generator.abs() as u64, other.generator.abs() as u64);
if lcm_val > i64::MAX as u64 {
return Err(StateSpaceIdealError::InvalidOperation("LCM overflow".to_string()));
}
let intersection_generator = if self.is_quantum() || other.is_quantum() {
-(lcm_val as i64)
} else {
lcm_val as i64
};
StateSpaceIdeal::new(intersection_generator)
}
pub fn contains_ideal(&self, other: &StateSpaceIdeal) -> bool {
if self.generator == 0 {
other.generator == 0
} else {
other.generator % self.generator == 0
}
}
pub fn quotient(&self, other: &StateSpaceIdeal) -> Result<QuotientStructure, StateSpaceIdealError> {
if !self.contains_ideal(other) {
return Err(StateSpaceIdealError::InvalidOperation(
"Divisor ideal must be contained in dividend ideal".to_string()
));
}
let quotient_size = if other.generator == 0 {
if self.generator == 0 {
1
} else {
usize::MAX }
} else {
(self.generator / other.generator).abs() as usize
};
Ok(QuotientStructure {
dividend: self.clone(),
divisor: other.clone(),
quotient_size,
})
}
pub fn radical(&self) -> Result<StateSpaceIdeal, StateSpaceIdealError> {
let factorizations = self.state_space.factorizations();
if factorizations.is_empty() {
return StateSpaceIdeal::new(self.generator);
}
let first_factorization = &factorizations[0];
let mut unique_primes = HashSet::new();
for (&prime, _) in first_factorization.factors() {
if prime != -1 { unique_primes.insert(prime.abs());
}
}
let radical_value: i64 = unique_primes.iter().product();
let radical_generator = if self.is_quantum() {
-radical_value
} else {
radical_value
};
StateSpaceIdeal::new(radical_generator)
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct QuotientStructure {
pub dividend: StateSpaceIdeal,
pub divisor: StateSpaceIdeal,
pub quotient_size: usize,
}
impl QuotientStructure {
pub fn is_finite(&self) -> bool {
self.quotient_size != usize::MAX
}
pub fn representatives(&self) -> Vec<i64> {
if !self.is_finite() {
return vec![];
}
let m = self.divisor.generator().abs();
if m == 0 {
return vec![0];
}
(0..m).collect()
}
}
fn gcd(a: u64, b: u64) -> u64 {
if b == 0 {
a
} else {
gcd(b, a % b)
}
}
fn lcm(a: u64, b: u64) -> u64 {
if a == 0 || b == 0 {
0
} else {
(a / gcd(a, b)) * b
}
}
impl fmt::Display for StateSpaceIdeal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "IS({}) = (({})⬝S({}))",
self.generator,
self.generator,
self.generator
)?;
if self.is_quantum() {
write!(f, " [Quantum]")?;
} else if self.is_classical() {
write!(f, " [Classical]")?;
}
write!(f, " dim={}", self.dimension())
}
}
impl fmt::Display for QuotientStructure {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "IS({})/IS({})",
self.dividend.generator(),
self.divisor.generator()
)?;
if self.is_finite() {
write!(f, " ≅ ℤ/{}", self.quotient_size)
} else {
write!(f, " ≅ ℤ")
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_state_space_ideal_creation() {
let ideal6 = StateSpaceIdeal::new(6).unwrap();
assert_eq!(ideal6.generator(), 6);
assert!(ideal6.is_classical());
assert!(!ideal6.is_quantum());
let ideal_neg6 = StateSpaceIdeal::new(-6).unwrap();
assert_eq!(ideal_neg6.generator(), -6);
assert!(!ideal_neg6.is_classical());
assert!(ideal_neg6.is_quantum());
}
#[test]
fn test_principal_ideal_elements() {
let mut ideal3 = StateSpaceIdeal::new(3).unwrap();
let elements = ideal3.principal_ideal_elements(20);
assert!(elements.contains(&3));
assert!(elements.contains(&6));
assert!(elements.contains(&9));
assert!(elements.contains(&-3));
assert!(elements.contains(&-6));
for &elem in elements {
assert_eq!(elem % 3, 0);
}
}
#[test]
fn test_ideal_multiplication() {
let ideal2 = StateSpaceIdeal::new(2).unwrap();
let ideal3 = StateSpaceIdeal::new(3).unwrap();
let product = ideal2.multiply(&ideal3).unwrap();
assert_eq!(product.generator(), 6);
let ideal_neg2 = StateSpaceIdeal::new(-2).unwrap();
let ideal_neg3 = StateSpaceIdeal::new(-3).unwrap();
let quantum_product = ideal_neg2.multiply(&ideal_neg3).unwrap();
assert_eq!(quantum_product.generator(), 6);
assert!(quantum_product.is_classical());
}
#[test]
fn test_ideal_addition() {
let ideal6 = StateSpaceIdeal::new(6).unwrap();
let ideal9 = StateSpaceIdeal::new(9).unwrap();
let sum = ideal6.add(&ideal9).unwrap();
assert_eq!(sum.generator(), 3);
let ideal_neg6 = StateSpaceIdeal::new(-6).unwrap();
let ideal_neg9 = StateSpaceIdeal::new(-9).unwrap();
let quantum_sum = ideal_neg6.add(&ideal_neg9).unwrap();
assert_eq!(quantum_sum.generator(), -3);
assert!(quantum_sum.is_quantum());
}
#[test]
fn test_ideal_intersection() {
let ideal4 = StateSpaceIdeal::new(4).unwrap();
let ideal6 = StateSpaceIdeal::new(6).unwrap();
let intersection = ideal4.intersect(&ideal6).unwrap();
assert_eq!(intersection.generator(), 12);
let ideal_neg4 = StateSpaceIdeal::new(-4).unwrap();
let mixed_intersection = ideal_neg4.intersect(&ideal6).unwrap();
assert_eq!(mixed_intersection.generator(), -12);
assert!(mixed_intersection.is_quantum());
}
#[test]
fn test_ideal_containment() {
let ideal2 = StateSpaceIdeal::new(2).unwrap();
let ideal6 = StateSpaceIdeal::new(6).unwrap();
let ideal9 = StateSpaceIdeal::new(9).unwrap();
assert!(ideal2.contains_ideal(&ideal6)); assert!(!ideal6.contains_ideal(&ideal2)); assert!(!ideal6.contains_ideal(&ideal9)); }
#[test]
fn test_quotient_structure() {
let ideal2 = StateSpaceIdeal::new(2).unwrap();
let ideal6 = StateSpaceIdeal::new(6).unwrap();
let quotient = ideal2.quotient(&ideal6).unwrap();
assert_eq!(quotient.quotient_size, 0); assert!(quotient.is_finite());
let reps = quotient.representatives();
assert_eq!(reps, vec![0, 1, 2, 3, 4, 5]);
}
#[test]
fn test_radical() {
let ideal12 = StateSpaceIdeal::new(12).unwrap(); let radical = ideal12.radical().unwrap();
assert_eq!(radical.generator(), 6);
let ideal_neg18 = StateSpaceIdeal::new(-18).unwrap(); let quantum_radical = ideal_neg18.radical().unwrap();
assert_eq!(quantum_radical.generator(), -6); assert!(quantum_radical.is_quantum());
}
#[test]
fn test_display() {
let ideal6 = StateSpaceIdeal::new(6).unwrap();
let display = format!("{}", ideal6);
assert!(display.contains("IS(6)"));
assert!(display.contains("[Classical]"));
assert!(display.contains("dim="));
let ideal_neg6 = StateSpaceIdeal::new(-6).unwrap();
let quantum_display = format!("{}", ideal_neg6);
assert!(quantum_display.contains("IS(-6)"));
assert!(quantum_display.contains("[Quantum]"));
}
}