"""
Verification of Theorem 4.5.1 (Renewal Capture) and related results (Ch. IV).
Renewal Libertarianism, Part 1, Chapter IV, Modules 5 and 6.

Theorem 4.5.1 states: under the three conditions
  (i)   substrate payoff convexity in response intensity,
  (ii)  escalation-monotone authority gain after defeat,
  (iii) non-acquiescent optimal response,
and with sufficient defeat capacity, substrate's expected post-renewal
authority on the targeted dimension strictly exceeds its pre-renewal authority:
    E[A_d^{post}] > A_d^{pre}.

Verification approach: implement substrate's response-choice game numerically
with concrete payoff structures that satisfy the three conditions, compute the
substrate's optimal response r*, and confirm the theorem's prediction in the
high-defeat regime. Confirm separately that the theorem can fail in the
low-defeat regime (the "sufficient defeat capacity" condition is real, not
trivial). Then verify the comparative statics (Section 4.5.2), the renewal-
provocation result (Section 4.6), and the dimensional asymmetry (Section 4.6.3).

Run: uv run python renewal_capture.py
"""

import numpy as np

from _helpers import banner


def expected_authority(p_defeat, A_defeat, A_success):
    """E[A^post | response r] = p_defeat * A^defeat(r) + (1 - p_defeat) * A^success(r)"""
    return p_defeat * A_defeat + (1 - p_defeat) * A_success


def evaluate_response_game(responses, A_pre):
    """Compute net expected authority for each response option and return the
    optimal response together with a structured table of intermediate values.
    """
    rows = []
    for name, params in responses.items():
        p = params["p"]
        cost = params["cost"]
        if name == "Acquiescent":
            # Substrate accepts; no defeat outcome. A^post is the success value
            # for the substrate (i.e., what it retains after acquiescing).
            E_A = params["A_success"]
        else:
            E_A = expected_authority(p, params["A_defeat"], params["A_success"])
        net = E_A - cost
        rows.append({
            "name": name,
            "p": p,
            "A_defeat": params.get("A_defeat"),
            "A_success": params["A_success"],
            "cost": cost,
            "E_A": E_A,
            "net": net,
        })
    best = max(rows, key=lambda r: r["net"])
    return best, rows


def print_response_table(rows, header):
    print(f"\n  {header}")
    print("  " + "-" * 80)
    print(f"  {'Response':<14} {'p_def':<8} {'A^defeat':<10} {'A^succ':<10} "
          f"{'cost':<8} {'E[A]':<10} {'Net':<10}")
    print("  " + "-" * 80)
    for r in rows:
        A_def_str = f"{r['A_defeat']:.3f}" if r["A_defeat"] is not None else "   -   "
        print(f"  {r['name']:<14} {r['p']:<8.3f} {A_def_str:<10} "
              f"{r['A_success']:<10.3f} {r['cost']:<8.3f} {r['E_A']:<10.4f} {r['net']:<10.4f}")
    print("  " + "-" * 80)


