use num_bigint::BigInt;
use std::fmt;
use thiserror::Error;
pub const SIGN_PRIME: i64 = -1;
#[derive(Error, Debug, Clone, PartialEq)]
pub enum SignPrimeError {
#[error("Invalid operation: {0}")]
InvalidOperation(String),
#[error("Sign Prime power must be non-negative")]
InvalidPower,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SignPrime;
impl SignPrime {
pub fn new() -> Self {
SignPrime
}
pub fn value(&self) -> i64 {
SIGN_PRIME
}
pub fn is_sign_prime(&self) -> bool {
true
}
pub fn power(&self, n: u32) -> Result<i64, SignPrimeError> {
if n % 2 == 0 {
Ok(1)
} else {
Ok(-1)
}
}
pub fn multiply(&self, other: i64) -> i64 {
-other
}
pub fn multiply_bigint(&self, other: &BigInt) -> BigInt {
-other
}
pub fn divides(&self, n: i64) -> bool {
n != 0
}
pub fn divide(&self, n: i64) -> Result<i64, SignPrimeError> {
if n == 0 {
Err(SignPrimeError::InvalidOperation("Division by zero".to_string()))
} else {
Ok(-n)
}
}
}
impl Default for SignPrime {
fn default() -> Self {
Self::new()
}
}
impl fmt::Display for SignPrime {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "-1")
}
}
pub fn is_sign_prime(n: i64) -> bool {
n == SIGN_PRIME
}
pub fn is_sign_prime_bigint(n: &BigInt) -> bool {
n == &BigInt::from(SIGN_PRIME)
}
impl std::ops::Mul<i64> for SignPrime {
type Output = i64;
fn mul(self, rhs: i64) -> Self::Output {
self.multiply(rhs)
}
}
impl std::ops::Mul<SignPrime> for i64 {
type Output = i64;
fn mul(self, rhs: SignPrime) -> Self::Output {
rhs.multiply(self)
}
}
impl std::ops::Mul<SignPrime> for SignPrime {
type Output = i64;
fn mul(self, _rhs: SignPrime) -> Self::Output {
1 }
}
impl SignPrime {
pub fn apply_to_factorization(&self, factors: &[i64]) -> Vec<i64> {
let mut result = vec![SIGN_PRIME];
result.extend_from_slice(factors);
result
}
pub fn absorb_from_factorization(&self, factors: &[i64]) -> Vec<i64> {
let mut result = Vec::new();
let mut has_sign_prime = false;
for &factor in factors {
if factor == SIGN_PRIME {
has_sign_prime = true;
} else {
result.push(factor);
}
}
if has_sign_prime && !result.is_empty() {
result[0] = -result[0];
}
result
}
pub fn count_in_factorization(&self, factors: &[i64]) -> usize {
factors.iter().filter(|&&f| f == SIGN_PRIME).count()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sign_prime_creation() {
let sp = SignPrime::new();
assert_eq!(sp.value(), -1);
assert!(sp.is_sign_prime());
}
#[test]
fn test_sign_prime_power() {
let sp = SignPrime::new();
assert_eq!(sp.power(0).unwrap(), 1);
assert_eq!(sp.power(1).unwrap(), -1);
assert_eq!(sp.power(2).unwrap(), 1);
assert_eq!(sp.power(3).unwrap(), -1);
assert_eq!(sp.power(100).unwrap(), 1);
assert_eq!(sp.power(101).unwrap(), -1);
}
#[test]
fn test_sign_prime_multiplication() {
let sp = SignPrime::new();
assert_eq!(sp.multiply(5), -5);
assert_eq!(sp.multiply(-3), 3);
assert_eq!(sp.multiply(0), 0);
}
#[test]
fn test_sign_prime_division() {
let sp = SignPrime::new();
assert_eq!(sp.divide(6).unwrap(), -6);
assert_eq!(sp.divide(-8).unwrap(), 8);
assert!(sp.divide(0).is_err());
}
#[test]
fn test_sign_prime_divisibility() {
let sp = SignPrime::new();
assert!(sp.divides(42));
assert!(sp.divides(-17));
assert!(!sp.divides(0));
}
#[test]
fn test_is_sign_prime() {
assert!(is_sign_prime(-1));
assert!(!is_sign_prime(1));
assert!(!is_sign_prime(-2));
assert!(!is_sign_prime(0));
}
#[test]
fn test_sign_prime_operators() {
let sp = SignPrime::new();
assert_eq!(sp * 5, -5);
assert_eq!(5 * sp, -5);
assert_eq!(sp * sp, 1);
}
#[test]
fn test_factorization_operations() {
let sp = SignPrime::new();
let factors = vec![2, 3, 5];
let with_sign = sp.apply_to_factorization(&factors);
assert_eq!(with_sign, vec![-1, 2, 3, 5]);
let factors_with_sign = vec![-1, 2, 3, 5];
let absorbed = sp.absorb_from_factorization(&factors_with_sign);
assert_eq!(absorbed, vec![-2, 3, 5]);
assert_eq!(sp.count_in_factorization(&vec![-1, 2, -1, 3]), 2);
assert_eq!(sp.count_in_factorization(&vec![2, 3, 5]), 0);
}
#[test]
fn test_bigint_operations() {
let sp = SignPrime::new();
let big_num = BigInt::from(12345);
let result = sp.multiply_bigint(&big_num);
assert_eq!(result, BigInt::from(-12345));
assert!(is_sign_prime_bigint(&BigInt::from(-1)));
assert!(!is_sign_prime_bigint(&BigInt::from(1)));
}
#[test]
fn test_display() {
let sp = SignPrime::new();
assert_eq!(format!("{}", sp), "-1");
}
}