Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/ludics/fitness_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,35 @@ def general_four_state_fitness_function(state, **kwargs):
return np.array(
[sym.Function(f"f_{i + 1}")(state_symbol) for i, j in enumerate(state)]
)

def pairwise_interaction_fitness_function(state,a,b,c,d):
"""
Returns the fitness of players in a symmetric pairwise interaction game.
The payoff matrix for the row player is given by:

| | C | D |
|---|-----|-----|
| C | a_i | b_i |
| D | c_i | d_i |

And a player's fitness is given by the mean payoff they receive when
interacting in a 2 player game with a random other member of the
population.

Parameters:
-----------
state: numpy.array, the ordered set of actions each player takes. 1 is a
cooperator, 0 is a defector,

a,b,c,d: float numpy.array, the entries to go into the payoff matrix. Entry i is the
respective payoff for player i's payoff matrix. Float values indicate a symmetric game

Returns:
---------
numpy.array: an ordered array of each player's fitness
"""
N = len(state)
number_of_cooperators = np.sum(state)
cooperator_payoffs = ((number_of_cooperators-1) * a + (N - number_of_cooperators) * b)/(N-1)
defector_payoffs = ((number_of_cooperators) * c + (N - number_of_cooperators-1) * d)/(N-1)
return cooperator_payoffs * state + defector_payoffs * (1 - state)
52 changes: 51 additions & 1 deletion tests/test_fitness_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,4 +243,54 @@ def test_public_goods_game_fitness_function_for_homoogeneous_contribution_and_he

expected_return = np.array([0,1,2])

np.testing.assert_allclose(actual_return, expected_return)
np.testing.assert_allclose(actual_return, expected_return)

def test_pairwise_interaction_fitness_function_for_symmetric_prisoners_dilemma():
"""
Tests that pairwise_interaction_fitness_function returns the correct
value for a symmetric, standard prisoner's dilemma"""

state = np.array([0,1,1,0,1])
a = np.array([3 for _ in state])
b = np.array([0 for _ in state])
c = np.array([5 for _ in state])
d = np.array([1 for _ in state])

actual_value = ludics.fitness_functions.pairwise_interaction_fitness_function(state=state,a=a,b=b,c=c,d=d)
expected_value = np.array([4, 6/4, 6/4, 4, 6/4])

np.testing.assert_allclose(actual_value, expected_value)

def test_pairwise_interaction_fitness_function_for_asymmetric_game():
"""
Tests that pairwise_interaction_fitness_function returns the correct value for
an asymmetric game"""

state = np.array([1,0,1,0])
a = np.array([1,2,3,4])
b = np.array([2,4,6,8])
c = np.array([5,4,3,2])
d = np.array([2,2,2,1])

actual_value = ludics.fitness_functions.pairwise_interaction_fitness_function(state=state,a=a,b=b,c=c,d=d)

expected_value = np.array([5/3, 10/3, 5, 5/3])

np.testing.assert_allclose(actual_value, expected_value)

def test_pairwise_interaction_fitness_function_for_mixed_parameters():
"""
Tests that pairwise_interaction_fitness_function returns the correct value for
an asymmetric game where two parameters are symmetric"""

state = np.array([1,0,0,1])
a = np.array([1,2,3,4])
b = np.array([2,4,6,4])
c = 5
d = 2

actual_value = ludics.fitness_functions.pairwise_interaction_fitness_function(state=state,a=a,b=b,c=c,d=d)

expected_value = np.array([5/3, 4, 4, 4])

np.testing.assert_allclose(actual_value, expected_value)
Loading