#[allow(unused_imports)]
use crate::prelude::*;
use num_bigint::BigInt;
use num_rational::BigRational;
use num_traits::{One, Zero};
pub type Var = u32;
#[derive(Debug, Clone)]
pub struct AlgebraicNumber {
pub polynomial: Vec<BigRational>,
pub lower: BigRational,
pub upper: BigRational,
}
impl AlgebraicNumber {
pub fn new(polynomial: Vec<BigRational>, lower: BigRational, upper: BigRational) -> Self {
Self {
polynomial,
lower,
upper,
}
}
pub fn from_rational(value: BigRational) -> Self {
Self {
polynomial: vec![value.clone(), -BigRational::one()], lower: value.clone(),
upper: value,
}
}
pub fn is_rational(&self) -> bool {
self.lower == self.upper
}
pub fn as_rational(&self) -> Option<BigRational> {
if self.is_rational() {
Some(self.lower.clone())
} else {
None
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ThomEncoding {
pub signs: Vec<i8>,
}
impl ThomEncoding {
pub fn new(signs: Vec<i8>) -> Self {
Self { signs }
}
pub fn is_valid(&self) -> bool {
!self.signs.is_empty() && self.signs[0] == 0 }
}
#[derive(Debug, Clone)]
pub struct RealClosureAdvancedConfig {
pub enable_thom: bool,
pub enable_refinement: bool,
pub refinement_precision: BigRational,
}
impl Default for RealClosureAdvancedConfig {
fn default() -> Self {
Self {
enable_thom: true,
enable_refinement: true,
refinement_precision: BigRational::new(BigInt::from(1), BigInt::from(1000)),
}
}
}
#[derive(Debug, Clone, Default)]
pub struct RealClosureAdvancedStats {
pub sign_determinations: u64,
pub comparisons: u64,
pub thom_encodings: u64,
pub refinements: u64,
}
#[derive(Debug)]
pub struct RealClosureAdvanced {
config: RealClosureAdvancedConfig,
stats: RealClosureAdvancedStats,
}
impl RealClosureAdvanced {
pub fn new(config: RealClosureAdvancedConfig) -> Self {
Self {
config,
stats: RealClosureAdvancedStats::default(),
}
}
pub fn default_config() -> Self {
Self::new(RealClosureAdvancedConfig::default())
}
pub fn sign(&mut self, num: &AlgebraicNumber) -> i8 {
self.stats.sign_determinations += 1;
if num.lower > BigRational::zero() {
1
} else if num.upper < BigRational::zero() {
-1
} else if num.is_rational() && num.as_rational() == Some(BigRational::zero()) {
0
} else {
0
}
}
pub fn compare(&mut self, a: &AlgebraicNumber, b: &AlgebraicNumber) -> core::cmp::Ordering {
self.stats.comparisons += 1;
if a.upper < b.lower {
core::cmp::Ordering::Less
} else if a.lower > b.upper {
core::cmp::Ordering::Greater
} else {
core::cmp::Ordering::Equal
}
}
pub fn thom_encoding(&mut self, _num: &AlgebraicNumber) -> ThomEncoding {
if !self.config.enable_thom {
return ThomEncoding::new(vec![0]);
}
self.stats.thom_encodings += 1;
ThomEncoding::new(vec![0, 1, -1]) }
pub fn refine_interval(&mut self, num: &mut AlgebraicNumber) {
if !self.config.enable_refinement {
return;
}
let width = &num.upper - &num.lower;
if width <= self.config.refinement_precision {
return; }
self.stats.refinements += 1;
let mid = (&num.lower + &num.upper) / BigRational::from(BigInt::from(2));
num.upper = mid;
}
pub fn stats(&self) -> &RealClosureAdvancedStats {
&self.stats
}
pub fn reset_stats(&mut self) {
self.stats = RealClosureAdvancedStats::default();
}
}
impl Default for RealClosureAdvanced {
fn default() -> Self {
Self::default_config()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_engine_creation() {
let engine = RealClosureAdvanced::default_config();
assert_eq!(engine.stats().sign_determinations, 0);
}
#[test]
fn test_algebraic_from_rational() {
let num = AlgebraicNumber::from_rational(BigRational::from(BigInt::from(3)));
assert!(num.is_rational());
assert_eq!(num.as_rational(), Some(BigRational::from(BigInt::from(3))));
}
#[test]
fn test_sign_determination() {
let mut engine = RealClosureAdvanced::default_config();
let positive = AlgebraicNumber::from_rational(BigRational::from(BigInt::from(5)));
let negative = AlgebraicNumber::from_rational(BigRational::from(BigInt::from(-3)));
assert_eq!(engine.sign(&positive), 1);
assert_eq!(engine.sign(&negative), -1);
assert_eq!(engine.stats().sign_determinations, 2);
}
#[test]
fn test_compare() {
let mut engine = RealClosureAdvanced::default_config();
let a = AlgebraicNumber::from_rational(BigRational::from(BigInt::from(3)));
let b = AlgebraicNumber::from_rational(BigRational::from(BigInt::from(5)));
assert_eq!(engine.compare(&a, &b), core::cmp::Ordering::Less);
assert_eq!(engine.stats().comparisons, 1);
}
#[test]
fn test_thom_encoding() {
let mut engine = RealClosureAdvanced::default_config();
let num = AlgebraicNumber::from_rational(BigRational::zero());
let encoding = engine.thom_encoding(&num);
assert!(encoding.is_valid());
assert_eq!(engine.stats().thom_encodings, 1);
}
#[test]
fn test_refine_interval() {
let mut engine = RealClosureAdvanced::default_config();
let mut num = AlgebraicNumber::new(
vec![
BigRational::one(),
BigRational::zero(),
-BigRational::from(BigInt::from(2)),
], BigRational::one(),
BigRational::from(BigInt::from(2)),
);
let initial_width = &num.upper - &num.lower;
engine.refine_interval(&mut num);
let final_width = &num.upper - &num.lower;
assert!(final_width < initial_width);
assert_eq!(engine.stats().refinements, 1);
}
}