1-- Equilibria as a predicate, and the deviation reading of Nash's condition:2-- when the payoffs of a player's pure strategies do not depend on that3-- player's own mixture, no change of their mixture improves their expected4-- payoff at an equilibrium5-- Part of Cumulus, the Grace17 mathematics library.6-- Copyright (c) 2026 Grant Passmore.7-- Released under the Apache License 2.0. See LICENSE in the repository root.8-- Authors: Grant Passmore910module Grace.Cumulus.GameTheory.NashDeviation11import NashEquilibrium1213-- A profile in the product where no pure strategy beats its owner's14-- expected payoff.15predicate Equilibrium (n m blk V x : Set) :=16 x ∈ simplexProduct(n, m, blk) ∧∀ i ∈ n, (V(i)(x):R) ≤ (expectedPayoff(n, blk, V, blk(i))(x):R)1718theorem Equilibrium.profile (n m blk V x : Set)19requires equilibrium : Equilibrium(n, m, blk, V, x)20shows x ∈ simplexProduct(n, m, blk)21proof22exact equilibrium.left2324theorem Equilibrium.pure (n m blk V x i : Set)25requires equilibrium : Equilibrium(n, m, blk, V, x)26requires hi : i ∈ n27shows (V(i)(x):R) ≤ (expectedPayoff(n, blk, V, blk(i))(x):R)28proof29exact equilibrium.right with hi3031theorem nash.exists_equilibrium (n : Nat) (m blk V a : Set)32requires blkFunction : blk : n → m33requires ha : a ∈ simplexProduct(n, m, blk)34requires family : ∀ i ∈ n, CubeFunctionContinuous(V(i), n)35shows∃ x, Equilibrium(n, m, blk, V, x)36proof37obtain⟨x, hx, pure⟩:= nash.equilibrium with blkFunction, ha, family38witness x39exact⟨hx, pure⟩4041-- If z agrees with the equilibrium x except on player p's block, and the42-- payoffs of p's pure strategies are the same at z and at x, then p's43-- expected payoff at z is at most their expected payoff at x.44theorem nash.no_deviation (n : Nat) (m blk V x z p : Set)45requires blkFunction : blk : n → m46requires family : ∀ i ∈ n, CubeFunctionContinuous(V(i), n)47requires equilibrium : Equilibrium(n, m, blk, V, x)48requires hz : z ∈ simplexProduct(n, m, blk)49requires hp : p ∈ m50requires independent : ∀ i ∈ n, blk(i) = p → V(i)(z) = V(i)(x)51shows (expectedPayoff(n, blk, V, p)(z):R) ≤ (expectedPayoff(n, blk, V, p)(x):R)52proof53have hx := Equilibrium.profile with equilibrium54have xCube := simplexProduct.cube with hx55have zCube := simplexProduct.cube with hz56have zFunction := unitCube.point with zCube57have functions := payoffFamily.functions with family58have payoffs := assembledPoint.function with functions, zCube59have maskedP := maskedPoint.sequence at n, blockSet(n, blk, p), assembledPoint(n, payoffFamily(n, V), z) with payoffs60have maskedZ := maskedPoint.sequence at n, blockSet(n, blk, p), z with zFunction61have payoffReal := expectedPayoff.real at n, blk, V, p, x with family, xCube62have constantU := constantSequence.sequence at expectedPayoff(n, blk, V, p)(x)63have scaledZ := mulSequence.sequence with constantU, maskedZ64have bounded : ∀ k ∈ ℕ, k < n → (maskedPoint(n, blockSet(n, blk, p), assembledPoint(n, payoffFamily(n, V), z))(k):R) ≤ (mulSequence(constantSequence(expectedPayoff(n, blk, V, p)(x)), maskedPoint(n, blockSet(n, blk, p), z))(k):R)65intros k hk hkn66have kNat : Nat(k) bytypecheck67have hkIn : k ∈ n byexact membership.of_Less with hkn68have zReal := RealSequence.value at maskedPoint(n, blockSet(n, blk, p), z), k with maskedZ69have uReal := RealSequence.value at constantSequence(expectedPayoff(n, blk, V, p)(x)), k with constantU70have uValue := constantSequence.value at expectedPayoff(n, blk, V, p)(x), k71have scaledValue := mulSequence.value with constantU, maskedZ, uReal, zReal72rw [scaledValue, uValue]73have alternatives : k ∈ blockSet(n, blk, p) ∨¬k ∈ blockSet(n, blk, p) bytauto74cases alternatives with inBlock | outside75 . have parts := blockSet.membership.forward with inBlock76have block := parts.right77have pSame := maskedPoint.on_block with payoffs, hkIn, inBlock78have zSame := maskedPoint.on_block with zFunction, hkIn, inBlock79have pValue := assembledPoint.value with functions, zCube, hkIn80have term := payoffFamily.term with family, zCube, hkIn81have same := independent with hkIn, block82have pure := Equilibrium.pure with equilibrium, hkIn83rw block at pure84have zInterval := unitCube.coordinate with zCube, hkIn85obtain⟨zkReal, zLower, zUpper⟩:= closedInterval.membership.forward with zInterval86have vReal := CubeFunction.value with (CubeFunctionContinuous.function with (family with hkIn)), xCube87have step := realLe.mul_left_of_nonnegative with pure, zLower88have commute := realMulValue.commutative at z(k), expectedPayoff(n, blk, V, p)(x)89rw commute at step90 rwa [pSame, zSame, pValue, term, same]91 . have pSame := maskedPoint.off_block with payoffs, hkIn, outside92have zSame := maskedPoint.off_block with zFunction, hkIn, outside93have zero := realMulValue.zero_right at expectedPayoff(n, blk, V, p)(x)94rw [pSame, zSame, zero]95exact realLe.reflexive96have monotone := realPartialSum.monotone_prefix with maskedP, scaledZ, bounded97have scale := realPartialSum.scale at maskedPoint(n, blockSet(n, blk, p), z), n, expectedPayoff(n, blk, V, p)(x) with maskedZ98have zValue := expectedPayoff.value at n, blk, V, p, z with family, zCube99have sumOne := simplexProduct.block_sum with hz, hp100have blockValue := blockSum.definition at n, blk, p101have cubeValue := sumCube.value at n, blockSet(n, blk, p), z with zCube102rw blockValue at cubeValue103rw cubeValue at sumOne104have one := realMulValue.one_right at expectedPayoff(n, blk, V, p)(x)105rw [scale, sumOne, one] at monotone106 rwa zValue107