Skip to content
Snippets Groups Projects
Select Git revision
  • 2cbe44dcb07ca93c8b60397dc2542435e017de88
  • master default protected
2 results

game.py

Blame
  • game.py 8.57 KiB
    import matplotlib.pyplot as plt
    from matplotlib import cm
    from mpl_toolkits.mplot3d import Axes3D
    import numpy as np
    import utilis, agent, graph
    
    
    class game:
        def __init__(self, N=100, R=1, K=99, P=0, Actions=[0, 0.2, 0.4, 0.6, 0.8], I=1000, RF=0, alpha=1):
            # datamap = utilis.read()
            # self.N = datamap['N']  # N-Player Game
            # self.M = datamap['M']  # Randomly choose M players to play the game (normally 2)
            # self.RF = datamap['RF']  # Parsed number of risk function chosen for the game
            # self.alpha = datamap['alpha']  # Loss fraction
            # self.R = datamap['R']   # Rounds of a game
    
    
            self.N = N
            self.M = 2
            self.RF = RF
            self.alpha = alpha
            self.R = R
            self.threshold = 0.5      # Threshold
            # self.actions = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
            self.actions = Actions
            self.iterations = I
    
            """
            | 2-Player Game Graph Model:
            |
            | P: Probability of rewiring each original edge in the graph
            |
            | K: The number of edges(games) connected to each player. Has to be an even number.
            |    If 1 is desired, don't use graph model. Max k: n - 2 (for even n) | n - 1 (for odd n)
            |    * k can be odd as n - 1 (for even n). In cases k = n - 1 (for all n) -> a fully connected graph
            """
            # self.graph_based = True
            self.rewire_p = P
            self.rewire_k = K
            # assert (self.rewire_k < self.N)
            self.graph = graph.Graph(self.N, self.rewire_k, self.rewire_p)
    
    
            "Create players"
            self.players = []
            IW = 100     # Initial Wealth - can be input, can be variable to distinguish population
            self.totalWealth = self.M * IW    # subject to change
            for i in range(self.N):
                self.players.append(agent.Agent(self.R, IW, self.actions))
    
    
    
        def riskfunc(self,contribution,totalwealth):
            """
                the probability of collective-risk happening, given contribution
            """
    
            proportion = contribution/totalwealth
    
            if self.RF == 0:
                # probably parse more parameters here
                return 1 - proportion
    
    
            elif self.RF == 1:
                if proportion >= 0.5:
                    return 0
                else:
                    return 1
    
    
            elif self.RF == 2:
                threshold = 0.5
                if proportion < threshold:
                    return 1 - proportion / threshold
                else:
                    return 0
    
            return "error"
    
    
        def play(self):
    
            # lastStrategyTable = np.zeros((self.N, self.R))
            # sameStrategyRounds = 0
    
            results = np.zeros((self.iterations, self.R, len(self.actions)))
            """ITERATION"""
            for iter in range(self.iterations):
    
                actionTable = np.zeros((self.N, self.R))
                strategyTable = np.zeros((self.R, self.N))        # DIFFERENT AXIS R-N
                lossTable = np.zeros((self.N, self.R))
    
                for playerIndex in range(self.N):                 # For each player
                    player = self.players[playerIndex]
                    player.resetWealth()                          # reset initial wealth
                    for r in range(self.R):                              # For each round
                        action = player.chooseAction(r)
                        actionTable[playerIndex][r] = action
                        strategyTable[r][playerIndex] = player.getStrategy()[r]
    
                playersNo = self.graph.select()
                for r in range(self.R):
                    for [i, j] in playersNo:
                        pool = 0
                        pool += self.players[i].getWealth() * actionTable[i][r] +\
                                self.players[j].getWealth() * actionTable[j][r]
                        risk = self.riskfunc(pool, self.totalWealth)
    
                        for p in [i, j]:
                            if np.random.uniform(0, 1) < risk:
                                lossTable[p, r] += self.alpha/self.graph.getNodesNumber()[p]
                    for i in range(self.N):
                        self.players[i].updateReward(r, actionTable[i][r], lossTable[i][r])
    
                """Strategy Stats"""
                # if np.array_equal(strategyTable, lastStrategyTable):
                #     sameStrategyRounds += 1
                # else:
                #     sameStrategyRounds = 0
                #     lastStrategyTable = strategyTable
    
                for r in range(self.R):
                    unique, count = np.unique(strategyTable[r], return_counts=True)
                    round_counter = dict(zip(unique, count))
                    # print("Round ", r, round_counter)
    
                    for a in range(len(self.actions)):
                        if self.actions[a] not in round_counter:
                            pass
                        else:
                            results[iter, r, a] = round_counter[self.actions[a]]
    
            return results
    
    
    
    def stackPlot(data, r, Actions, Iterations, titleComment = ""):
    
        A = len(Actions)
        x = range(Iterations)
        y = np.zeros((Iterations, A))
        for i in range(Iterations):
            y[i] = data[i][r]
        y = np.vstack(y.T)
    
        fig, ax = plt.subplots()
        # grays = np.arange(0, 1, (max(Actions) - min(Actions))/A)
        ax.stackplot(x, y, labels=Actions, colors=[str(1 - x) for x in Actions])
        ax.legend(loc='lower right')
        plt.ylabel('Number of Actions')
        plt.xlabel('Time(iterations)')
    
        title = 'Average Number of Actions in Round ' + str(r+1) + ')'
        if not titleComment:
            title += "\n" + titleComment
    
        plt.title(title)
        plt.show()
    
    
    def rep(repeat, N=100, R=1, K=99, P=0, Actions=[0, 0.2, 0.4, 0.6, 0.8], I=1000, RF=0, alpha=1):
        data = np.zeros((I, R, len(Actions)))
        Actions.sort()
        for re in range(repeat):
            print("REP", re)
            g = game(N, R, K, P, Actions, I, RF, alpha)
            result = g.play()
            data += result
        data /= repeat
        return data
    
    
    def averageOfLast(data, Actions, r=0, lastIterations=100 ):
        sum = 0
        action_counter = {action:0 for action in Actions}
    
        for i in range(-1, -lastIterations-1, -1):
            sum += np.sum(data[i, r] * Actions)
            for a in range(len(Actions)):
                action_counter[Actions[a]] += data[i, r, a]/lastIterations
        return (sum/100, action_counter)
    
    
    
    def graph_kp3d(Actions, Klist=[2, 4], Plist=[0.2, 0.5, 0.8], repeat=1):
        K = Klist
        P = Plist
    
        meanA = np.zeros((len(K), len(P)))
    
        for k in range(len(K)):
            for p in range(len(P)):
                data = rep(repeat, K=K[k], P=P[p])    # Specify other params by adding here or change default of rep
                meanA[k][p] = averageOfLast(data, Actions, lastIterations=100)[0]  # Doing the first round only -- for now
                print("k, p, mean",k,p,meanA[k][p])
    
        P, K = np.meshgrid(P, K)
    
        fig = plt.figure()
        ax = fig.gca(projection='3d')
    
        surf = ax.plot_surface(P, K, meanA, cmap=cm.coolwarm,
                               linewidth=0, antialiased=False)
    
        fig.colorbar(surf, shrink=0.5, aspect=5)
        plt.show()
    
    
    def stackBar_alpha(r, Actions, alphaList, repeat=1):    # Plotting the data for round r
    
        A = len(Actions)
        p = []
        count = np.zeros((A, len(alphaList)))     # of each action in each iter
        ind = np.arange(len(alphaList))
        width = 0.3
    
        for al in range(len(alphaList)):
            data = rep(repeat, Actions=Actions, alpha=alphaList[al])
            action_counter = averageOfLast(data, Actions, r, 100)[1]
            for a in range(A):
                count[a, al] = action_counter[Actions[a]]
        base = 0
    
        for a in range(A):
            p.append(plt.bar(ind, count[a], width, bottom=base, color=str(0.9 - 0.9 * Actions[a])))
            base += count[a]
    
        plt.ylabel('Number of Actions')
        plt.xlabel('Alpha, the loss fraction')
        plt.title('Average Number of Actions in Round ' + str(r+1))
        plt.xticks(ind, alphaList)
        # plt.yticks(np.arange(0, 81, 10))
        plt.legend(tuple([p[x][0] for x in range(A)][::-1]), tuple(Actions[::-1]), loc='lower left')
        plt.show()
    
    
    
    def main():
    
        # Read-in or Define Parameters
    
        N = 100
        R = 2
        K = 99
        P = 0
        I = 1000
        RF = 0
        alpha =1
        Actions = [0, 0.2, 0.4, 0.6, 0.8]
    
    
        """
        Graph1: Number of Actions of Round r (start by 0) by Iteration
        """
        # Repeat game and get the averaged data
        # RepeatTimes = 30
        # data = rep(RepeatTimes, N, R, K, P, Actions, I, RF, alpha)
        #
        # for r in range(R):
        #     stackPlot(data, r, Actions, I, "Fully-Mixed Graph")
    
        """
        Graph2: Average contribution by K, P
        """
    
        # graph_kp3d(Actions)
    
        """
        Graph3: Actions by different alpha value
        """
        stackBar_alpha(0, Actions, alphaList=[0, 0.2, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1])
    
    if __name__ == '__main__':
        main()