Skip to content

Commit c3ca167

Browse files
authored
feat: impl Sum and Product for Int and Real (#479)
* feat: impl Sum and Product for Int and Real * fmt * clippy * fmt with newer rustfmt * Avoid extra term in sums/products at the cost of some refcounting
1 parent 2d8aa70 commit c3ca167

File tree

2 files changed

+168
-0
lines changed

2 files changed

+168
-0
lines changed

z3/src/ops.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use crate::ast::{Bool, Float, IntoAst};
2+
use std::iter::Product;
3+
use std::iter::Sum;
24
use std::ops::{
35
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
46
Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Sub, SubAssign,
@@ -178,3 +180,42 @@ impl_trait_number_types!(BV, Mul::mul, [u8, i8, u16, i16, u32, i32, u64, i64]);
178180
impl_trait_number_types!(BV, BitXor::bitxor, [u8, i8, u16, i16, u32, i32, u64, i64]);
179181
impl_trait_number_types!(BV, BitAnd::bitand, [u8, i8, u16, i16, u32, i32, u64, i64]);
180182
impl_trait_number_types!(BV, BitOr::bitor, [u8, i8, u16, i16, u32, i32, u64, i64]);
183+
184+
macro_rules! integer_sum_product {
185+
($zero:expr, $one:expr, $($a:ty)*) => ($(
186+
impl Sum for $a {
187+
fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
188+
iter.reduce(
189+
|a, b| a + b,
190+
).unwrap_or($zero)
191+
}
192+
}
193+
194+
impl Product for $a {
195+
fn product<I: Iterator<Item=Self>>(iter: I) -> Self {
196+
iter.reduce(
197+
|a, b| a * b,
198+
).unwrap_or($one)
199+
}
200+
}
201+
202+
impl<'a> Sum<&'a $a> for $a {
203+
fn sum<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
204+
iter.cloned().reduce(
205+
|a, b| a + b,
206+
).unwrap_or($zero)
207+
}
208+
}
209+
210+
impl<'a> Product<&'a $a> for $a {
211+
fn product<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
212+
iter.cloned().reduce(
213+
|a, b| a * b,
214+
).unwrap_or($one)
215+
}
216+
}
217+
)*);
218+
}
219+
220+
integer_sum_product!(Int::from_u64(0), Int::from_u64(1), Int);
221+
integer_sum_product!(Real::from_rational(0, 1), Real::from_rational(1, 1), Real);

