Invariant Coordinates for Normal-Form Games Modulo Strategy Relabeling
type: NewsArticle
description: Researchers have identified 17 invariant coordinates for normal-form games under strategy relabeling, consisting of nine degree-2 and eight degree-3 polynomial generators. The discovery provides a complete algebraic description of game payoffs modulo row and column permutations, enabling systematic analysis of game symmetries. This invariant coordinate system allows researchers to classify and compare games independent of player labeling, with applications in game theory and evolutionary dynamics.
date published: 2026-05-17 04:00:00+00:00
date modified: 2026-05-29 16:39:19.483331+00:00
language: en
is accessible for free: true
article body: ``` python import numpy as np from itertools import combinations_with_replacement from sympy import symbols, expand rA, cA, dA, rB, cB, dB = symbols('rA cA dA rB cB dB') VARS = [rA, cA, dA, rB, cB, dB] def build_s2xs2(): """S_2 x S_2 acting on (rA, cA, dA, rB, cB, dB) by row/col sign flips.""" I = np.eye(6) s1 = np.diag([-1, 1, -1, -1, 1, -1.0]) # row swap s2 = np.diag([1, -1, -1, 1, -1, -1.0]) # col swap return [I, s1, s2, s1 @ s2] def reynolds_symbolic(exp_vec, group): total = 0 for g in group: gv = [sum(int(round(g[i, j])) * VARS[j] for j in range(6)) for i in range(6)] mono = 1 for k, e in enumerate(exp_vec): mono *= gv[k] ** e total += mono return expand(total / len(group)) def reynolds_numerical(exp_vec, group, points): n = len(points) vals = np.zeros(n) for g in group: for j in range(n): gpt = g @ points[j] v = 1.0 for k, e in enumerate(exp_vec): v *= gpt[k] ** e vals[j] += v return vals / len(group) def find_all_generators(group, n_pts=400, seed=42, max_deg=4): """Find generators up to Noether bound = |G| = 4.""" rng = np.random.default_rng(seed) pts = 2 * rng.standard_normal((n_pts, 6)) all_num, all_sym, all_deg = [], [], [] molien = {} for deg in range(max_deg + 1): mono_list = [] for combo in combinations_with_replacement(range(6), deg): exp = [0] * 6 for c in combo: exp[c] += 1 if tuple(exp) not in mono_list: mono_list.append(tuple(exp)) if not mono_list: mono_list = [(0,) * 6] prods = [] for i in range(len(all_num)): for j in range(i, len(all_num)): if all_deg[i] + all_deg[j] == deg: prods.append(all_num[i] * all_num[j]) for j in range(i, len(all_num)): for k in range(j, len(all_num)): if all_deg[i] + all_deg[j] + all_deg[k] == deg: prods.append(all_num[i] * all_num[j] * all_num[k]) prod_mat = np.array(prods) if prods else np.zeros((0, n_pts)) current = prod_mat.copy() if len(prods) > 0 else np.zeros((0, n_pts)) current_rank = np.linalg.matrix_rank(current, tol=1e-8) if current.shape[0] else 0 for m in mono_list: rv = reynolds_numerical(m, group, pts) t…
publisher: Web Pulse
keywords: ai-research
citation: CreativeWork