Exemple #1
0
    def fill_genome(self, block_def: BlockDefinition,
                    block_material: BlockMaterial):
        '''
        TODO
        '''
        block_material.genome = [None] * block_def.genome_count
        block_material.genome[(
            -1 * block_def.input_count):] = ["InputPlaceholder"
                                             ] * block_def.input_count

        # fill main nodes
        for node_index in range(block_def.main_count):
            ftns = block_def.get_random_ftn(return_all=True)
            for ftn in ftns:
                # find inputs
                input_dtypes = block_def.operator_dict[ftn]["inputs"]
                input_index = [None] * len(input_dtypes)
                for ith_input, input_dtype in enumerate(input_dtypes):
                    input_index[ith_input] = block_def.get_random_input(
                        block_material, req_dtype=input_dtype, _max=node_index)
                if None in input_index:
                    # failed to fill it in; try another ftn
                    continue
                else:
                    pass

                # find args
                arg_dtypes = block_def.operator_dict[ftn]["args"]
                arg_index = [None] * len(arg_dtypes)
                for ith_arg, arg_dtype in enumerate(arg_dtypes):
                    arg_index[ith_arg] = block_def.get_random_arg(
                        req_dtype=arg_dtype)
                if None in arg_index:
                    # failed to fill it in; try another ftn
                    continue
                else:
                    pass

                # all complete
                block_material[node_index] = {
                    "ftn": ftn,
                    "inputs": input_index,
                    "args": arg_index
                }
                break
            # error check that node got filled
            if block_material[node_index] is None:
                print(
                    "GENOME ERROR: no primitive was able to fit into current genome arrangment"
                )
                import pdb
                pdb.set_trace()
                exit()

        # fill output nodes
        for ith_output, node_index in enumerate(
                range(block_def.main_count,
                      block_def.main_count + block_def.output_count)):
            req_dtype = block_def.output_dtypes[ith_output]
            block_material[node_index] = block_def.get_random_input(
                block_material,
                req_dtype=req_dtype,
                _min=0,
                _max=block_def.main_count)