z3/tests/ops.rs

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,3 +427,130 @@ fn test_float_ops() {
427427
assert!(abs(t.mul_towards_zero(2.0).simplify().as_f64() - 20.0) < 0.1);
428428
assert!(abs(t.div_towards_zero(2.0).simplify().as_f64() - 5.0) < 0.1);
429429
}
430+
431+
#[test]
432+
fn test_int_sum() {
433+
// Test Sum for owned Int values
434+
let ints = vec![
435+
Int::from_i64(1),
436+
Int::from_i64(2),
437+
Int::from_i64(3),
438+
Int::from_i64(4),
439+
Int::from_i64(5),
440+
];
441+
let sum: Int = ints.into_iter().sum();
442+
assert_eq!(sum.simplify(), 15);
443+
444+
// Test Sum for borrowed Int values
445+
let ints = [Int::from_i64(10), Int::from_i64(20), Int::from_i64(30)];
446+
let sum: Int = ints.iter().sum();
447+
assert_eq!(sum.simplify(), 60);
448+
449+
// Test empty iterator gives zero
450+
let empty: Vec<Int> = vec![];
451+
let sum: Int = empty.into_iter().sum();
452+
assert_eq!(sum, 0);
453+
454+
// Test with symbolic values
455+
let x = Int::new_const("x");
456+
let y = Int::new_const("y");
457+
let z = Int::new_const("z");
458+
let ints = vec![x.clone(), y.clone(), z.clone()];
459+
let sum: Int = ints.into_iter().sum();
460+
// sum should be x + y + z
461+
let expected = &(&x + &y) + &z;
462+
assert_eq!(sum, expected);
463+
}
464+
465+
#[test]
466+
fn test_int_product() {
467+
// Test Product for owned Int values
468+
let ints = vec![Int::from_i64(2), Int::from_i64(3), Int::from_i64(4)];
469+
let product: Int = ints.into_iter().product();
470+
assert_eq!(product.simplify(), 24);
471+
472+
// Test Product for borrowed Int values
473+
let ints = [Int::from_i64(5), Int::from_i64(6)];
474+
let product: Int = ints.iter().product();
475+
assert_eq!(product.simplify(), 30);
476+
477+
// Test empty iterator gives one
478+
let empty: Vec<Int> = vec![];
479+
let product: Int = empty.into_iter().product();
480+
assert_eq!(product, 1);
481+
482+
// Test with symbolic values
483+
let x = Int::new_const("x");
484+
let y = Int::new_const("y");
485+
let ints = vec![x.clone(), y.clone(), Int::from_i64(2)];
486+
let product: Int = ints.into_iter().product();
487+
// product should be x * y * 2
488+
let expected = &(&x * &y) * 2;
489+
assert_eq!(product, expected);
490+
}
491+
492+
#[test]
493+
fn test_real_sum() {
494+
// Test Sum for owned Real values
495+
let reals = vec![
496+
Real::from_rational(1, 2),
497+
Real::from_rational(1, 3),
498+
Real::from_rational(1, 6),
499+
];
500+
let sum: Real = reals.into_iter().sum();
501+
assert_eq!(sum.simplify(), Real::from_rational(1, 1));
502+
503+
// Test Sum for borrowed Real values
504+
let reals = [
505+
Real::from_rational(2, 1),
506+
Real::from_rational(3, 1),
507+
Real::from_rational(5, 1),
508+
];
509+
let sum: Real = reals.iter().sum();
510+
assert_eq!(sum.simplify(), Real::from_rational(10, 1));
511+
512+
// Test empty iterator gives zero
513+
let empty: Vec<Real> = vec![];
514+
let sum: Real = empty.into_iter().sum();
515+
assert_eq!(sum, Real::from_rational(0, 1));
516+
517+
// Test with symbolic values
518+
let x = Real::new_const("x");
519+
let y = Real::new_const("y");
520+
let reals = vec![x.clone(), y.clone(), Real::from_rational(1, 1)];
521+
let sum: Real = reals.into_iter().sum();
522+
// sum should be x + y + 1
523+
let expected = &(&x + &y) + &Real::from_rational(1, 1);
524+
assert_eq!(sum, expected);
525+
}
526+
527+
#[test]
528+
fn test_real_product() {
529+
// Test Product for owned Real values
530+
let reals = vec![
531+
Real::from_rational(2, 1),
532+
Real::from_rational(3, 1),
533+
Real::from_rational(4, 1),
534+
];
535+
let product: Real = reals.into_iter().product();
536+
assert_eq!(product.simplify(), Real::from_rational(24, 1));
537+
538+
// Test Product for borrowed Real values
539+
let reals = [Real::from_rational(1, 2), Real::from_rational(1, 3)];
540+
let product: Real = reals.iter().product();
541+
assert_eq!(product.simplify(), Real::from_rational(1, 6));
542+
543+
// Test empty iterator gives one
544+
let empty: Vec<Real> = vec![];
545+
let product: Real = empty.into_iter().product();
546+
assert_eq!(product, Real::from_rational(1, 1));
547+
548+
// Test with symbolic values
549+
let x = Real::new_const("x");
550+
let y = Real::new_const("y");
551+
let reals = vec![x.clone(), y.clone(), Real::from_rational(2, 1)];
552+
let product: Real = reals.into_iter().product();
553+
// product should be x * y * 2
554+
let expected = &(&x * &y) * &Real::from_rational(2, 1);
555+
assert_eq!(product, expected);
556+
}

0 commit comments

Comments
 (0)