"""Exact score demonstration, not a cache benchmark or optimized LRFU engine."""
from fractions import Fraction
import json


def validate(history, now, q):
    if type(now) is not int or now < 0:
        raise ValueError("now must be a nonnegative integer request tick")
    if not isinstance(q, Fraction) or not Fraction(1, 2) <= q <= 1:
        raise ValueError("q must be an exact Fraction in [1/2, 1]")
    if any(type(t) is not int or t < 0 or t > now for t in history):
        raise ValueError("reference ticks must be integers between zero and now")
    if any(a >= b for a, b in zip(history, history[1:])):
        raise ValueError("reference ticks must be strictly increasing")


def direct_score(history, now, q):
    validate(history, now, q)
    return sum((q ** (now - t) for t in history), Fraction(0))


def lazy_score(history, now, q):
    validate(history, now, q)
    value, last = Fraction(0), 0
    for tick in history:
        value = 1 + q ** (tick - last) * value
        last = tick
    return value * q ** (now - last)


def example():
    histories = {"A": [1, 2, 3], "B": [4]}
    now = 5
    rows = []
    for q, label in [(Fraction(1), "lambda=0"),
                     (Fraction(3, 4), "lambda=log2(4/3)"),
                     (Fraction(1, 2), "lambda=1")]:
        scores = {key: direct_score(ts, now, q) for key, ts in histories.items()}
        stored = {key: direct_score(ts, ts[-1], q) for key, ts in histories.items()}
        rows.append({
            "q": str(q), "parameter": label,
            "scores_at_tick_5": {k: str(v) for k, v in scores.items()},
            "stored_at_last_reference": {k: str(v) for k, v in stored.items()},
            "victims": [k for k, v in scores.items() if v == min(scores.values())],
        })
    return {
        "schema_version": 1,
        "kind": "constructed exact arithmetic",
        "trace_before_miss": ["A", "A", "A", "B"],
        "incoming_request": {"tick": now, "block": "C"},
        "capacity_equal_size_blocks": 2,
        "initial_state": "empty; no eviction before tick 5",
        "clock_unit": "one tick per block reference, not seconds",
        "score": "sum(q ** (now - reference_tick)); q = 2 ** (-lambda)",
        "histories": histories,
        "rows": rows,
        "scope": "First victim only; no hit-rate, latency or device-performance claim.",
    }


if __name__ == "__main__":
    print(json.dumps(example(), indent=2))
