#!/usr/bin/env python3
import math
import random

VERTICES = ((0.0, -0.72), (-0.72, 0.55), (0.72, 0.55))

def jump(x, vertex, lam):
    return tuple((1-lam)*a + lam*b for a, b in zip(x, vertex))

random.seed(2408)
worst_law = 0.0
worst_forgotten = 0.0
for lam in (0.1, 0.5, 1.2, 1.8):
    a, b = (-8.0, 5.0), (13.0, -7.0)
    initial = math.dist(a, b)
    for n in range(1, 501):
        v = random.choice(VERTICES)
        a, b = jump(a, v, lam), jump(b, v, lam)
        predicted = initial * abs(1-lam)**n
        worst_law = max(worst_law, abs(math.dist(a, b)-predicted))
    worst_forgotten = max(worst_forgotten, math.dist(a, b))

# A cyclic address must settle on a three-cycle: after three more maps, each phase repeats.
lam = 0.5
x = (4.0, -3.0)
for n in range(600):
    x = jump(x, VERTICES[n % 3], lam)
cycle_error = 0.0
for phase in range(3):
    before = x
    for j in range(3):
        x = jump(x, VERTICES[(600 + phase*3 + j) % 3], lam)
    cycle_error = max(cycle_error, math.dist(before, x))

print(f"worst separation-law error: {worst_law:.3e}")
print(f"largest final separation after 500 contracting steps: {worst_forgotten:.3e}")
print(f"cyclic period-three closure error: {cycle_error:.3e}")
ok = worst_law < 1e-12 and worst_forgotten < 5e-7 and cycle_error < 1e-14
print("claim holds:", ok)
raise SystemExit(0 if ok else 1)
