diff --git a/game_theory/__init__.py b/game_theory/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/game_theory/best_response_dynamics.py b/game_theory/best_response_dynamics.py new file mode 100644 index 000000000000..a3fb04468c70 --- /dev/null +++ b/game_theory/best_response_dynamics.py @@ -0,0 +1,30 @@ +import numpy as np + + +def best_response_dynamics(payoff_matrix_a, payoff_matrix_b, iterations=10): + n = payoff_matrix_a.shape[0] + m = payoff_matrix_a.shape[1] + + # Initialize strategies + strategy_a = np.ones(n) / n + strategy_b = np.ones(m) / m + + for _ in range(iterations): + # Update strategy A + response_a = np.argmax(payoff_matrix_a @ strategy_b) + strategy_a = np.zeros(n) + strategy_a[response_a] = 1 + + # Update strategy B + response_b = np.argmax(payoff_matrix_b.T @ strategy_a) + strategy_b = np.zeros(m) + strategy_b[response_b] = 1 + + return strategy_a, strategy_b + + +# Example usage +payoff_a = np.array([[3, 0], [5, 1]]) +payoff_b = np.array([[2, 4], [0, 2]]) +strategies = best_response_dynamics(payoff_a, payoff_b) +print("Final strategies:", strategies) diff --git a/game_theory/fictitious_play.py b/game_theory/fictitious_play.py new file mode 100644 index 000000000000..906bc2debcc9 --- /dev/null +++ b/game_theory/fictitious_play.py @@ -0,0 +1,36 @@ +import numpy as np + + +def fictitious_play(payoff_matrix_a, payoff_matrix_b, iterations=100): + n = payoff_matrix_a.shape[0] + m = payoff_matrix_a.shape[1] + + # Initialize counts and strategies + counts_a = np.zeros(n) + counts_b = np.zeros(m) + strategy_a = np.ones(n) / n + strategy_b = np.ones(m) / m + + for _ in range(iterations): + # Update counts + counts_a += strategy_a + counts_b += strategy_b + + # Calculate best responses + best_response_a = np.argmax(payoff_matrix_a @ strategy_b) + best_response_b = np.argmax(payoff_matrix_b.T @ strategy_a) + + # Update strategies + strategy_a = np.zeros(n) + strategy_a[best_response_a] = 1 + strategy_b = np.zeros(m) + strategy_b[best_response_b] = 1 + + return strategy_a, strategy_b + + +# Example usage +payoff_a = np.array([[3, 0], [5, 1]]) +payoff_b = np.array([[2, 4], [0, 2]]) +strategies = fictitious_play(payoff_a, payoff_b) +print("Fictitious Play strategies:", strategies) diff --git a/game_theory/minimax_algorithm.py b/game_theory/minimax_algorithm.py new file mode 100644 index 000000000000..607ccce07119 --- /dev/null +++ b/game_theory/minimax_algorithm.py @@ -0,0 +1,29 @@ +def minimax(depth, node_index, is_maximizing_player, values, alpha, beta): + if depth == 0: + return values[node_index] + + if is_maximizing_player: + best_value = float("-inf") + for i in range(2): # Two children (0 and 1) + value = minimax(depth - 1, node_index * 2 + i, False, values, alpha, beta) + best_value = max(best_value, value) + alpha = max(alpha, best_value) + if beta <= alpha: + break # Beta cut-off + return best_value + else: + best_value = float("inf") + for i in range(2): # Two children (0 and 1) + value = minimax(depth - 1, node_index * 2 + i, True, values, alpha, beta) + best_value = min(best_value, value) + beta = min(beta, best_value) + if beta <= alpha: + break # Alpha cut-off + return best_value + + +# Example usage +values = [3, 5, 2, 9, 0, 1, 8, 6] # Leaf node values +depth = 3 # Depth of the game tree +result = minimax(depth, 0, True, values, float("-inf"), float("inf")) +print("The optimal value is:", result) diff --git a/game_theory/nash_equlibrium.py b/game_theory/nash_equlibrium.py new file mode 100644 index 000000000000..4daf6469506f --- /dev/null +++ b/game_theory/nash_equlibrium.py @@ -0,0 +1,32 @@ +import numpy as np +from scipy.optimize import linprog + + +def find_nash_equilibrium(payoff_matrix_a, payoff_matrix_b): + n = payoff_matrix_a.shape[0] + m = payoff_matrix_a.shape[1] + + # Solve for player A + c = [-1] * n # Objective: maximize A's payoff + a_ub = -payoff_matrix_a # A's constraints + b_ub = [-1] * m + + result_a = linprog(c, A_ub=a_ub, b_ub=b_ub, bounds=(0, None)) + p_a = result_a.x + + # Solve for player B + c = [-1] * m # Objective: maximize B's payoff + a_ub = -payoff_matrix_b.T # B's constraints + b_ub = [-1] * n + + result_b = linprog(c, A_ub=a_ub, b_ub=b_ub, bounds=(0, None)) + p_b = result_b.x + + return p_a, p_b + + +# Example usage +payoff_a = np.array([[3, 0], [5, 1]]) +payoff_b = np.array([[2, 4], [0, 2]]) +equilibrium = find_nash_equilibrium(payoff_a, payoff_b) +print("Nash Equilibrium strategies:", equilibrium) diff --git a/game_theory/shapley_value.py b/game_theory/shapley_value.py new file mode 100644 index 000000000000..c7db1f82d4fb --- /dev/null +++ b/game_theory/shapley_value.py @@ -0,0 +1,34 @@ +import numpy as np + + +def shapley_value(payoff_matrix): + n = payoff_matrix.shape[1] # Number of players + shapley_values = np.zeros(n) # Initialize Shapley values + + # Iterate over each player + for i in range(n): + # Iterate over all subsets of players (from 0 to 2^n - 1) + for s in range(1 << n): # All subsets of players + if (s & (1 << i)) == 0: # If player i is not in subset S + continue + + # Calculate the value of the subset S without player i + s_without_i = s & ~(1 << i) # Remove player i from the subset + marginal_contribution = payoff_matrix[s][i] - ( + payoff_matrix[s_without_i][i] if s_without_i else 0 + ) + + # Count the size of the subset S + size_of_s = bin(s).count("1") # Number of players in subset S + shapley_values[i] += marginal_contribution / ( + size_of_s * (n - size_of_s) + ) # Normalize by size of S + + return shapley_values + + +# Example usage +# Payoff matrix with payoffs for 4 coalitions: {}, {1}, {2}, {1, 2} +payoff_matrix = np.array([[0, 0], [1, 0], [0, 2], [3, 4]]) +shapley_vals = shapley_value(payoff_matrix) +print("Shapley Values:", shapley_vals)