def get_closest_wrapped(self, vector, *args, **kwargs): if not self.trees: value = random.choice(vector) return [gp.Terminal(value, False, float)], [value] * len(vector) if not numpy.all(numpy.isfinite(vector)): max_height = kwargs.get("max_height", numpy.inf) num_trees = len(self.trees) if max_height >= len( self.height_levels) else self.height_levels[max_height] tree_index = random.randrange(num_trees) return self.trees[tree_index][:], self.semantic_array[tree_index] if is_constant(vector): return [gp.Terminal(vector[0], False, float)], [vector[0]] * len(vector) return get_closest_func(self, vector, *args, **kwargs)
def get_closest(self, vector, distance_measure, max_height=numpy.inf, k=1, check_constant=False, constant_prob=1.0): if max_height >= len(self.height_levels): dists = distance_measure(self.semantic_array, vector, axis=1) else: dists = distance_measure( self.semantic_array[:self.height_levels[max_height]], vector, axis=1) if 1 < k < len(dists): indices = numpy.argpartition(dists, k) min_distance_index = numpy.random.choice(indices[:k]) else: min_distance_index = numpy.nanargmin(dists) if check_constant and random.random() < constant_prob: constant = numpy.median(vector).item() constant_distance = distance_measure(vector, constant) if constant_distance < dists[min_distance_index]: return [gp.Terminal(constant, False, float)], [constant] * len(vector) return self.trees[min_distance_index][:], self.semantic_array[ min_distance_index]
def get_closest_direction(self, vector, distance_measure, max_height=numpy.inf, k=1, check_constant=False): unit_vector = calc_unit_vector(vector) if max_height > len(self.height_levels): dot_products = numpy.dot(self.unit_semantic_array, unit_vector) else: dot_products = numpy.dot( self.unit_semantic_array[:self.height_levels[max_height]], unit_vector) if k > 1: indices = numpy.argpartition(dot_products, -k) index = numpy.random.choice(indices[-k:]) else: index = numpy.nanargmax(dot_products) print numpy.arccos(dot_products[index]) print unit_vector print self.unit_semantic_array[index] if check_constant: distance = distance_measure(self.semantic_array[index], vector) constant = numpy.median(vector).item() constant_distance = distance_measure(vector, constant) if constant_distance < distance: return [gp.Terminal(constant, False, float)], [constant] * len(vector) return self.trees[index][:], self.semantic_array[index]
def simplify_constant_semantics(population, toolbox, semantics_threshold=0.01, size_threshold=0, precompute_semantics=False): for ind in population: if len(ind) < size_threshold: continue if precompute_semantics: ind.semantics = toolbox.calc_semantics(ind) removed = bitarray(len(ind)) removed.setall(False) num_nodes_removed = 0 for subtree_semantics in ind.semantics: subtree_index = subtree_semantics.node_index subtree_size = subtree_semantics.tree_size if subtree_size > 1 and not removed[subtree_index]: min_value = numpy.max(subtree_semantics).item() max_value = numpy.min(subtree_semantics).item() if abs(max_value - min_value) < semantics_threshold: new_const = random.uniform(min_value, max_value) slice_begin = -num_nodes_removed + subtree_index slice_end = slice_begin + subtree_size ind[slice_begin:slice_end] = [ gp.Terminal(new_const, True, float) ] removed[subtree_index:subtree_index + subtree_size] = True num_nodes_removed += subtree_size - 1
def sgx(ind1, ind2, pset, creatorIndividual): for op in pset.primitives[pset.ret]: if op.name == "add": pAdd = op elif op.name == "subtract": pSub = op elif op.name == "multiply": pMul = op term1 = gp.Terminal(1, True, pset.ret) rand_ = gp.Terminal(random.random(), True, pset.ret) expr1, expr2 = [], [] expr1.extend((pAdd, pMul, rand_)), expr2.extend((pAdd, pMul, rand_)) expr1.extend(ind1), expr2.extend(ind2) expr1.extend((pMul, pSub, term1, rand_)), expr2.extend( (pMul, pSub, term1, rand_)) expr1.extend(ind2), expr2.extend(ind1) return creatorIndividual(expr1), creatorIndividual(expr2)
def test_primitive_sequence_to_expression_string_wrong_length(self): primitive_sequence = [ gp.Primitive('add', args=(int, int), ret=int), gp.Terminal('x', symbolic=True, ret=None), ] with self.assertRaisesRegex( ValueError, r'The length of sequence should be 1 \+ 2 \* n, but got 2'): evolutionary.primitive_sequence_to_expression_string( primitive_sequence)
def test_primitive_sequence_to_expression_string(self): # add # / \ # x mul # / \ # sub y # / \ # a b primitive_sequence = [ gp.Primitive('add', args=(int, int), ret=int), gp.Terminal('x', symbolic=True, ret=None), gp.Primitive('mul', args=(int, int), ret=int), gp.Primitive('sub', args=(int, int), ret=int), # Whether symbolic is True or False does not matter. gp.Terminal(1, symbolic=True, ret=None), gp.Terminal(2, symbolic=False, ret=None), gp.Terminal('y', symbolic=True, ret=None), ] self.assertEqual( evolutionary.primitive_sequence_to_expression_string( primitive_sequence), '( x + ( ( 1 - 2 ) * y ) )')
def get_closest_direction_scaled(self, vector, distance_measure, pset, max_height=numpy.inf, k=1, check_constant=False): unit_vector, vector_norm = calc_unit_vector_norm(vector) if max_height > len(self.height_levels): dot_products = numpy.dot(self.unit_semantic_array, unit_vector) else: dot_products = numpy.dot( self.unit_semantic_array[:self.height_levels[max_height]], unit_vector) if k > 1: indices = numpy.argpartition(dot_products, -k) index = numpy.random.choice(indices[-k:]) else: index = numpy.nanargmax(dot_products) best_tree = self.trees[index] best_tree_semantics = self.semantic_array[index] best_tree_norm = numpy.sqrt( best_tree_semantics.dot(best_tree_semantics)) constant_value = round( (vector_norm * dot_products[index]) / best_tree_norm, 3) if check_constant: distance = distance_measure( self.semantic_array[index] * constant_value, vector) constant = numpy.median(vector).item() constant_distance = distance_measure(vector, constant) if constant_distance < distance: return [gp.Terminal(constant, False, float)], [constant] * len(vector) constant_terminal = gp.Terminal(constant_value, False, float) return [pset.mapping["multiply"], constant_terminal ] + best_tree[:], self.semantic_array[index] * constant_value
def _generate_terminal(arg_type, scope, pset): """ Generate a terminal value. :param arg_type: The type of argument to generate. :param scope: The scope in which to generate the terminal. :param pset: The primitive set to generate from. :return: The generated terminal. """ var = [ gp.Terminal(name, True, type) for name, type in scope.items() if issubclass(type, arg_type) ] return random.choice(pset.terminals[arg_type] + var)
def get_closest_inconsistencies(self, vector, distance_measure, max_height=numpy.inf, check_constant=False, constant_prob=1.0): num_trees = len(self.trees) if max_height >= len( self.height_levels) else self.height_levels[max_height] consistent_indices = ~numpy.isnan(vector) if not numpy.any(consistent_indices): tree_index = random.randrange(num_trees) return self.trees[tree_index][:], self.semantic_array[tree_index] consistent_vector = vector[consistent_indices] if not numpy.all(numpy.isfinite(consistent_vector)): tree_index = random.randrange(num_trees) return self.trees[tree_index][:], self.semantic_array[tree_index] if is_constant(consistent_vector): return [gp.Terminal(consistent_vector[0], False, float)], [consistent_vector[0]] * len(vector) dists = distance_measure(self.semantic_array[:num_trees, consistent_indices], consistent_vector, axis=1) min_distance_index = numpy.nanargmin(dists) if check_constant and random.random() < constant_prob: constant = numpy.median(consistent_vector).item() constant_distance = distance_measure(consistent_vector, constant) if constant_distance < dists[min_distance_index]: return [gp.Terminal(constant, False, float)], [constant] * len(vector) return self.trees[min_distance_index][:], self.semantic_array[ min_distance_index]
def mutNodeReplacement(individual, pset): """ Replace a randomly chosen primitive from *individual* by a randomly chosen primitive with the same number of arguments from the `pset`. attribute of the individual. :param individual: The normal or typed tree to be mutated. :returns: A tuple of one tree. """ if len(individual) < 2: return individual, index = random.randrange(1, len(individual)) node = individual[index] if node.arity == 0: # Terminal terms = pset.terminals[node.ret] var = list([ name for name, type in _find_in_scope(individual, index).items() if issubclass(type, node.ret) ]) choice = len(terms) + len(var) # If there is no replacement available: abort if choice <= 0: return individual, i = random.randrange(choice) if i < len(terms): term = random.choice(terms) else: term = gp.Terminal(random.choice(var), True, node.ret) # Fix for ephemeral constants if term.arity != 0: term.arity = 0 individual[index] = term elif node.name not in {'set/2', 'return/1'}: # Prevent replacement of set and return calls due to their order sensitivity prims = [ p for p in pset.primitives[node.ret] if _can_substitute_call(node, p) ] # Make sure that a replacement is available if prims: individual[index] = random.choice(prims) return individual,
def from_string(cls, string, pset): """Try to convert a string expression into a PrimitiveTree given a PrimitiveSet *pset*. The primitive set needs to contain every primitive present in the expression. :param string: String representation of a Python expression. :param pset: Primitive set from which primitives are selected. :returns: PrimitiveTree populated with the deserialized primitives. """ tokens = re.split("[ \t\n\r\f\v(),]", string) expr = [] ret_types = deque() for token in tokens: if token == '': continue if len(ret_types) != 0: type_ = ret_types.popleft() else: type_ = None if token in pset.mapping: primitive = pset.mapping[token] if len(ret_types) != 0 and primitive.ret != type_: raise TypeError("Primitive {} return type {} does not " "match the expected one: {}.".format( primitive, primitive.ret, type_)) expr.append(primitive) if isinstance(primitive, gp.Primitive): ret_types.extendleft(reversed(primitive.args)) else: try: token = eval(token) except NameError: raise TypeError( "Unable to evaluate terminal: {}.".format(token)) if type_ is None: type_ = type(token) if type(token) != type_: raise TypeError("Terminal {} type {} does not " "match the expected one: {}.".format( token, type(token), type_)) expr.append(gp.Terminal(token, False, type_)) return cls(expr)
def librarySearch(library, pset, sm, metric, *forbidden): """Library Search: a library of known programs is searched for a programs p' that minimizes the semantic distance to sm. Pawlak, T. P., & Krawiec, K. (2017). Competent Geometric Semantic Genetic Programming for Symbolic Regression and Boolean Function Synthesis. Evolutionary Computation, (x), 1–36. https://doi.org/doi:10.1162/EVCO_a_00205 :param library: First expression participating :param sm: desired semantic :metric: metric to evaluete distance :returns: the closest item to desired from library """ minDistLib = float("inf") minDistERC = float("inf") nInfac = np.logical_not(np.logical_or(np.isnan(sm), np.isinf(sm))) itens, values = library if sum(nInfac) == 0: return random.choice(itens) for idx, pred in enumerate(values): isForbidden = False itemValue = np.array(pred) dist = metric(itemValue[nInfac], sm[nInfac]) if dist <= minDistLib: for f in forbidden: fValue = np.array(f) if np.array_equal(itemValue[nInfac], fValue[nInfac]): isForbidden = True break if not (isForbidden): pLib = itens[idx] minDistLib = dist for value in np.linspace(-10**3, 10**3, 200): ercValue = value * np.ones(sm.shape) dist = metric(ercValue[nInfac], sm[nInfac]) if dist <= minDistERC: for f in forbidden: fValue = np.array(f) if np.array_equal(ercValue[nInfac], fValue[nInfac]): isForbidden = True break if not (isForbidden): pErc = [gp.Terminal(value, True, pset.ret)] minDistERC = dist if minDistERC < minDistLib: p = pErc else: p = pLib return p
def sgm(individual, step, pset, creatorIndividual, toolbox): for op in pset.primitives[pset.ret]: if op.name == "add": pAdd = op elif op.name == "subtract": pSub = op elif op.name == "multiply": pMul = op st1expr = toolbox.expr_mut(pset=pset) st2expr = toolbox.expr_mut(pset=pset) stepExpr = gp.Terminal(step, True, pset.ret) expr = [] expr.extend((pAdd, pMul, stepExpr, pSub)) expr.extend(st1expr) expr.extend(st2expr) expr.extend(individual) return creatorIndividual(expr),
def from_string(cls, string, pset): """Try to convert a string expression into a PrimitiveTree given a PrimitiveSet *pset*. The primitive set needs to contain every primitive present in the expression. :param string: String representation of a Python expression. :param pset: Primitive set from which primitives are selected. :returns: PrimitiveTree populated with the deserialized primitives. """ tokens = re.split("[ \t\n\r\f\v(),]", string) expr = [] def get_parts(token_string): parts = tokens[i].split('_') return parts[1], parts[2], parts[3] i = 0 while i < len(tokens): if tokens[i] == '': i += 1 continue if tokens[i] in pset.mapping: primitive = pset.mapping[tokens[i]] expr.append(primitive) elif RangeOperationTerminal.NAME in tokens[i]: operation, begin_range_name, end_range_name = get_parts(tokens[i]) range_operation_terminal = RangeOperationTerminal() range_operation_terminal.initialize_parameters(pset.variable_type_indices, pset.variable_names, operation, begin_range_name, end_range_name) expr.append(range_operation_terminal) elif MomentFindingTerminal.NAME in tokens[i]: operation, begin_range_name, end_range_name = get_parts(tokens[i]) moment_operation_terminal = MomentFindingTerminal() moment_operation_terminal.initialize_parameters(pset.variable_type_indices, pset.variable_names, operation, begin_range_name, end_range_name) expr.append(moment_operation_terminal) else: try: token = eval(tokens[i]) except NameError: raise TypeError("Unable to evaluate terminal: {}.".format(tokens[i])) expr.append(gp.Terminal(token, False, gp.__type__)) i += 1 return cls(expr)
def mutShrink(individual): """ Mutate the tree by randomly selecting and deleting a subtree of the tree, replacing them with the unit value of their return type. :param individual: The tree to mutate. """ index = random.randrange(len(individual)) prim = individual[index] slice_ = individual.searchSubtree(index) name = prim.name.split('/')[0] # In case the statement is an assignment (set), then set the right hand side to the default terminal of the same # type to prevent undefined variable errors if name == 'set': ret_type = individual[index + 2].ret slice_ = individual.searchSubtree(index + 2) del individual[slice_] if ret_type == shader.Float: node = gp.Terminal(0.0, False, shader.Float) elif ret_type == shader.Bool: node = gp.Terminal(False, False, shader.Bool) else: node = gp.Terminal('void', False, shader.Unit) individual.insert(index + 2, node) elif prim.ret == shader.Float: node = gp.Terminal(0.0, False, shader.Float) del individual[slice_] individual.insert(index, node) elif prim.ret == shader.Bool: node = gp.Terminal(False, False, shader.Bool) del individual[slice_] individual.insert(index, node) elif prim.ret == shader.Unit: node = gp.Terminal('void', False, shader.Unit) del individual[slice_] individual.insert(index, node) return individual,
def _literal(value, type): return gp.Terminal(value, False, type)
def _var(name, type): return gp.Terminal(name, True, type)
def _id(name): return gp.Terminal(name, True, Id)
def from_string(cls, string, pset, nparams): """Try to convert a string expression into a PrimitiveTree given a PrimitiveSet *pset*. The primitive set needs to contain every primitive present in the expression. :param string: String representation of a Python expression. :param pset: Primitive set from which primitives are selected. :returns: PrimitiveTree populated with the deserialized primitives. """ tokens = re.split("[ \t\n\r\f\v()\[\],]", string.replace('array', ',')) expr = [] ret_types = deque() def consume(iterator, n): '''Advance the iterator n-steps ahead. If n is none, consume entirely.''' deque(itertools.islice(iterator, n), maxlen=0) iterator = range(len(tokens)).__iter__() for i in iterator: token = tokens[i] if token == '': continue if len(ret_types) != 0: type_ = ret_types.popleft() else: type_ = None if token in pset.mapping: primitive = pset.mapping[token] if type_ is not None and not issubclass(primitive.ret, type_): raise TypeError("Primitive {} return type {} does not " "match the expected one: {}.".format( primitive, primitive.ret, type_)) expr.append(primitive) if isinstance(primitive, gp.Primitive): ret_types.extendleft(reversed(primitive.args)) else: try: x = eval("parametrized_terminals.{}".format(token)) parameters = [] num_params = nparams count = 0 while len(parameters) < num_params: if tokens[i + 1] not in ['', ',', '']: parameters.append(float(tokens[i + 1])) i += 1 count += 1 y = x() y.set_params(*parameters) expr.append(y) consume(iterator, count) except SyntaxError: try: token = eval(token) except NameError: raise TypeError( "Unable to evaluate terminal: {}.".format(token)) if type_ is None: type_ = type(token) if not issubclass(type(token), type_): raise TypeError("Terminal {} type {} does not " "match the expected one: {}.".format( token, type(token), type_)) expr.append(gp.Terminal(token, False, type_)) return cls(expr)
class EvolutionaryTest(parameterized.TestCase): def setUp(self): super(EvolutionaryTest, self).setUp() self.pset = evolutionary.get_univariate_one_constant_primitives_set() @parameterized.parameters( ('( 1 + x )', True), (gp.Terminal('x', symbolic=True, ret=None), True), (gp.Primitive('c', args=(), ret=None), True), (gp.Primitive('add', args=(int, int), ret=int), False), ) def test_is_terminal(self, node, expected): self.assertEqual(evolutionary.is_terminal(node), expected) @parameterized.parameters( (gp.Primitive('add', args=(int, int), ret=int), gp.Terminal('x', symbolic=True, ret=None), gp.Terminal('y', symbolic=True, ret=None), '( x + y )'), (gp.Primitive('add', args=(int, int), ret=int), gp.Primitive('add', args=(int, int), ret=int), gp.Terminal('y', symbolic=True, ret=None), None), (gp.Primitive('add', args=(int, int), ret=int), gp.Terminal('x', symbolic=True, ret=None), gp.Primitive('add', args=(int, int), ret=int), None), ) def test_combine_nodes(self, node0, node1, node2, expected): self.assertEqual(evolutionary.combine_nodes(node0, node1, node2), expected) def test_primitive_sequence_to_expression_string(self): # add # / \ # x mul # / \ # sub y # / \ # a b primitive_sequence = [ gp.Primitive('add', args=(int, int), ret=int), gp.Terminal('x', symbolic=True, ret=None), gp.Primitive('mul', args=(int, int), ret=int), gp.Primitive('sub', args=(int, int), ret=int), # Whether symbolic is True or False does not matter. gp.Terminal(1, symbolic=True, ret=None), gp.Terminal(2, symbolic=False, ret=None), gp.Terminal('y', symbolic=True, ret=None), ] self.assertEqual( evolutionary.primitive_sequence_to_expression_string( primitive_sequence), '( x + ( ( 1 - 2 ) * y ) )') def test_primitive_sequence_to_expression_string_constant(self): primitive_sequence = [gp.Terminal('ARG0', symbolic=True, ret=None)] self.assertEqual( evolutionary.primitive_sequence_to_expression_string( primitive_sequence), 'x') def test_primitive_sequence_to_expression_string_wrong_length(self): primitive_sequence = [ gp.Primitive('add', args=(int, int), ret=int), gp.Terminal('x', symbolic=True, ret=None), ] with self.assertRaisesRegex( ValueError, r'The length of sequence should be 1 \+ 2 \* n, but got 2'): evolutionary.primitive_sequence_to_expression_string( primitive_sequence) def test_evolutionary_algorithm_with_num_evals_limit(self): evolutionary.set_creator() toolbox = evolutionary.get_toolbox(pset=self.pset, max_height=50) toolbox.register('evaluate', evolutionary.evaluate_individual, input_values=np.array([1., 2., 3.]), output_values=np.array([2., 3., 4.]), toolbox=toolbox) population = toolbox.population(n=10) halloffame = tools.HallOfFame(1) evolutionary.evolutionary_algorithm_with_num_evals_limit( population=population, toolbox=toolbox, cxpb=0.5, mutpb=0.1, num_evals_limit=500, halloffame=halloffame) func = toolbox.compile(expr=halloffame[0]) np.testing.assert_allclose(func(np.array([5., 6., 7.])), [6., 7., 8.]) @parameterized.parameters( (None, None, None, False), (0, 1, None, True), (0, 1, 50., True), ) def test_search_expression(self, leading_at_0, leading_at_inf, hard_penalty_default_value, include_leading_powers): # Test search several expressions. evolutionary.set_creator() evolutionary.search_expression( input_values=np.array([1., 2., 3.]), output_values=np.array([2., 3., 4.]), pset=self.pset, max_height=50, population_size=10, cxpb=0.5, mutpb=0.1, num_evals_limit=30, leading_at_0=leading_at_0, leading_at_inf=leading_at_inf, hard_penalty_default_value=hard_penalty_default_value, include_leading_powers=include_leading_powers, default_value=50.) evolutionary.search_expression( input_values=np.array([1., 2., 3.]), output_values=np.array([1., 4., 9.]), pset=self.pset, max_height=50, population_size=10, cxpb=0.5, mutpb=0.1, num_evals_limit=30, leading_at_0=leading_at_0, leading_at_inf=leading_at_inf, hard_penalty_default_value=hard_penalty_default_value, include_leading_powers=include_leading_powers, default_value=50.)
def test_primitive_sequence_to_expression_string_constant(self): primitive_sequence = [gp.Terminal('ARG0', symbolic=True, ret=None)] self.assertEqual( evolutionary.primitive_sequence_to_expression_string( primitive_sequence), 'x')