Example #1
0
    def test_mutate(self):

        # vars for the test and defining programs
        progs = 100
        muts = 100
        prog_len = 100
        ops = 5
        dests = 8
        inputs = 10000

        # needed for mutation and initialization
        mutateParams = {
            'pProgMut': 0.5,
            'nOperations': ops,
            'nDestinations': dests,
            'inputSize': inputs,
            'pInstDel': 0.5,
            'pInstMut': 0.5,
            'pInstSwp': 0.5,
            'pInstAdd': 0.5,
            'idCountProgram': 0
        }

        # mutate all the progs many times
        for i in range(progs):
            p = Program(maxProgramLength=100,
                        nOperations=ops,
                        nDestinations=dests,
                        inputSize=inputs,
                        initParams=mutateParams)
            for i in range(muts):
                p.mutate(mutateParams)

            # check for program validity
            # atleast 1 instruction
            self.assertGreaterEqual(len(p.instructions), 1)
            # make sure each value in each intex within proper range
            for inst in p.instructions:
                # mode
                self.assertGreaterEqual(inst[0], 0)
                self.assertLessEqual(inst[0], 1)
                # op
                self.assertGreaterEqual(inst[1], 0)
                self.assertLessEqual(inst[1], ops - 1)
                # dest
                self.assertGreaterEqual(inst[2], 0)
                self.assertLessEqual(inst[2], dests - 1)
                # input
                self.assertGreaterEqual(inst[3], 0)
                self.assertLessEqual(inst[3], inputs - 1)