Exemple #2
0
    def build_block_from_lisp(self, block_def: BlockDefinition, lisp: str,
                              indiv_id):
        '''
        the expectation here is that lisp is the string tree representation (not a file holding the str)
        that follows the format of how we build out a lisp in codes.block_definitions.block_definition.get_lisp()

        shoud look something like: [func1,[func2,-2n,-1n],-1n]
        
        we also can handle cases where we are 'reusing' the output of a node...thanks to this line
            ```lisp = lisp.replace(_active_dict[ith_node], "%in" % ith_node)```
        try with: lisp = '[mult,-1n,[mult,[sub,[mult,-1n,-1n],-2n],[sub,[mult,-1n,-1n],-2n]]]'

        NOTE: I think this currently only works if the block has 1 output!
        '''
        _active_dict = {}
        ith_node = 0
        while True:
            # from the start of the string, keep looking for lists []
            match = re.search("\[[0-9A-Za-z_\-\s.,']+\]", lisp)
            if match is None:
                # no more lists inside lisp. so we're done
                break
            else:
                # get the single element lisp
                _active_dict[ith_node] = lisp[match.start():match.end()]
                # now replace that element with the node number
                # add 'n' to distinguish from arg value
                lisp = lisp.replace(_active_dict[ith_node], "%in" % ith_node)
                # increment to next node
                ith_node += 1

                if ith_node >= 10**3:
                    # very unlikely to have more than 1000 nodes...prob something went wrong
                    ezLogging.error("something went wrong")
                    break

        # now build the individual
        block_material = BlockMaterial(block_def.nickname)
        block_material.set_id(indiv_id)
        block_material.args = [None] * block_def.arg_count
        block_material.genome = [None] * block_def.genome_count
        block_material.genome[(
            -1 * block_def.input_count):] = ["InputPlaceholder"
                                             ] * block_def.input_count

        ith_active_node = -1
        args_used = []  # so we don't overwrite an arg we already used
        active_main_nodes = sorted(
            np.random.choice(range(block_def.main_count),
                             size=len(_active_dict),
                             replace=False))
        for node_index in range(block_def.main_count):
            if node_index in active_main_nodes:
                ith_active_node += 1
                # fill node with what we got from the lisp
                lisp = _active_dict[ith_active_node].strip('][').split(',')
                for ftn in block_def.operator_dict.keys():
                    if ftn.__name__ == lisp[0]:
                        # we matched our lisp ftn with entry in operatordict
                        input_index = []
                        arg_index = []
                        ith_input = -1
                        ith_arg = -1
                        # now grab what we have in the lisp and make sure they match
                        for val in lisp[
                                1:]:  # [1:] #ignores the ftn in 0th element
                            if val.endswith('n'):
                                # then it's a node index
                                ith_input += 1
                                extracted_val = int(
                                    val[:-1])  # [:-1] to remove 'n'
                                if extracted_val >= 0:
                                    # then it's a main node
                                    input_index.append(
                                        active_main_nodes[int(extracted_val)])
                                    # verify that the data types match
                                    incoming_dtype = block_def.get_node_dtype(
                                        block_material,
                                        node_index=input_index[ith_input],
                                        key='output')
                                    expected_dtype = block_def.operator_dict[
                                        ftn]["inputs"][ith_input]
                                    if incoming_dtype != expected_dtype:
                                        ezLogging.error(
                                            "error in genome seeding...mismatching incoming + given data types"
                                        )
                                        import pdb
                                        pdb.set_trace()
                                        return None
                                    else:
                                        # all good
                                        pass
                                else:
                                    # then it's an input node
                                    input_index.append(extracted_val)
                            else:
                                # then it's an arg value
                                ith_arg += 1
                                req_arg_type = block_def.operator_dict[ftn][
                                    "args"][ith_arg]
                                poss_arg_index = block_def.get_random_arg(
                                    req_arg_type, exclude=args_used)
                                if poss_arg_index is None:
                                    ezLogging.error(
                                        "can't find matching arg type in seeding"
                                    )
                                    import pdb
                                    pdb.set_trace()
                                    return None
                                arg_index.append(poss_arg_index)
                                args_used.append(poss_arg_index)
                                # have to convert val which is still a string to expected datatype!
                                # kinda hacky but should work
                                if 'float' in req_arg_type.__name__.lower():
                                    val = float(val)
                                elif 'int' in req_arg_type.__name__.lower():
                                    val = int(val)
                                elif 'bool' in req_arg_type.__name__.lower():
                                    val = bool(val)
                                else:
                                    pass
                                block_material.args[
                                    poss_arg_index] = req_arg_type(value=val)

                        block_material[node_index] = {
                            "ftn": ftn,
                            "inputs": input_index,
                            "args": arg_index
                        }
                        break
                    else:
                        # ftn doesn't match our lisp
                        continue
            else:
                # then this is not an active main node...just fill it normally then
                # copy paste from fill_nodes
                ftns = block_def.get_random_ftn(return_all=True)
                for ftn in ftns:
                    # find inputs
                    input_dtypes = block_def.operator_dict[ftn]["inputs"]
                    input_index = [None] * len(input_dtypes)
                    for ith_input, input_dtype in enumerate(input_dtypes):
                        input_index[ith_input] = block_def.get_random_input(
                            block_material,
                            req_dtype=input_dtype,
                            _max=node_index)
                    if None in input_index:
                        # failed to fill it in; try another ftn
                        continue
                    else:
                        pass
                    # find args
                    arg_dtypes = block_def.operator_dict[ftn]["args"]
                    arg_index = [None] * len(arg_dtypes)
                    for ith_arg, arg_dtype in enumerate(arg_dtypes):
                        arg_index[ith_arg] = block_def.get_random_arg(
                            req_dtype=arg_dtype)
                    if None in arg_index:
                        # failed to fill it in; try another ftn
                        continue
                    else:
                        pass
                    # all complete
                    block_material[node_index] = {
                        "ftn": ftn,
                        "inputs": input_index,
                        "args": arg_index
                    }
                    break
                # error check that node got filled
                if block_material[node_index] is None:
                    print(
                        "GENOME ERROR: no primitive was able to fit into current genome arrangment"
                    )
                    import pdb
                    pdb.set_trace()
                    return None

        # output node
        # currently only works for 1 output node
        block_material[block_def.main_count] = active_main_nodes[-1]

        # now finish filling in the args
        for arg_index, arg_type in enumerate(block_def.arg_types):
            if block_material.args[arg_index] is None:
                block_material.args[arg_index] = arg_type()
            else:
                continue

        block_def.get_actives(block_material)
        return block_material