use crate::core::{FactorizationStateSpace, FactorizationError};
use crate::algebra::StateSpaceIdeal;
use std::collections::{HashMap, HashSet};
use std::fmt;
use thiserror::Error;
use serde::{Deserialize, Serialize};
#[derive(Error, Debug, Clone, PartialEq)]
pub enum SpectrumError {
#[error("Factorization error: {0}")]
FactorizationError(#[from] FactorizationError),
#[error("Invalid spectrum operation: {0}")]
InvalidOperation(String),
#[error("Prime {0} not in spectrum")]
PrimeNotInSpectrum(i64),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct SpectrumPoint {
prime: i64,
is_sign_prime: bool,
local_dimension: usize,
}
impl SpectrumPoint {
pub fn new(prime: i64) -> Result<Self, SpectrumError> {
if prime == -1 {
Ok(SpectrumPoint {
prime: -1,
is_sign_prime: true,
local_dimension: 1, })
} else if is_prime(prime) {
Ok(SpectrumPoint {
prime,
is_sign_prime: false,
local_dimension: 1,
})
} else {
Err(SpectrumError::InvalidOperation(
format!("{} is not a P-prime", prime)
))
}
}
pub fn prime(&self) -> i64 {
self.prime
}
pub fn is_sign_prime(&self) -> bool {
self.is_sign_prime
}
pub fn local_ring(&self, base: i64) -> LocalRing {
LocalRing::new(self.clone(), base)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PPrimeSpectrum {
points: HashMap<i64, SpectrumPoint>,
sign_prime_point: SpectrumPoint,
magnitude_primes: Vec<i64>,
}
impl PPrimeSpectrum {
pub fn new(prime_bound: u64) -> Self {
let mut points = HashMap::new();
let mut magnitude_primes = Vec::new();
let sign_prime_point = SpectrumPoint::new(-1).unwrap();
points.insert(-1, sign_prime_point.clone());
for p in 2..=prime_bound {
if is_prime(p as i64) {
let point = SpectrumPoint::new(p as i64).unwrap();
points.insert(p as i64, point);
magnitude_primes.push(p as i64);
}
}
PPrimeSpectrum {
points,
sign_prime_point,
magnitude_primes,
}
}
pub fn get_point(&self, prime: i64) -> Option<&SpectrumPoint> {
self.points.get(&prime)
}
pub fn sign_prime_point(&self) -> &SpectrumPoint {
&self.sign_prime_point
}
pub fn magnitude_prime_points(&self) -> Vec<&SpectrumPoint> {
self.magnitude_primes
.iter()
.filter_map(|&p| self.points.get(&p))
.collect()
}
pub fn all_points(&self) -> Vec<&SpectrumPoint> {
self.points.values().collect()
}
pub fn localize(
&self,
state_space: &FactorizationStateSpace,
prime: i64,
) -> Result<LocalizedStateSpace, SpectrumError> {
let point = self.get_point(prime)
.ok_or(SpectrumError::PrimeNotInSpectrum(prime))?;
Ok(LocalizedStateSpace::new(state_space.clone(), point.clone()))
}
pub fn morphism(
&self,
source: &FactorizationStateSpace,
target: &FactorizationStateSpace,
) -> Result<StateSpaceMorphism, SpectrumError> {
StateSpaceMorphism::new(source.clone(), target.clone())
}
pub fn is_local_isomorphism(
&self,
morphism: &StateSpaceMorphism,
prime: i64,
) -> Result<bool, SpectrumError> {
let _point = self.get_point(prime)
.ok_or(SpectrumError::PrimeNotInSpectrum(prime))?;
let local_source = self.localize(morphism.source(), prime)?;
let local_target = self.localize(morphism.target(), prime)?;
Ok(local_source.local_dimension() == local_target.local_dimension())
}
pub fn support(&self, state_space: &FactorizationStateSpace) -> HashSet<i64> {
let mut support = HashSet::new();
for factorization in state_space.factorizations() {
for (&prime, _) in factorization.factors() {
support.insert(prime);
}
}
support
}
pub fn have_disjoint_support(
&self,
space1: &FactorizationStateSpace,
space2: &FactorizationStateSpace,
) -> bool {
let support1 = self.support(space1);
let support2 = self.support(space2);
support1.is_disjoint(&support2)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LocalRing {
point: SpectrumPoint,
base: i64,
units: Vec<i64>,
}
impl LocalRing {
pub fn new(point: SpectrumPoint, base: i64) -> Self {
let mut units = Vec::new();
for i in 1..100 {
if i % point.prime().abs() != 0 {
units.push(i);
}
}
LocalRing { point, base, units }
}
pub fn is_unit(&self, element: i64) -> bool {
element % self.point.prime().abs() != 0
}
pub fn maximal_ideal(&self) -> StateSpaceIdeal {
StateSpaceIdeal::new(self.point.prime()).unwrap()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LocalizedStateSpace {
state_space: FactorizationStateSpace,
point: SpectrumPoint,
local_dimension: usize,
}
impl LocalizedStateSpace {
pub fn new(state_space: FactorizationStateSpace, point: SpectrumPoint) -> Self {
let mut local_dim = 0;
for factorization in state_space.factorizations() {
let has_prime = factorization.factors()
.iter()
.any(|(&p, _)| {
if point.is_sign_prime() {
p == -1 } else {
p.abs() == point.prime().abs() }
});
if has_prime {
local_dim += 1;
}
}
LocalizedStateSpace {
state_space,
point,
local_dimension: local_dim,
}
}
pub fn local_dimension(&self) -> usize {
self.local_dimension
}
pub fn point(&self) -> &SpectrumPoint {
&self.point
}
pub fn is_trivial(&self) -> bool {
self.local_dimension == 0
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StateSpaceMorphism {
source: FactorizationStateSpace,
target: FactorizationStateSpace,
morphism_type: MorphismType,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum MorphismType {
Inclusion,
Projection,
General,
}
impl StateSpaceMorphism {
pub fn new(
source: FactorizationStateSpace,
target: FactorizationStateSpace,
) -> Result<Self, SpectrumError> {
let source_val = source.value();
let target_val = target.value();
let morphism_type = if target_val % source_val == 0 {
MorphismType::Inclusion
} else if source_val % target_val == 0 {
MorphismType::Projection
} else {
MorphismType::General
};
Ok(StateSpaceMorphism {
source,
target,
morphism_type,
})
}
pub fn source(&self) -> &FactorizationStateSpace {
&self.source
}
pub fn target(&self) -> &FactorizationStateSpace {
&self.target
}
pub fn morphism_type(&self) -> MorphismType {
self.morphism_type
}
pub fn is_isomorphism(&self) -> bool {
self.source.size() == self.target.size() &&
self.source.value().abs() == self.target.value().abs()
}
}
fn is_prime(n: i64) -> bool {
if n < 2 {
return false;
}
for i in 2..=((n as f64).sqrt() as i64) {
if n % i == 0 {
return false;
}
}
true
}
impl fmt::Display for SpectrumPoint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_sign_prime {
write!(f, "Sign Prime (-1)")
} else {
write!(f, "Prime {}", self.prime)
}
}
}
impl fmt::Display for PPrimeSpectrum {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "P-Prime Spectrum Spec_P(ℤ):")?;
writeln!(f, " Sign Prime: {}", self.sign_prime_point)?;
writeln!(f, " Magnitude primes: {:?}", self.magnitude_primes)?;
writeln!(f, " Total points: {}", self.points.len())
}
}
impl fmt::Display for StateSpaceMorphism {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Morphism: S({}) → S({}) [{:?}]",
self.source.value(),
self.target.value(),
self.morphism_type
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_spectrum_point_creation() {
let sign_prime = SpectrumPoint::new(-1).unwrap();
assert!(sign_prime.is_sign_prime());
assert_eq!(sign_prime.prime(), -1);
let prime5 = SpectrumPoint::new(5).unwrap();
assert!(!prime5.is_sign_prime());
assert_eq!(prime5.prime(), 5);
assert!(SpectrumPoint::new(4).is_err());
}
#[test]
fn test_spectrum_creation() {
let spectrum = PPrimeSpectrum::new(20);
assert!(spectrum.get_point(-1).is_some());
assert!(spectrum.get_point(-1).unwrap().is_sign_prime());
assert!(spectrum.get_point(2).is_some());
assert!(spectrum.get_point(3).is_some());
assert!(spectrum.get_point(5).is_some());
assert!(spectrum.get_point(7).is_some());
assert!(spectrum.get_point(11).is_some());
assert!(spectrum.get_point(4).is_none());
assert!(spectrum.get_point(6).is_none());
}
#[test]
fn test_localization() {
let spectrum = PPrimeSpectrum::new(10);
let state_space = FactorizationStateSpace::new(6).unwrap();
let local2 = spectrum.localize(&state_space, 2).unwrap();
assert!(local2.local_dimension() > 0);
let local3 = spectrum.localize(&state_space, 3).unwrap();
assert!(local3.local_dimension() > 0);
let local5 = spectrum.localize(&state_space, 5).unwrap();
assert_eq!(local5.local_dimension(), 0); }
#[test]
fn test_support() {
let spectrum = PPrimeSpectrum::new(10);
let state_space6 = FactorizationStateSpace::new(6).unwrap();
let support6 = spectrum.support(&state_space6);
assert!(support6.contains(&2));
assert!(support6.contains(&3));
assert!(!support6.contains(&5));
let state_space_neg6 = FactorizationStateSpace::new(-6).unwrap();
let support_neg6 = spectrum.support(&state_space_neg6);
assert!(support_neg6.contains(&-1)); assert!(support_neg6.contains(&2));
assert!(support_neg6.contains(&3));
}
#[test]
fn test_morphisms() {
let spectrum = PPrimeSpectrum::new(10);
let s2 = FactorizationStateSpace::new(2).unwrap();
let s6 = FactorizationStateSpace::new(6).unwrap();
let morphism = spectrum.morphism(&s2, &s6).unwrap();
assert_eq!(morphism.morphism_type(), MorphismType::Inclusion);
let reverse = spectrum.morphism(&s6, &s2).unwrap();
assert_eq!(reverse.morphism_type(), MorphismType::Projection);
}
#[test]
fn test_local_isomorphism() {
let spectrum = PPrimeSpectrum::new(10);
let s6 = FactorizationStateSpace::new(6).unwrap();
let s_neg6 = FactorizationStateSpace::new(-6).unwrap();
let morphism = spectrum.morphism(&s6, &s_neg6).unwrap();
assert!(!spectrum.is_local_isomorphism(&morphism, 2).unwrap());
assert!(!spectrum.is_local_isomorphism(&morphism, 3).unwrap());
let _sign_iso = spectrum.is_local_isomorphism(&morphism, -1).unwrap();
}
#[test]
fn test_disjoint_support() {
let spectrum = PPrimeSpectrum::new(20);
let s5 = FactorizationStateSpace::new(5).unwrap();
let s6 = FactorizationStateSpace::new(6).unwrap();
let s10 = FactorizationStateSpace::new(10).unwrap();
assert!(spectrum.have_disjoint_support(&s5, &s6));
assert!(!spectrum.have_disjoint_support(&s5, &s10));
}
#[test]
fn test_local_ring() {
let prime3 = SpectrumPoint::new(3).unwrap();
let local_ring = prime3.local_ring(12);
assert!(local_ring.is_unit(1));
assert!(local_ring.is_unit(2));
assert!(!local_ring.is_unit(3));
assert!(local_ring.is_unit(4));
assert!(!local_ring.is_unit(6));
let maximal = local_ring.maximal_ideal();
assert_eq!(maximal.generator(), 3);
}
}