Example #2
0
class ConfActionObject:
    def init_def(self, initParams=None, action=None):
        '''
        Defer importing the Team class to avoid circular dependency.
        This may require refactoring to fix properly
        '''
        from tpg.team import Team

        # The action is a team
        if isinstance(action, Team):
            self.teamAction = action
            self.actionCode = None
            #print("chose team action")
            return

        # The action is another action object
        if isinstance(action, ActionObject):
            self.actionCode = action.actionCode
            self.teamAction = action.teamAction
            return

        # An int means the action is an index into the action codes in initParams
        if isinstance(action, int):

            if "actionCodes" not in initParams:
                raise Exception('action codes not found in init params',
                                initParams)

            try:
                self.actionCode = initParams["actionCodes"][action]
                self.teamAction = None
            except IndexError as err:
                '''
                TODO log index error
                '''
                print("Index error")
            return

    def init_real(self, initParams=None, action=None):
        '''
        Defer importing the Team class to avoid circular dependency.
        This may require refactoring to fix properly
        '''
        from tpg.team import Team

        if isinstance(action, Team):
            # The action is a team
            self.actionCode = None
            self.actionLength = None
            self.teamAction = action
            self.program = Program(
                initParams=initParams,
                maxProgramLength=initParams["initMaxActProgSize"],
                nOperations=initParams["nOperations"],
                nDestinations=initParams["nDestinations"],
                inputSize=initParams["inputSize"])

        elif isinstance(action, ActionObject):
            # The action is another action object
            self.actionCode = action.actionCode
            self.actionLength = action.actionLength
            self.teamAction = action.teamAction
            self.program = Program(instructions=action.program.instructions,
                                   initParams=initParams)

        elif isinstance(action, int):
            # An int means the action is an index into the action codes in initParams

            if "actionCodes" not in initParams:
                raise Exception('action codes not found in init params',
                                initParams)

            try:
                self.actionCode = initParams["actionCodes"][action]
                self.actionLength = initParams["actionLengths"][action]
                self.teamAction = None
                self.program = Program(
                    initParams=initParams,
                    maxProgramLength=initParams["initMaxActProgSize"],
                    nOperations=initParams["nOperations"],
                    nDestinations=initParams["nDestinations"],
                    inputSize=initParams["inputSize"])
            except IndexError as err:
                '''
                TODO log index error
                '''
                print("Index error")

        self.registers = np.zeros(
            max(initParams["nActRegisters"], initParams["nDestinations"]))

    """
    Returns the action code, and if applicable corresponding real action.
    """

    def getAction_def(self, state, visited, actVars=None, path_trace=None):
        if self.teamAction is not None:
            # action from team
            return self.teamAction.act(state,
                                       visited,
                                       actVars=actVars,
                                       path_trace=path_trace)
        else:
            # atomic action
            return self.actionCode

    """
    Returns the action code, and if applicable corresponding real action(s).
    """

    def getAction_real(self, state, visited, actVars=None, path_trace=None):
        if self.teamAction is not None:
            # action from team
            return self.teamAction.act(state,
                                       visited,
                                       actVars=actVars,
                                       path_trace=path_trace)
        else:
            # atomic action
            if self.actionLength == 0:
                return self.actionCode, None
            else:
                return self.actionCode, self.getRealAction(state,
                                                           actVars=actVars)

    """
    Gets the real action from a register.
    """

    def getRealAction_real(self, state, actVars=None):
        Program.execute(state, self.registers, self.program.instructions[:, 0],
                        self.program.instructions[:, 1],
                        self.program.instructions[:, 2],
                        self.program.instructions[:, 3])

        return self.registers[:self.actionLength]

    """
    Gets the real action from a register. With memory.
    """

    def getRealAction_real_mem(self, state, actVars=None):
        Program.execute(state, self.registers, self.program.instructions[:, 0],
                        self.program.instructions[:, 1],
                        self.program.instructions[:, 2],
                        self.program.instructions[:, 3], actVars["memMatrix"],
                        actVars["memMatrix"].shape[0],
                        actVars["memMatrix"].shape[1],
                        Program.memWriteProbFunc)

        return self.registers[:self.actionLength]

    """
    Returns true if the action is atomic, otherwise the action is a team.
    """

    def isAtomic_def(self):
        return self.teamAction is None

    """
    Change action to team or atomic action.
    """

    def mutate_def(self, mutateParams, parentTeam, teams, pActAtom,
                   learner_id):
        # mutate action
        if flip(pActAtom):
            # atomic
            '''
            If we already have an action code make sure not to pick the same one.
            TODO handle case where there is only 1 action code.
            '''
            if self.actionCode is not None:
                options = list(
                    filter(lambda code: code != self.actionCode,
                           mutateParams["actionCodes"]))
            else:
                options = mutateParams["actionCodes"]

            # let our current team know we won't be pointing to them anymore
            if not self.isAtomic():
                #print("Learner {} switching from Team {} to atomic action".format(learner_id, self.teamAction.id))
                self.teamAction.inLearners.remove(str(learner_id))

            self.actionCode = random.choice(options)
            self.teamAction = None
        else:
            # team action
            selection_pool = [
                t for t in teams
                if t is not self.teamAction and t is not parentTeam
            ]

            # If we have a valid set of options choose from them
            if len(selection_pool) > 0:
                # let our current team know we won't be pointing to them anymore
                oldTeam = None
                if not self.isAtomic():
                    oldTeam = self.teamAction
                    self.teamAction.inLearners.remove(str(learner_id))

                self.teamAction = random.choice(selection_pool)
                # Let the new team know we're pointing to them
                self.teamAction.inLearners.append(str(learner_id))

                #if oldTeam != None:
                #    print("Learner {} switched from Team {} to Team {}".format(learner_id, oldTeam.id, self.teamAction.id))

        return self

    """
    Change action to team or atomic action.
    """

    def mutate_real(self, mutateParams, parentTeam, teams, pActAtom,
                    learner_id):

        # first maybe mutate just program
        if self.actionLength > 0 and flip(0.5):
            self.program.mutate(mutateParams)

        # mutate action
        if flip(pActAtom):
            # atomic
            '''
            If we already have an action code make sure not to pick the same one.
            TODO handle case where there is only 1 action code.
            '''
            if self.actionCode is not None:
                options = list(
                    filter(lambda code: code != self.actionCode,
                           mutateParams["actionCodes"]))
            else:
                options = mutateParams["actionCodes"]

            # let our current team know we won't be pointing to them anymore
            if not self.isAtomic():
                #print("Learner {} switching from Team {} to atomic action".format(learner_id, self.teamAction.id))
                self.teamAction.inLearners.remove(str(learner_id))

            self.actionCode = random.choice(options)
            self.actionLength = mutateParams["actionLengths"][self.actionCode]
            self.teamAction = None
        else:
            # team action
            selection_pool = [
                t for t in teams
                if t is not self.teamAction and t is not parentTeam
            ]

            # If we have a valid set of options choose from them
            if len(selection_pool) > 0:
                # let our current team know we won't be pointing to them anymore
                oldTeam = None
                if not self.isAtomic():
                    oldTeam = self.teamAction
                    self.teamAction.inLearners.remove(str(learner_id))

                self.teamAction = random.choice(selection_pool)
                # Let the new team know we're pointing to them
                self.teamAction.inLearners.append(str(learner_id))

                #if oldTeam != None:
                #    print("Learner {} switched from Team {} to Team {}".format(learner_id, oldTeam.id, self.teamAction.id))

        return self
