#!/bin/bash
# friction.sh — Head-to-head benchmark: CPython vs lumbda-Python vs lumbda-C
#
# Usage: bash friction.sh

set -e
cd "$(dirname "$0")"

echo "═══════════════════════════════════════════════════════════════"
echo "Friction Benchmark: CPython vs lumbda-Python vs lumbda-C"
echo "═══════════════════════════════════════════════════════════════"
echo

# Build C version
make -C c all -s 2>/dev/null

# ── fib(35) iterative ──────────────────────────────────────────
echo ">>> fib(35) iterative"

printf "  CPython:             "
python3 -c "
import time
def fib(n):
    a, b = 0, 1
    for _ in range(n): a, b = b, a+b
    return a
t=time.perf_counter(); r=fib(35); print(f'{(time.perf_counter()-t)*1000:.3f}ms  result={r}')
"

printf "  lumbda-Python: "
python3 -c "
import time; from lumbda import *
g=make_global_env(); [leval(e,g) for e in read_all(PRELUDE)]
[leval(e,g) for e in read_all('(auto-compile! #t)')]
[leval(e,g) for e in read_all('(define (fib n) (let loop ((a 0) (b 1) (i 0)) (if (= i n) a (loop b (+ a b) (+ i 1)))))')]
t=time.perf_counter(); r=[leval(e,g) for e in read_all('(fib 35)')][-1]
print(f'{(time.perf_counter()-t)*1000:.3f}ms  result={r}')
"

printf "  lumbda-C:      "
/usr/bin/time -f "%e s" ./c/lumbda -e '(define (fib n) (let loop ((a 0) (b 1) (i 0)) (if (= i n) a (loop b (+ a b) (+ i 1))))) (display (fib 35)) (newline)' 2>&1

echo

# ── fib(20) tree-recursive ──────────────────────────────────────
echo ">>> fib(20) tree-recursive"

printf "  CPython:             "
python3 -c "
import time
def fib(n):
    if n <= 1: return n
    return fib(n-1) + fib(n-2)
t=time.perf_counter(); r=fib(20); print(f'{(time.perf_counter()-t)*1000:.3f}ms  result={r}')
"

printf "  lumbda-Python: "
python3 -c "
import time,sys; sys.setrecursionlimit(50000); from lumbda import *
g=make_global_env(); [leval(e,g) for e in read_all(PRELUDE)]
[leval(e,g) for e in read_all('(auto-compile! #t)')]
[leval(e,g) for e in read_all('(define (fib n) (if (<= n 1) n (+ (fib (- n 1)) (fib (- n 2)))))')]
t=time.perf_counter(); r=[leval(e,g) for e in read_all('(fib 20)')][-1]
print(f'{(time.perf_counter()-t)*1000:.3f}ms  result={r}')
"

printf "  lumbda-C:      "
/usr/bin/time -f "%e s" ./c/lumbda -e '(define (fib n) (if (<= n 1) n (+ (fib (- n 1)) (fib (- n 2))))) (display (fib 20)) (newline)' 2>&1

echo

# ── ackermann(3,4) ──────────────────────────────────────────────
echo ">>> ackermann(3,4)"

printf "  CPython:             "
python3 -c "
import time,sys; sys.setrecursionlimit(50000)
def ack(m,n):
    if m==0: return n+1
    if n==0: return ack(m-1,1)
    return ack(m-1, ack(m, n-1))
t=time.perf_counter(); r=ack(3,4); print(f'{(time.perf_counter()-t)*1000:.3f}ms  result={r}')
"

printf "  lumbda-Python: "
python3 -c "
import time,sys; sys.setrecursionlimit(50000); from lumbda import *
g=make_global_env(); [leval(e,g) for e in read_all(PRELUDE)]
[leval(e,g) for e in read_all('(auto-compile! #t)')]
[leval(e,g) for e in read_all('(define (ack m n) (cond ((= m 0) (+ n 1)) ((= n 0) (ack (- m 1) 1)) (else (ack (- m 1) (ack m (- n 1))))))')]
t=time.perf_counter(); r=[leval(e,g) for e in read_all('(ack 3 4)')][-1]
print(f'{(time.perf_counter()-t)*1000:.3f}ms  result={r}')
"

printf "  lumbda-C:      "
/usr/bin/time -f "%e s" ./c/lumbda -e '(define (ack m n) (cond ((= m 0) (+ n 1)) ((= n 0) (ack (- m 1) 1)) (else (ack (- m 1) (ack m (- n 1)))))) (display (ack 3 4)) (newline)' 2>&1

echo

# ── sum-to(50000) tail-recursive ────────────────────────────────
echo ">>> sum-to(50000) tail-recursive"

printf "  CPython:             "
python3 -c "
import time
def s(n):
    acc=0
    while n>0: acc+=n; n-=1
    return acc
t=time.perf_counter(); r=s(50000); print(f'{(time.perf_counter()-t)*1000:.3f}ms  result={r}')
"

printf "  lumbda-Python: "
python3 -c "
import time; from lumbda import *
g=make_global_env(); [leval(e,g) for e in read_all(PRELUDE)]
[leval(e,g) for e in read_all('(auto-compile! #t)')]
[leval(e,g) for e in read_all('(define (sum-to n) (let loop ((i n) (acc 0)) (if (= i 0) acc (loop (- i 1) (+ acc i)))))')]
t=time.perf_counter(); r=[leval(e,g) for e in read_all('(sum-to 50000)')][-1]
print(f'{(time.perf_counter()-t)*1000:.3f}ms  result={r}')
"

printf "  lumbda-C:      "
/usr/bin/time -f "%e s" ./c/lumbda -e '(define (sum-to n) (let loop ((i n) (acc 0)) (if (= i 0) acc (loop (- i 1) (+ acc i))))) (display (sum-to 50000)) (newline)' 2>&1

echo
echo "═══════════════════════════════════════════════════════════════"
