java-topology/defects/lean4/bench/bench-lean4-0002.py

56 lines
1.7 KiB
Python

#!/usr/bin/env python3
# bench-lean4-0002.py
# lean4-0002: expr_set inductive type check std::find vs set
#
# Models the Lean4 isInductiveApp / inductive type-check defect where
# result argument deduplication uses std::find (O(N) per call) inside
# an O(K) outer loop, giving O(K*N) total. Fixed version builds a set
# once (O(N)) and queries it O(1) per item.
import sys
import time
def bench_defective(k, n):
"""Model std::find pattern: O(K*N) total."""
to_check = list(range(k))
result_args = list(range(n, 2 * n)) # disjoint so scan goes full length
t0 = time.perf_counter()
for arg in to_check:
_ = arg in result_args # O(N) linear scan
return time.perf_counter() - t0
def bench_fixed(k, n):
"""Model set lookup pattern: O(N) build + O(K) queries = O(N+K)."""
to_check = list(range(k))
result_args = list(range(n, 2 * n))
result_set = set(result_args) # O(N) build -- done once
t0 = time.perf_counter()
for arg in to_check:
_ = arg in result_set # O(1)
return time.perf_counter() - t0
TRIALS = 3
SIZES = [100, 500, 1000]
def run():
lines = []
header = "=== lean4-0002: inductive type check std::find vs set ==="
print(header)
lines.append(header)
for sz in SIZES:
k, n = sz, sz
def_times = [bench_defective(k, n) for _ in range(TRIALS)]
fix_times = [bench_fixed(k, n) for _ in range(TRIALS)]
d_ms = min(def_times) * 1000
f_ms = min(fix_times) * 1000
speedup = d_ms / f_ms if f_ms > 0 else float('inf')
line = f"K=N={sz:<4}: defective={d_ms:.3f}ms fixed={f_ms:.3f}ms speedup={speedup:.1f}x"
print(line)
lines.append(line)
sys.stdout.flush()
return lines
if __name__ == "__main__":
run()