Example #3
0
class Learner:

    idCount = 0  # unique learner id
    """
    Create a new learner, either copied from the original or from a program or
    action. Either requires a learner, or a program/action pair.
    """
    def __init__(self,
                 learner=None,
                 program=None,
                 action=None,
                 numRegisters=8):
        if learner is not None:
            self.program = Program(instructions=learner.program.instructions)
            self.action = learner.action
            self.registers = np.zeros(len(learner.registers), dtype=float)
        elif program is not None and action is not None:
            self.program = program
            self.action = action
            self.registers = np.zeros(numRegisters, dtype=float)

        if not self.isActionAtomic():
            self.action.numLearnersReferencing += 1

        self.states = []

        self.numTeamsReferencing = 0  # amount of teams with references to this

        self.id = Learner.idCount

    """
    Get the bid value, highest gets its action selected.
    """

    def bid(self, state):
        Program.execute(state, self.registers, self.program.modes,
                        self.program.operations, self.program.destinations,
                        self.program.sources)

        return self.registers[0]

    """
    Returns the action of this learner, either atomic, or requests the action
    from the action team.
    """

    def getAction(self, state, visited):
        if self.isActionAtomic():
            return self.action
        else:
            return self.action.act(state, visited)

    """
    Returns true if the action is atomic, otherwise the action is a team.
    """

    def isActionAtomic(self):
        return isinstance(self.action, (int, list))

    """
    Mutates either the program or the action or both.
    """

    def mutate(self,
               pMutProg,
               pMutAct,
               pActAtom,
               atomics,
               parentTeam,
               allTeams,
               pDelInst,
               pAddInst,
               pSwpInst,
               pMutInst,
               multiActs,
               pSwapMultiAct,
               pChangeMultiAct,
               uniqueProgThresh,
               inputs=None,
               outputs=None,
               update=True):

        changed = False
        while not changed:
            # mutate the program
            if flip(pMutProg):
                changed = True
                self.program.mutate(pMutProg,
                                    pDelInst,
                                    pAddInst,
                                    pSwpInst,
                                    pMutInst,
                                    len(self.registers),
                                    uniqueProgThresh,
                                    inputs=inputs,
                                    outputs=outputs,
                                    update=update)

            # mutate the action
            if flip(pMutAct):
                changed = True
                self.mutateAction(pActAtom, atomics, allTeams, parentTeam,
                                  multiActs, pSwapMultiAct, pChangeMultiAct)

    """
    Changes the action, into an atomic or team.
    """

    def mutateAction(self, pActAtom, atomics, allTeams, parentTeam, multiActs,
                     pSwapMultiAct, pChangeMultiAct):
        if not self.isActionAtomic():  # dereference old team action
            self.action.numLearnersReferencing -= 1

        if flip(pActAtom):  # atomic action
            if multiActs is None:
                self.action = random.choice(
                    [a for a in atomics if a is not self.action])
            else:
                swap = flip(pSwapMultiAct)
                if swap or not self.isActionAtomic(
                ):  # totally swap action for another
                    self.action = list(random.choice(multiActs))

                # change some value in action
                if not swap or flip(pChangeMultiAct):
                    changed = False
                    while not changed or flip(pChangeMultiAct):
                        index = random.randint(0, len(self.action) - 1)
                        self.action[index] += random.gauss(0, .15)
                        self.action = list(np.clip(self.action, 0, 1))
                        changed = True

        else:  # Team action
            self.action = random.choice([
                t for t in allTeams
                if t is not self.action and t is not parentTeam
            ])

        if not self.isActionAtomic():  # add reference for new team action
            self.action.numLearnersReferencing += 1

    """
    Saves visited states for mutation uniqueness purposes.
    """

    def saveState(self, state, numStates=50):
        self.states.append(state)
        self.states = self.states[-numStates:]