def main():
    banner("Chapter IV Renewal Capture Theorem - numerical verification")

    # Pre-renewal authority on the targeted dimension (normalize to 1.0)
    A_pre = 1.0

    # -----------------------------------------------------------------
    # Build a response game that satisfies the three theorem conditions
    # and has sufficient defeat capacity (high-defeat regime).
    # -----------------------------------------------------------------
    responses_high_defeat = {
        # Acquiescent: substrate concedes. A^success here is the reduced
        # authority substrate retains after acquiescing.
        "Acquiescent":  {"p": 0.0,  "A_defeat": None, "A_success": 0.60, "cost": 0.00},
        # Mild: partial concessions while preserving most authority.
        # Modest defeat probability, modest gain on defeat.
        "Mild":         {"p": 0.40, "A_defeat": 1.10, "A_success": 0.70, "cost": 0.05},
        # Escalatory: political contestation. Higher defeat probability.
        "Escalatory":   {"p": 0.70, "A_defeat": 1.40, "A_success": 0.40, "cost": 0.15},
        # Violent: force suppression. Highest defeat probability, highest
        # consolidation gain on defeat, catastrophic loss on success.
        "Violent":      {"p": 0.90, "A_defeat": 1.90, "A_success": 0.10, "cost": 0.40},
    }

    best_hi, rows_hi = evaluate_response_game(responses_high_defeat, A_pre)
    print_response_table(rows_hi, "High-defeat regime")
    print(f"\n  Optimal response r* = {best_hi['name']}  (net payoff {best_hi['net']:.4f})")

    # -----------------------------------------------------------------
    # Verify the three theorem conditions on the high-defeat regime
    # -----------------------------------------------------------------
    banner("Theorem 4.5.1: verify conditions (i)-(iii) and the conclusion")

    # (iii) Non-acquiescent optimal response
    assert best_hi["name"] != "Acquiescent", (
        "Optimal response should not be acquiescent in high-defeat regime")
    print(f"\n  (iii) Optimal response is non-acquiescent: r* = {best_hi['name']}  [pass]")

    # (ii) Escalation-monotone authority gain: A^defeat strictly increases with intensity
    intensity_order = ["Mild", "Escalatory", "Violent"]
    A_defeats = [responses_high_defeat[r]["A_defeat"] for r in intensity_order]
    assert all(A_defeats[i] < A_defeats[i + 1] for i in range(len(A_defeats) - 1)), (
        "A^defeat should be strictly increasing in response intensity")
    print(f"  (ii) A^defeat strictly increasing in intensity: "
          f"M={A_defeats[0]} < E={A_defeats[1]} < V={A_defeats[2]}  [pass]")

    # (i) Payoff convexity in response intensity:
    #     A^defeat at intermediate intensity should not exceed the linear
    #     interpolation between extremes (i.e., the function does not bow up
    #     more on the inside than at the endpoints).
    linear_midpoint = (A_defeats[0] + A_defeats[2]) / 2
    assert A_defeats[1] <= linear_midpoint + 1e-10, (
        f"A^defeat should be convex in intensity; got {A_defeats[1]} > "
        f"linear midpoint {linear_midpoint}")
    print(f"  (i)  Convexity: A^defeat(E)={A_defeats[1]} <= "
          f"(A^defeat(M)+A^defeat(V))/2={linear_midpoint}  [pass]")

    # Theorem's conclusion: E[A^post | r*] > A^pre
    E_post_optimal = best_hi["E_A"]
    print(f"\n  Conclusion: E[A^post | r* = {best_hi['name']}] = {E_post_optimal:.4f}, "
          f"A^pre = {A_pre:.4f}")
    print(f"  Difference E[A^post] - A^pre = {E_post_optimal - A_pre:+.4f}")
    assert E_post_optimal > A_pre, (
        "Theorem 4.5.1 conclusion E[A^post] > A^pre failed in high-defeat regime")
    print(f"  [pass] E[A^post] > A^pre under the three theorem conditions")

    # -----------------------------------------------------------------
    # Boundary: the conclusion can fail when defeat capacity is insufficient
    # -----------------------------------------------------------------
    banner("Theorem 4.5.1 boundary: conclusion fails when defeat capacity is too low")

    # Same payoff structure but lower defeat probabilities throughout
    responses_low_defeat = {
        "Acquiescent":  {"p": 0.00, "A_defeat": None, "A_success": 0.60, "cost": 0.00},
        "Mild":         {"p": 0.10, "A_defeat": 1.10, "A_success": 0.70, "cost": 0.05},
        "Escalatory":   {"p": 0.20, "A_defeat": 1.40, "A_success": 0.40, "cost": 0.15},
        "Violent":      {"p": 0.30, "A_defeat": 1.90, "A_success": 0.10, "cost": 0.40},
    }
    best_lo, rows_lo = evaluate_response_game(responses_low_defeat, A_pre)
    print_response_table(rows_lo, "Low-defeat regime")
    print(f"\n  Optimal response r* = {best_lo['name']}  (net payoff {best_lo['net']:.4f})")
    print(f"  E[A^post | r* = {best_lo['name']}] = {best_lo['E_A']:.4f},  A^pre = {A_pre:.4f}")
    print(f"  Difference E[A^post] - A^pre = {best_lo['E_A'] - A_pre:+.4f}")
    assert best_lo["E_A"] < A_pre, (
        "In low-defeat regime, optimal E[A^post] should fall below A^pre, "
        "showing the 'sufficient defeat capacity' condition is non-trivial")
    print(f"  [pass] Theorem conclusion fails when defeat capacity is insufficient")
    print(f"         (the 'sufficient defeat capacity' condition is real, not trivial)")

    # -----------------------------------------------------------------
    # Comparative statics (Section 4.5.2)
    # Higher defeat probability strengthens renewal capture
    # -----------------------------------------------------------------
    banner("Comparative statics (Section 4.5.2): E[A^post] - A^pre is increasing in p")

    # Sweep defeat probability for the Escalatory response holding everything else fixed
    A_defeat_fixed = 1.40
    A_success_fixed = 0.40
    cost_fixed = 0.15
    print(f"\n  Escalatory response, A^defeat={A_defeat_fixed}, A^success={A_success_fixed}, cost={cost_fixed}")
    print(f"  {'p_defeat':<12} {'E[A^post]':<12} {'Net':<12} {'E[A^post] - A^pre':<20}")
    print("  " + "-" * 56)

    prev_diff = -float("inf")
    for p in np.linspace(0.1, 0.95, 18):
        E_A = expected_authority(p, A_defeat_fixed, A_success_fixed)
        net = E_A - cost_fixed
        diff = E_A - A_pre
        print(f"  {p:<12.4f} {E_A:<12.4f} {net:<12.4f} {diff:<+20.4f}")
        assert diff > prev_diff, "E[A^post] - A^pre should be monotonically increasing in p"
        prev_diff = diff
    print(f"\n  [pass] E[A^post] - A^pre strictly increasing in defeat probability p")

    # Identify the threshold p above which renewal capture occurs
    # Solve E[A^post] = A^pre: p * A^defeat + (1-p) * A^success = A^pre
    #                          p * (A^defeat - A^success) = A^pre - A^success
    #                          p = (A^pre - A^success) / (A^defeat - A^success)
    p_threshold = (A_pre - A_success_fixed) / (A_defeat_fixed - A_success_fixed)
    print(f"\n  Renewal-capture threshold p* on Escalatory response:")
    print(f"      p* = (A^pre - A^success) / (A^defeat - A^success) = {p_threshold:.4f}")
    # Verify: E[A^post] crosses A^pre exactly at p_threshold
    E_at_thresh = expected_authority(p_threshold, A_defeat_fixed, A_success_fixed)
    assert abs(E_at_thresh - A_pre) < 1e-12, "Threshold formula does not produce E[A^post] = A^pre"
    print(f"  [pass] E[A^post](p=p*) = {E_at_thresh:.6f} = A^pre (threshold formula verified)")

    # -----------------------------------------------------------------
    # Section 4.6: Renewal Provocation result
    # Substrate has positive marginal incentive to provoke renewal attempts
    # when E[A^post] - A^pre > 0 (which is the high-defeat regime's
    # conclusion of Theorem 4.5.1).
    # -----------------------------------------------------------------
    banner("Renewal Provocation (Section 4.6): incentive to provoke when defeat capacity is high")

    provocation_payoff = best_hi["E_A"] - A_pre
    print(f"\n  In the high-defeat regime, substrate's optimal r* gives:")
    print(f"      E[A^post] - A^pre = {provocation_payoff:+.4f}")
    print(f"  This positive expected gain is substrate's incentive to provoke the renewal")
    print(f"  attempt, since the attempted renewal raises substrate's expected authority")
    print(f"  above the pre-renewal level.")
    assert provocation_payoff > 0, "Provocation incentive should be positive in high-defeat regime"
    print(f"  [pass] positive marginal incentive to provoke confirmed (E[A^post] > A^pre)")

    print(f"\n  In the low-defeat regime, substrate's optimal r* gives:")
    print(f"      E[A^post] - A^pre = {best_lo['E_A'] - A_pre:+.4f}")
    print(f"  The expected outcome is below A^pre, so substrate has no provocation")
    print(f"  incentive in this regime; the renewal attempt would lower substrate")
    print(f"  authority in expectation.")
    assert best_lo["E_A"] - A_pre < 0
    print(f"  [pass] no provocation incentive in low-defeat regime")

    # -----------------------------------------------------------------
    # Section 4.6.3: Dimensional asymmetry
    # The same polity can have substrate choosing different responses on
    # different dimensions, if defeat capacity differs across dimensions.
    # -----------------------------------------------------------------
    banner("Dimensional asymmetry (Section 4.6.3): different optimal responses across dimensions")

    # Suppose substrate has high defeat capacity on extraction (tau) but low
    # on scope (S) -- a polity with strong central authority over revenue but
    # weak central authority over jurisdictional boundaries.
    print(f"\n  Polity with high defeat capacity on tau, low on S, both targeted simultaneously.")
    best_tau, _ = evaluate_response_game(responses_high_defeat, A_pre)
    best_S,   _ = evaluate_response_game(responses_low_defeat,  A_pre)
    print(f"      Optimal response on tau-targeting attempt: {best_tau['name']}  "
          f"(E[A^post]={best_tau['E_A']:.4f})")
    print(f"      Optimal response on S-targeting attempt:   {best_S['name']}  "
          f"(E[A^post]={best_S['E_A']:.4f})")
    assert best_tau["name"] != best_S["name"], (
        "Substrate should choose different responses across dimensions when defeat capacities differ")
    print(f"  [pass] substrate rationally picks different responses across dimensions")
    print(f"         (escalation on tau where defeat capacity is high; less-costly")
    print(f"          response on S where defeat capacity is low)")

    banner("All verifications passed")
    print("""
  Result: Chapter IV's Renewal Capture Theorem and adjacent results verified
  on concrete numerical instances of substrate's response-choice game.

    - Theorem 4.5.1: conditions (i) convexity, (ii) escalation-monotone
      authority gain, (iii) non-acquiescent optimum all hold by construction;
      conclusion E[A^post] > A^pre verified in the high-defeat regime.
    - Boundary: in the low-defeat regime, the optimal response still satisfies
      condition (iii) but the conclusion fails, confirming the 'sufficient
      defeat capacity' qualifier is non-trivial.
    - Section 4.5.2 comparative statics: E[A^post] - A^pre is strictly
      monotonically increasing in defeat probability p.
    - Renewal-capture threshold formula
        p* = (A^pre - A^success) / (A^defeat - A^success)
      verified by direct substitution.
    - Section 4.6 Renewal Provocation: positive marginal incentive to provoke
      confirmed in the high-defeat regime; absent in the low-defeat regime.
    - Section 4.6.3 Dimensional asymmetry: substrate rationally picks
      different optimal responses across dimensions with different defeat
      capacities, even in the same polity at the same time.
""")


if __name__ == "__main__":
    main()
