Skip to main content

bench_index2/
bench_index2.rs

1use std::time::Instant;
2use vampire_prover::{Function, Options, Predicate, Problem, ProofRes, Term, exists, forall};
3
4fn main() {
5    println!("Running index-2 subgroup normality proof benchmark");
6    println!(
7        "This will run the proof repeatedly to detect memory leaks or performance degradation\n"
8    );
9
10    const NUM_ITERATIONS: usize = 1000;
11    let mut times = Vec::with_capacity(NUM_ITERATIONS);
12
13    for i in 0..NUM_ITERATIONS {
14        waste_symbols(i);
15        unsafe {
16            vampire_sys::vampire_reset();
17        }
18
19        let start = Instant::now();
20        let result = run_proof(i);
21        let elapsed = start.elapsed();
22
23        times.push(elapsed.as_micros());
24
25        print!("Iteration {:3}: {:6} µs  ", i + 1, elapsed.as_micros());
26
27        match result {
28            ProofRes::Proved => print!("[PROVED]"),
29            ProofRes::Unprovable => print!("[UNPROVABLE]"),
30            ProofRes::Unknown(reason) => print!("[UNKNOWN: {:?}]", reason),
31        }
32
33        // Print running statistics every 10 iterations
34        if (i + 1) % 10 == 0 {
35            let avg = times.iter().sum::<u128>() / times.len() as u128;
36            let min = *times.iter().min().unwrap();
37            let max = *times.iter().max().unwrap();
38            println!("  (avg: {} µs, min: {} µs, max: {} µs)", avg, min, max);
39        } else {
40            println!();
41        }
42    }
43
44    // Final statistics
45    println!("\n{}", "=".repeat(60));
46    println!("Final Statistics:");
47    println!("{}", "=".repeat(60));
48
49    let avg = times.iter().sum::<u128>() / times.len() as u128;
50    let min = *times.iter().min().unwrap();
51    let max = *times.iter().max().unwrap();
52
53    // Calculate standard deviation
54    let variance = times
55        .iter()
56        .map(|&t| {
57            let diff = t as i128 - avg as i128;
58            (diff * diff) as u128
59        })
60        .sum::<u128>()
61        / times.len() as u128;
62    let std_dev = (variance as f64).sqrt();
63
64    println!("Total runs:        {}", NUM_ITERATIONS);
65    println!(
66        "Average time:      {} µs ({:.2} ms)",
67        avg,
68        avg as f64 / 1000.0
69    );
70    println!(
71        "Min time:          {} µs ({:.2} ms)",
72        min,
73        min as f64 / 1000.0
74    );
75    println!(
76        "Max time:          {} µs ({:.2} ms)",
77        max,
78        max as f64 / 1000.0
79    );
80    println!(
81        "Std deviation:     {:.2} µs ({:.2} ms)",
82        std_dev,
83        std_dev / 1000.0
84    );
85
86    // Check for performance degradation
87    let first_10_avg = times[0..10].iter().sum::<u128>() / 10;
88    let last_10_avg = times[times.len() - 10..].iter().sum::<u128>() / 10;
89    let degradation_percent =
90        ((last_10_avg as f64 - first_10_avg as f64) / first_10_avg as f64) * 100.0;
91
92    println!("\nFirst 10 avg:      {} µs", first_10_avg);
93    println!("Last 10 avg:       {} µs", last_10_avg);
94    println!("Degradation:       {:.2}%", degradation_percent);
95
96    if degradation_percent > 10.0 {
97        println!("\n⚠️  WARNING: Significant performance degradation detected!");
98        println!("   This may indicate a memory leak or resource accumulation.");
99    } else if degradation_percent < -10.0 {
100        println!("\n✓ Performance improved over time (likely JIT/cache effects)");
101    } else {
102        println!("\n✓ Performance stable across iterations");
103    }
104}
105
106fn waste_symbols(i: usize) {
107    for j in 0..1000 {
108        Function::new(&format!("p{i}-{j}"), 2);
109        Predicate::new(&format!("f{i}-{j}"), 2);
110    }
111}
112
113fn run_proof(i: usize) -> ProofRes {
114    // Prove that every subgroup of index 2 is normal.
115    let mult = Function::new(&format!("mult{i}"), 2);
116    let inv = Function::new(&format!("inv{i}"), 1);
117    let one = Function::constant(&format!("1{i}"));
118
119    // Helper to make multiplication more readable
120    let mul = |x: Term, y: Term| -> Term { mult.with(&[x, y]) };
121
122    // Group Axiom 1: Right identity - ∀x. x * 1 = x
123    let right_identity = forall(|x| mul(x, one).eq(x));
124
125    // Group Axiom 2: Right inverse - ∀x. x * inv(x) = 1
126    let right_inverse = forall(|x| {
127        let inv_x = inv.with(&[x]);
128        mul(x, inv_x).eq(one)
129    });
130
131    // Group Axiom 3: Associativity - ∀x,y,z. (x * y) * z = x * (y * z)
132    let associativity = forall(|x| forall(|y| forall(|z| mul(mul(x, y), z).eq(mul(x, mul(y, z))))));
133
134    // Describe the subgroup
135    let h = Predicate::new("h", 1);
136
137    // Any subgroup contains the identity
138    let h_ident = h.with(&[one]);
139
140    // And is closed under multiplication
141    let h_mul_closed =
142        forall(|x| forall(|y| (h.with(&[x]) & h.with(&[y])) >> h.with(&[mul(x, y)])));
143
144    // And is closed under inverse
145    let h_inv_closed = forall(|x| h.with(&[x]) >> h.with(&[inv.with(&[x])]));
146
147    // H specifically is of order 2
148    let h_index_2 = exists(|x| {
149        // an element not in H
150        let not_in_h = !h.with(&[x]);
151        // but everything is in H or x H
152        let class = forall(|y| h.with(&[y]) | h.with(&[mul(inv.with(&[x]), y)]));
153
154        not_in_h & class
155    });
156
157    // Conjecture: H is normal
158    let h_normal = forall(|x| {
159        let h_x = h.with(&[x]);
160        let conj_x = forall(|y| {
161            let y_inv = inv.with(&[y]);
162            h.with(&[mul(mul(y, x), y_inv)])
163        });
164        h_x.iff(conj_x)
165    });
166
167    Problem::new(Options::new())
168        .with_axiom(right_identity)
169        .with_axiom(right_inverse)
170        .with_axiom(associativity)
171        .with_axiom(h_ident)
172        .with_axiom(h_mul_closed)
173        .with_axiom(h_inv_closed)
174        .with_axiom(h_index_2)
175        .conjecture(h_normal)
176        .solve()
177}