Example #4
0
class ConfLearner:

    """
    Create a new learner, either copied from the original or from a program or
    action. Either requires a learner, or a program/action pair.
    """
    def init_def(self, initParams, program, actionObj, numRegisters, learner_id=None):
        self.program = Program(
            instructions=program.instructions
        ) #Each learner should have their own copy of the program
        self.actionObj = ActionObject(action=actionObj, initParams=initParams) #Each learner should have their own copy of the action object
        self.registers = np.zeros(numRegisters, dtype=float)

        self.ancestor = None #By default no ancestor

        '''
        TODO What's self.states? 
        '''
        self.states = []


        self.inTeams = [] # Store a list of teams that reference this learner, incoming edges
        

        self.genCreate = initParams["generation"] # Store the generation that this learner was created on

        '''
        TODO should this be -1 before it sees any frames?
        '''
        self.frameNum = 0 # Last seen frame is 0

        # Assign id from initParams counter
        self.id = uuid.uuid4()


        if not self.isActionAtomic():
            self.actionObj.teamAction.inLearners.append(str(self.id))

        #print("Creating a brand new learner" if learner_id == None else "Creating a learner from {}".format(str(learner_id)))
        #print("Created learner {} [{}] -> {}".format(self.id, "atomic" if self.isActionAtomic() else "Team", self.actionObj.actionCode if self.isActionAtomic() else self.actionObj.teamAction.id))
        

    """
    Get the bid value, highest gets its action selected.
    """
    def bid_def(self, state, actVars=None):
        # exit early if we already got bidded this frame
        if self.frameNum == actVars["frameNum"]:
            return self.registers[0]

        self.frameNum = actVars["frameNum"]

        Program.execute(state, self.registers,
                        self.program.instructions[:,0], self.program.instructions[:,1],
                        self.program.instructions[:,2], self.program.instructions[:,3])

        return self.registers[0]

    """
    Get the bid value, highest gets its action selected. Passes memory args to program.
    """
    def bid_mem(self, state, actVars=None):
        # exit early if we already got bidded this frame
        if self.frameNum == actVars["frameNum"]:
            return self.registers[0]

        self.frameNum = actVars["frameNum"]

        Program.execute(state, self.registers,
                        self.program.instructions[:,0], self.program.instructions[:,1],
                        self.program.instructions[:,2], self.program.instructions[:,3],
                        actVars["memMatrix"], actVars["memMatrix"].shape[0], actVars["memMatrix"].shape[1],
                        Program.memWriteProbFunc)

        return self.registers[0]

    """
    Returns the action of this learner, either atomic, or requests the action
    from the action team.
    """
    def getAction_def(self, state, visited, actVars=None, path_trace=None):
        return self.actionObj.getAction(state, visited, actVars=actVars, path_trace=path_trace)



    """
    Gets the team that is the action of the learners action object.
    """
    def getActionTeam_def(self):
        return self.actionObj.teamAction

    """
    Returns true if the action is atomic, otherwise the action is a team.
    """
    def isActionAtomic_def(self):
        return self.actionObj.isAtomic()

    """
    Mutates either the program or the action or both.
    """
    def mutate_def(self, mutateParams, parentTeam, teams, pActAtom):

        changed = False
        while not changed:
            # mutate the program
            if flip(mutateParams["pProgMut"]):

                changed = True
              
                self.program.mutate(mutateParams)

            # mutate the action
            if flip(mutateParams["pActMut"]):

                changed = True
                
                self.actionObj.mutate(mutateParams, parentTeam, teams, pActAtom, learner_id=self.id)

        return self
