<commit_before>from __future__ import division
import random
from operator import itemgetter

from tpg.action import Action
from tpg.learner import Learner
from tpg.team import Team
from tpg.tpg_agent import TpgAgent

"""
The main class to do training on a population of Teams.
Created By: <NAME>.
Created On: June 29, 2018 13:44.
Created Because: I was tired of Java.
"""
class TpgTrainer:

    teamIdCounter = 0

    """
    Initializes the Training procedure, potentially picking up from a
    previously left off point.
    Args:
        actions        : (Int[] or Int) The actions available in the env. If
            Int[], the actions are each number in the list, use for single action
            output. If Int, the actions will be a list of length of the Int, use
            for multi action output.
        randSeed       :
        teamPopSizeInit: (Int) Initial Team population size.
        gap            : Proportion of agents to replace per gen.
        pLearnerDelete :
        pLearnerAdd    :
        pMutateAction  :
        pActionIsTeam  :
        maxTeamSize    :
        maxProgramSize :
        pProgramDelete :
        pProgramAdd    :
        pProgramSwap   :
        pProgramMutate :
        popInit        : Object containing all info needed to carry on from a
            previous training session. Serialize and deserialize with pickle.
        tourneyGap     : (Float) Gap for tournament selection.
        actionRange    : ((Float, Float, Float)) A 3-tuple of min, max, and step
            size for actions (if multi-action).
    """
    def __init__(self, actions, randSeed=0, teamPopSizeInit=360, gap=0.5,
            pLearnerDelete=0.7, pLearnerAdd=0.7, pMutateAction=0.2,
            pActionIsTeam=0.5, maxTeamSize=5, maxProgramSize=96,
            pProgramDelete=0.5, pProgramAdd=0.5, pProgramSwap=1.0,
            pProgramMutate=1.0, popInit=None, tourneyGap=0.5,
            actionRange=(0.0, 1.0, 0.05)):

        # set the variables
        self.actions = actions
        if isinstance(actions, int):
            self.multiAction = True
        else:
            self.multiAction = False
        self.randSeed = randSeed
        self.teamPopSizeInit = teamPopSizeInit
        self.gap = gap
        self.pLearnerDelete = pLearnerDelete
        self.pLearnerAdd = pLearnerAdd
        self.pMutateAction = pMutateAction
        self.pActionIsTeam = pActionIsTeam
        self.maxTeamSize = maxTeamSize
        self.maxProgramSize = maxProgramSize
        self.pProgramDelete = pProgramDelete
        self.pProgramAdd = pProgramAdd
        self.pProgramSwap = pProgramSwap
        self.pProgramMutate = pProgramMutate
        self.tourneyGap = tourneyGap
        self.actionRange = actionRange

        # establish random for training
        self.rand = random.Random()
        if randSeed == 0:
            self.rand.seed()
        else:
            self.rand.seed(randSeed)

        # create initial populations if starting anew
        if popInit is None:
            self.teams = []
            self.rootTeams = []
            self.learners = []
            self.curGen = 0
            self.tournamentsPlayed = 0
            self.initPops()
        else: # or carry on from object
            self.teams = popInit.teams
            self.rootTeams = popInit.rootTeams
            self.learners = popInit.learners
            self.curGen = popInit.gen
            self.tournamentsPlayed = popInit.tournamentsPlayed
            TpgTrainer.teamIdCounter = popInit.teamIdCounter
            Learner.idCount = popInit.idCount

        self.teamQueue = list(self.rootTeams)
        self.tasks = set() # set of tasks done per all individuals

        for i in range(len(self.teamQueue)):
            self.teamQueue[i].rootNum = i

        self.scoreStats = {}

    """
    Attempts to add a task to the set of tasks. Needs to be made thread safe on
    client side if applicable.
    """
    def addTask(self, task):
        self.tasks.add(task)

    """
    Clears the outcomes of all root teams.
    Args:
        tasks:
            (Str[]) List of tasks to clear from the outcomes, leave as None to
            clear all outcomes.
    """
    def clearOutcomes(self, tasks=None):
        for team in self.rootTeams:
            if tasks is None:
                team.outcomes = {}
            else:
                for task in tasks:
                    team.outcomes.pop(task, None)

    """
    Gets the agent that scores the best at the specified tasks.
    Args:
        tasks:
            (Str[]) List of tasks to base best on. If None, uses cur gen tasks.
            If Empty, uses default task.
        amount:
            (Int) Number of best to take.
        topn:
            (Int) Positions to consider for points.
    Returns:
        (Agent) The agent that scored the best. Based on positions, and points
        awarded to those positions.
    """
    def getBestAgents(self, tasks=None, amount=1, topn=3):
        if tasks is None:
            tasks = self.tasks
        elif len(tasks) == 0:
            tasks = [TpgAgent.defTaskName]

        taskPosMatrix = {}
        # fill position matrix
        for task in tasks:
            taskPosMatrix[task] = sorted([rt for rt in self.rootTeams if task in rt.outcomes],
                    key = lambda rt: rt.outcomes[task], reverse=True)[:topn]

        teamPoints = {}
        # assign points to teams based on positions
        for task in tasks:
            for i in range(len(taskPosMatrix[task])):
                team = taskPosMatrix[task][i]
                if team not in teamPoints:
                    teamPoints[team] = topn - i
                else:
                    teamPoints[team] += topn - i

        bestTeams = sorted(teamPoints.items(), key=itemgetter(1), reverse=True)[amount]

        return [TpgAgent(bt[0]) for bt in bestTeams]

    """
    Gets/pops the next team from the population for the client, in the form of
    an instance of TpgAgent. Needs to be made thread safe on client side if
    applicable.
    Args:
        noRef:
            (Bool): Whether to link to this trainer, don't use if multiprocessing.
    Returns:
        (TpgAgent) None if no team left in queue, means to call for evolution.
    """
    def getNextAgent(self, noRef=False):
        if len(self.teamQueue) == 0:
            agent = None
        else:
            trainer = self
            if noRef:
                trainer = None
            agent = TpgAgent(self.teamQueue.pop(), trainer=trainer)

        return agent

    """
    Gets all the agents. Empties the teamQueue. Needs to be made thread safe on
    client side if applicable.
    Args:
        skipTasks:<commit_msg>fixed getBestAgents<commit_after>from __future__ import division
import random
from operator import itemgetter

from tpg.action import Action
from tpg.learner import Learner
from tpg.team import Team
from tpg.tpg_agent import TpgAgent

"""
The main class to do training on a population of Teams.
Created By: <NAME>.
Created On: June 29, 2018 13:44.
Created Because: I was tired of Java.
"""
class TpgTrainer:

    teamIdCounter = 0

    """
    Initializes the Training procedure, potentially picking up from a
    previously left off point.
    Args:
        actions        : (Int[] or Int) The actions available in the env. If
            Int[], the actions are each number in the list, use for single action
            output. If Int, the actions will be a list of length of the Int, use
            for multi action output.
        randSeed       :
        teamPopSizeInit: (Int) Initial Team population size.
        gap            : Proportion of agents to replace per gen.
        pLearnerDelete :
        pLearnerAdd    :
        pMutateAction  :
        pActionIsTeam  :
        maxTeamSize    :
        maxProgramSize :
        pProgramDelete :
        pProgramAdd    :
        pProgramSwap   :
        pProgramMutate :
        popInit        : Object containing all info needed to carry on from a
            previous training session. Serialize and deserialize with pickle.
        tourneyGap     : (Float) Gap for tournament selection.
        actionRange    : ((Float, Float, Float)) A 3-tuple of min, max, and step
            size for actions (if multi-action).
    """
    def __init__(self, actions, randSeed=0, teamPopSizeInit=360, gap=0.5,
            pLearnerDelete=0.7, pLearnerAdd=0.7, pMutateAction=0.2,
            pActionIsTeam=0.5, maxTeamSize=5, maxProgramSize=96,
            pProgramDelete=0.5, pProgramAdd=0.5, pProgramSwap=1.0,
            pProgramMutate=1.0, popInit=None, tourneyGap=0.5,
            actionRange=(0.0, 1.0, 0.05)):

        # set the variables
        self.actions = actions
        if isinstance(actions, int):
            self.multiAction = True
        else:
            self.multiAction = False
        self.randSeed = randSeed
        self.teamPopSizeInit = teamPopSizeInit
        self.gap = gap
        self.pLearnerDelete = pLearnerDelete
        self.pLearnerAdd = pLearnerAdd
        self.pMutateAction = pMutateAction
        self.pActionIsTeam = pActionIsTeam
        self.maxTeamSize = maxTeamSize
        self.maxProgramSize = maxProgramSize
        self.pProgramDelete = pProgramDelete
        self.pProgramAdd = pProgramAdd
        self.pProgramSwap = pProgramSwap
        self.pProgramMutate = pProgramMutate
        self.tourneyGap = tourneyGap
        self.actionRange = actionRange

        # establish random for training
        self.rand = random.Random()
        if randSeed == 0:
            self.rand.seed()
        else:
            self.rand.seed(randSeed)

        # create initial populations if starting anew
        if popInit is None:
            self.teams = []
            self.rootTeams = []
            self.learners = []
            self.curGen = 0
            self.tournamentsPlayed = 0
            self.initPops()
        else: # or carry on from object
            self.teams = popInit.teams
            self.rootTeams = popInit.rootTeams
            self.learners = popInit.learners
            self.curGen = popInit.gen
            self.tournamentsPlayed = popInit.tournamentsPlayed
            TpgTrainer.teamIdCounter = popInit.teamIdCounter
            Learner.idCount = popInit.idCount

        self.teamQueue = list(self.rootTeams)
        self.tasks = set() # set of tasks done per all individuals

        for i in range(len(self.teamQueue)):
            self.teamQueue[i].rootNum = i

        self.scoreStats = {}

    """
    Attempts to add a task to the set of tasks. Needs to be made thread safe on
    client side if applicable.
    """
    def addTask(self, task):
        self.tasks.add(task)

    """
    Clears the outcomes of all root teams.
    Args:
        tasks:
            (Str[]) List of tasks to clear from the outcomes, leave as None to
            clear all outcomes.
    """
    def clearOutcomes(self, tasks=None):
        for team in self.rootTeams:
            if tasks is None:
                team.outcomes = {}
            else:
                for task in tasks:
                    team.outcomes.pop(task, None)

    """
    Gets the agent that scores the best at the specified tasks.
    Args:
        tasks:
            (Str[]) List of tasks to base best on. If None, uses cur gen tasks.
            If Empty, uses default task.
        amount:
            (Int) Number of best to take.
        topn:
            (Int) Positions to consider for points.
    Returns:
        (Agent) The agent that scored the best. Based on positions, and points
        awarded to those positions.
    """
    def getBestAgents(self, tasks=None, amount=1, topn=3):
        if tasks is None:
            tasks = self.tasks
        elif len(tasks) == 0:
            tasks = [TpgAgent.defTaskName]

        taskPosMatrix = {}
        # fill position matrix
        for task in tasks:
            taskPosMatrix[task] = sorted([rt for rt in self.rootTeams if task in rt.outcomes],
                    key = lambda rt: rt.outcomes[task], reverse=True)[:topn]

        teamPoints = {}
        # assign points to teams based on positions
        for task in tasks:
            for i in range(len(taskPosMatrix[task])):
                team = taskPosMatrix[task][i]
                if team not in teamPoints:
                    teamPoints[team] = topn - i
                else:
                    teamPoints[team] += topn - i

        bestTeams = sorted(teamPoints.items(), key=itemgetter(1), reverse=True)[:amount]

        return [TpgAgent(bt[0]) for bt in bestTeams]

    """
    Gets/pops the next team from the population for the client, in the form of
    an instance of TpgAgent. Needs to be made thread safe on client side if
    applicable.
    Args:
        noRef:
            (Bool): Whether to link to this trainer, don't use if multiprocessing.
    Returns:
        (TpgAgent) None if no team left in queue, means to call for evolution.
    """
    def getNextAgent(self, noRef=False):
        if len(self.teamQueue) == 0:
            agent = None
        else:
            trainer = self
            if noRef:
                trainer = None
            agent = TpgAgent(self.teamQueue.pop(), trainer=trainer)

        return agent

    """
    Gets all the agents. Empties the teamQueue. Needs to be made thread safe on
    client side if applicable.
    Args:
        skipTasks:
{'fraction_non_alphanumeric': 0.07486750765096663, 'fraction_numerical': 0.008210793461222662, 'mean_word_length': 1.8701799485861184, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1503952', 'n_tokens_mistral': 3810, 'n_tokens_neox': 3697, 'n_words': 1238}