Skip to main content

oxiz_math/
lib.rs

1//! # oxiz-math
2//!
3//! Mathematical foundations for the OxiZ SMT solver.
4//!
5//! This crate provides Pure Rust implementations of mathematical algorithms
6//! required for SMT solving, including:
7//!
8//! ## Linear Arithmetic
9//! - **Simplex**: Dual simplex algorithm for linear programming (LRA theory)
10//! - **Interior Point**: Primal-dual interior point method for large-scale LP
11//! - **Matrix**: Dense and sparse matrix operations with Gaussian elimination
12//! - **Interval**: Interval arithmetic for bound propagation
13//! - **Delta Rational**: Support for strict inequalities in simplex
14//! - **BLAS**: High-performance BLAS operations for large-scale LP (1000+ variables)
15//!
16//! ## Non-Linear Arithmetic
17//! - **Polynomial**: Multivariate polynomial arithmetic with GCD and factorization
18//! - **Rational Function**: Arithmetic on quotients of polynomials (p/q operations)
19//! - **Gröbner**: Gröbner basis computation (Buchberger, F4, and F5 algorithms)
20//! - **Real Closure**: Algebraic number representation and root isolation
21//! - **Hilbert**: Hilbert basis computation for integer cones
22//!
23//! ## Decision Diagrams
24//! - **BDD**: Reduced Ordered Binary Decision Diagrams
25//! - **ZDD**: Zero-suppressed BDDs for sparse set representation
26//! - **ADD**: Algebraic Decision Diagrams for rational-valued functions
27//!
28//! ## Numerical Utilities
29//! - **Rational**: Arbitrary precision rational arithmetic utilities
30//! - **MPFR**: Arbitrary precision floating-point arithmetic (MPFR-like)
31//!
32//! # Examples
33//!
34//! ## Polynomial Arithmetic
35//!
36//! ```
37//! use oxiz_math::polynomial::{Polynomial, Var};
38//!
39//! // Create polynomial for variable x (index 0)
40//! let x: Var = 0;
41//!
42//! // Create polynomial representing just x
43//! let p = Polynomial::from_var(x);
44//!
45//! // Compute x * x = x^2
46//! let p_squared = p.clone() * p.clone();
47//! ```
48//!
49//! ## BDD Operations
50//!
51//! ```
52//! use oxiz_math::bdd::BddManager;
53//!
54//! let mut mgr = BddManager::new();
55//!
56//! // Create variables (VarId is u32)
57//! let x = mgr.variable(0);
58//! let y = mgr.variable(1);
59//!
60//! // Compute x AND y
61//! let and_xy = mgr.and(x, y);
62//!
63//! // Compute x OR y
64//! let or_xy = mgr.or(x, y);
65//! ```
66//!
67//! ## BLAS Operations
68//!
69//! ```
70//! use oxiz_math::blas::{ddot, dgemv, Transpose};
71//!
72//! // Vector dot product
73//! let x = vec![1.0, 2.0, 3.0];
74//! let y = vec![4.0, 5.0, 6.0];
75//! let dot = ddot(&x, &y);
76//! assert_eq!(dot, 32.0);
77//! ```
78//!
79//! ## Arbitrary Precision Floats
80//!
81//! ```
82//! use oxiz_math::mpfr::{ArbitraryFloat, Precision, RoundingMode};
83//!
84//! let prec = Precision::new(128);
85//! let a = ArbitraryFloat::from_f64(3.14159, prec);
86//! let b = ArbitraryFloat::from_f64(2.71828, prec);
87//! let sum = a.add(&b, RoundingMode::RoundNearest);
88//! ```
89
90#![cfg_attr(not(feature = "std"), no_std)]
91#![warn(missing_docs)]
92
93#[cfg(not(feature = "std"))]
94extern crate alloc;
95
96mod prelude;
97
98pub mod algebraic;
99pub mod bdd;
100#[cfg(feature = "std")]
101pub mod blas;
102#[cfg(feature = "std")]
103pub mod blas_ops;
104pub mod delta_rational;
105pub mod fast_rational;
106pub mod grobner;
107pub mod hilbert;
108pub mod interior_point;
109pub mod interval;
110pub mod lp;
111pub mod lp_core;
112pub mod matrix;
113#[cfg(feature = "std")]
114pub mod mpfr;
115pub mod polynomial;
116pub mod rational;
117pub mod rational_function;
118pub mod realclosure;
119pub mod realclosure_advanced;
120#[cfg(feature = "std")]
121pub mod simd;
122pub mod simplex;
123pub mod simplex_parametric;
124pub mod simplex_solver;
125
126pub use simplex_solver::{
127    Constraint as SimplexConstraint, ConstraintKind, SimplexError, SimplexSolver, SolveResult,
128    SolveStatus,
129};
130
131#[cfg(test)]
132mod integration_tests {
133    use super::*;
134    use num_bigint::BigInt;
135    use num_rational::BigRational;
136
137    fn rat(n: i64) -> BigRational {
138        BigRational::from_integer(BigInt::from(n))
139    }
140
141    #[test]
142    fn test_grobner_with_root_isolation() {
143        // Integration test: Use Gröbner basis to simplify, then isolate roots
144        // System: x^2 - 2 = 0, y - x = 0
145        // Should reduce to y^2 - 2 = 0
146
147        let x_squared_minus_2 = polynomial::Polynomial::from_coeffs_int(&[
148            (1, &[(0, 2)]), // x^2
149            (-2, &[]),      // -2
150        ]);
151
152        let y_minus_x = polynomial::Polynomial::from_coeffs_int(&[
153            (1, &[(1, 1)]),  // y
154            (-1, &[(0, 1)]), // -x
155        ]);
156
157        let gb = grobner::grobner_basis(&[x_squared_minus_2.clone(), y_minus_x]);
158
159        // The Gröbner basis should contain polynomials
160        assert!(!gb.is_empty());
161
162        // One of the polynomials should be univariate
163        let has_univariate = gb.iter().any(|p| p.is_univariate());
164        assert!(has_univariate || gb.len() == 1);
165    }
166
167    #[test]
168    fn test_nra_solver_with_algebraic_numbers() {
169        // Integration test: NRA solver with algebraic number evaluation
170        // Solve x^2 - 2 = 0
171
172        let mut solver = grobner::NraSolver::new();
173
174        let x_squared_minus_2 = polynomial::Polynomial::from_coeffs_int(&[
175            (1, &[(0, 2)]), // x^2
176            (-2, &[]),      // -2
177        ]);
178
179        solver.add_equality(x_squared_minus_2.clone());
180
181        // Should be satisfiable
182        assert_eq!(solver.check_sat(), grobner::SatResult::Sat);
183
184        // Create algebraic number for sqrt(2)
185        // AlgebraicNumber::new(poly, var, lower, upper)
186        let sqrt_2 = realclosure::AlgebraicNumber::new(
187            x_squared_minus_2,
188            0, // variable 0
189            rat(1),
190            rat(2),
191        );
192
193        // Algebraic number should be valid
194        let _ = sqrt_2;
195    }
196
197    #[test]
198    fn test_interval_with_polynomial_bounds() {
199        // Integration test: Use interval arithmetic with polynomial evaluation
200        // Evaluate x^2 over [1, 2] should give [1, 4]
201
202        let x_squared = polynomial::Polynomial::from_coeffs_int(&[(1, &[(0, 2)])]);
203
204        // Evaluate at x = 1
205        let mut assignment1 = crate::prelude::FxHashMap::default();
206        assignment1.insert(0, rat(1));
207        let val1 = x_squared.eval(&assignment1);
208        assert_eq!(val1, rat(1));
209
210        // Evaluate at x = 2
211        let mut assignment2 = crate::prelude::FxHashMap::default();
212        assignment2.insert(0, rat(2));
213        let val2 = x_squared.eval(&assignment2);
214        assert_eq!(val2, rat(4));
215
216        // Create interval [1, 4]
217        let interval = interval::Interval::closed(rat(1), rat(4));
218        assert!(interval.contains(&val1));
219        assert!(interval.contains(&val2));
220    }
221
222    #[test]
223    fn test_delta_rationals_ordering() {
224        // Integration test: Delta rationals for strict inequalities
225        let delta_zero = delta_rational::DeltaRational::from_rational(rat(0));
226        let delta_small = delta_rational::DeltaRational::new(rat(0), 1); // delta_coeff is i64
227
228        // 0 + delta > 0
229        assert!(delta_small > delta_zero);
230
231        // Delta rationals maintain ordering
232        let delta_one = delta_rational::DeltaRational::from_rational(rat(1));
233        assert!(delta_one > delta_small);
234    }
235
236    #[test]
237    fn test_matrix_operations() {
238        // Integration test: Matrix operations (used in F4 algorithm)
239        use matrix::Matrix;
240        use num_rational::Rational64;
241
242        // Create a simple 2x2 matrix
243        let m = Matrix::from_vec(
244            2,
245            2,
246            vec![
247                Rational64::new(2, 1),
248                Rational64::new(1, 1),
249                Rational64::new(1, 1),
250                Rational64::new(1, 1),
251            ],
252        );
253
254        // Check matrix values
255        assert_eq!(m.get(0, 0), Rational64::new(2, 1));
256        assert_eq!(m.get(0, 1), Rational64::new(1, 1));
257    }
258
259    #[test]
260    fn test_polynomial_factorization_with_grobner() {
261        // Integration test: Factorization helps with Gröbner basis computation
262        // x^2 - y^2 can be analyzed via Gröbner basis
263
264        let x_sq_minus_y_sq = polynomial::Polynomial::from_coeffs_int(&[
265            (1, &[(0, 2)]),  // x^2
266            (-1, &[(1, 2)]), // -y^2
267        ]);
268
269        // Compute Gröbner basis of {x^2 - y^2}
270        let gb = grobner::grobner_basis(&[x_sq_minus_y_sq]);
271
272        assert!(!gb.is_empty());
273    }
274
275    #[test]
276    fn test_real_closure_root_isolation_integration() {
277        // Integration test: Real closure and root isolation
278        // Find roots of x^3 - 2 = 0
279
280        let poly = polynomial::Polynomial::from_coeffs_int(&[
281            (1, &[(0, 3)]), // x^3
282            (-2, &[]),      // -2
283        ]);
284
285        // Isolate roots (for variable 0)
286        let roots = poly.isolate_roots(0);
287
288        // Should find at least one real root (cube root of 2)
289        assert!(!roots.is_empty());
290    }
291
292    #[test]
293    fn test_polynomial_gcd_univariate() {
294        // Integration test: GCD computation for univariate polynomials
295        // gcd(x^2 - 1, x - 1) = x - 1
296
297        let p1 = polynomial::Polynomial::from_coeffs_int(&[
298            (1, &[(0, 2)]), // x^2
299            (-1, &[]),      // -1
300        ]);
301
302        let p2 = polynomial::Polynomial::from_coeffs_int(&[
303            (1, &[(0, 1)]), // x
304            (-1, &[]),      // -1
305        ]);
306
307        let gcd = p1.gcd_univariate(&p2);
308
309        // GCD should be x - 1 (or a scalar multiple)
310        assert_eq!(gcd.total_degree(), 1);
311    }
312}