Example #5
0
class Learner:
    def __init__(self,
                 initParams,
                 program,
                 actionObj,
                 numRegisters,
                 learner_id=None):
        self.program = Program(
            instructions=program.instructions
        )  #Each learner should have their own copy of the program
        self.actionObj = ActionObject(
            action=actionObj, initParams=initParams
        )  #Each learner should have their own copy of the action object
        self.registers = np.zeros(numRegisters, dtype=float)

        self.ancestor = None  #By default no ancestor
        '''
        TODO What's self.states? 
        '''
        self.states = []

        self.inTeams = [
        ]  # Store a list of teams that reference this learner, incoming edges

        self.genCreate = initParams[
            "generation"]  # Store the generation that this learner was created on
        '''
        TODO should this be -1 before it sees any frames?
        '''
        self.frameNum = 0  # Last seen frame is 0

        # Assign id from initParams counter
        self.id = uuid.uuid4()

        if not self.isActionAtomic():
            self.actionObj.teamAction.inLearners.append(str(self.id))

        #print("Creating a brand new learner" if learner_id == None else "Creating a learner from {}".format(str(learner_id)))
        #print("Created learner {} [{}] -> {}".format(self.id, "atomic" if self.isActionAtomic() else "Team", self.actionObj.actionCode if self.isActionAtomic() else self.actionObj.teamAction.id))

    def zeroRegisters(self):
        self.registers = np.zeros(len(self.registers), dtype=float)
        self.actionObj.zeroRegisters()

    def numTeamsReferencing(self):
        return len(self.inTeams)

    '''
    A learner is equal to another object if that object:
        - is an instance of the learner class
        - was created on the same generation
        - has an identical program
        - has the same action object
        - has the same inTeams
        - has the same id

    '''

    def __eq__(self, o: object) -> bool:

        # Object must be an instance of Learner
        if not isinstance(o, Learner):
            return False

        # The object must have been created the same generation as us
        if self.genCreate != o.genCreate:
            return False

        # The object's program must be equal to ours
        if self.program != o.program:
            return False

        # The object's action object must be equal to ours
        if self.actionObj != o.actionObj:
            return False
        '''
        The other object's inTeams must match our own, therefore:
            - len(inTeams) must be equal
            - every id that appears in our inTeams must appear in theirs (order doesn't matter)
        '''
        if len(self.inTeams) != len(o.inTeams):
            return False
        '''
        Collection comparison via collection counters
        https://www.journaldev.com/37089/how-to-compare-two-lists-in-python
        '''
        if collections.Counter(self.inTeams) != collections.Counter(o.inTeams):
            return False

        # The other object's id must be equal to ours
        if self.id != o.id:
            return False

        return True

    def debugEq(self, o: object) -> bool:

        # Object must be an instance of Learner
        if not isinstance(o, Learner):
            print("other object is not instance of Learner")
            return False

        # The object must have been created the same generation as us
        if self.genCreate != o.genCreate:
            print("other object has different genCreate")
            return False

        # The object's program must be equal to ours
        if self.program != o.program:
            print("other object has a different program")
            return False

        # The object's action object must be equal to ours
        if self.actionObj != o.actionObj:
            print("other object has a different action object")
            return False
        '''
        The other object's inTeams must match our own, therefore:
            - len(inTeams) must be equal
            - every id that appears in our inTeams must appear in theirs (order doesn't matter)
        '''
        if len(self.inTeams) != len(o.inTeams):
            print("other object has different number of inTeams")
            print("us:")
            print(self)
            print("other learner:")
            print(o)
            return False
        '''
        Collection comparison via collection counters
        https://www.journaldev.com/37089/how-to-compare-two-lists-in-python
        '''
        if collections.Counter(self.inTeams) != collections.Counter(o.inTeams):
            print("other object has different inTeams")
            return False

        # The other object's id must be equal to ours
        if self.id != o.id:
            print("other object has different id")
            return False

        return True

    '''
    Negation of __eq__
    '''

    def __ne__(self, o: object) -> bool:
        return not self.__eq__(o)

    '''
    String representation of a learner
    '''

    def __str__(self):

        result = """id: {}
created_at_gen: {}
program_id: {}
type: {}
action: {}
numTeamsReferencing: {}
inTeams:\n""".format(
            self.id, self.genCreate, self.program.id,
            "actionCode" if self.isActionAtomic() else "teamAction",
            self.actionObj.actionCode
            if self.isActionAtomic() else self.actionObj.teamAction.id,
            self.numTeamsReferencing())

        for cursor in self.inTeams:
            result += "\t{}\n".format(cursor)

        return result

    """
    Create a new learner, either copied from the original or from a program or
    action. Either requires a learner, or a program/action pair.
    """
    """
    Get the bid value, highest gets its action selected.
    """

    def bid(self, state, actVars=None):
        # exit early if we already got bidded this frame
        if self.frameNum == actVars["frameNum"]:
            return self.registers[0]

        self.frameNum = actVars["frameNum"]

        Program.execute(state, self.registers, self.program.instructions[:, 0],
                        self.program.instructions[:, 1],
                        self.program.instructions[:, 2],
                        self.program.instructions[:, 3])

        return self.registers[0]

    """
    Returns the action of this learner, either atomic, or requests the action
    from the action team.
    """

    def getAction(self, state, visited, actVars=None, path_trace=None):
        return self.actionObj.getAction(state,
                                        visited,
                                        actVars=actVars,
                                        path_trace=path_trace)

    """
    Gets the team that is the action of the learners action object.
    """

    def getActionTeam(self):
        return self.actionObj.teamAction

    """
    Returns true if the action is atomic, otherwise the action is a team.
    """

    def isActionAtomic(self):
        return self.actionObj.isAtomic()

    """
    Mutates either the program or the action or both. 
    A mutation creates a new instance of the learner, removes it's anscestor and adds itself to the team.
    """

    def mutate(self, mutateParams, parentTeam, teams, pActAtom):

        changed = False
        while not changed:
            # mutate the program
            if flip(mutateParams["pProgMut"]):

                changed = True

                self.program.mutate(mutateParams)

            # mutate the action
            if flip(mutateParams["pActMut"]):

                changed = True

                self.actionObj.mutate(mutateParams,
                                      parentTeam,
                                      teams,
                                      pActAtom,
                                      learner_id=self.id)

        return self

    """
    Ensures proper functions are used in this class as set up by configurer.
    """

    @classmethod
    def configFunctions(cls, functionsDict):
        from tpg.configuration.conf_learner import ConfLearner

        if functionsDict["init"] == "def":
            cls.__init__ = ConfLearner.init_def

        if functionsDict["bid"] == "def":
            cls.bid = ConfLearner.bid_def
        elif functionsDict["bid"] == "mem":
            cls.bid = ConfLearner.bid_mem

        if functionsDict["getAction"] == "def":
            cls.getAction = ConfLearner.getAction_def

        if functionsDict["getActionTeam"] == "def":
            cls.getActionTeam = ConfLearner.getActionTeam_def

        if functionsDict["isActionAtomic"] == "def":
            cls.isActionAtomic = ConfLearner.isActionAtomic_def

        if functionsDict["mutate"] == "def":
            cls.mutate = ConfLearner.mutate_def