preparing new evaluation method
This commit is contained in:
		
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -659,6 +659,9 @@ class RecipeTreeNode(object): | ||||
|          | ||||
|         return r | ||||
|      | ||||
|     def serialize_subtree(self): | ||||
|         return [n.serialize() for n in self.traverse()] | ||||
|      | ||||
|     def node_score(self): | ||||
|         raise NotImplementedError() | ||||
|          | ||||
| @ -781,8 +784,8 @@ class MixNode(RecipeTreeNode): | ||||
|                 #if c_grouped_mix[ia,ib] > 0 or c_grouped_mix[ib,ia] > 0: | ||||
|                 #    s += 1 | ||||
|                  | ||||
|                 ia = m_mix._label_index[grouped_ing_a.to_json()] | ||||
|                 ib = m_mix._label_index[grouped_ing_b.to_json()] | ||||
|                 ia = m_mix._label_index[ing_a.to_json()] | ||||
|                 ib = m_mix._label_index[ing_b.to_json()] | ||||
|                  | ||||
|                 if c_mix[ia,ib] > 0 or c_mix[ib,ia] > 0: | ||||
|                     s += 1 | ||||
| @ -1290,10 +1293,10 @@ class Tree(object): | ||||
|                 if node.name() in constant_ingredients: | ||||
|                     node._constant = True | ||||
|          | ||||
|         return Tree(root) | ||||
|         return Tree(root, main_ingredients) | ||||
|      | ||||
|     @staticmethod | ||||
|     def from_serialization(s): | ||||
|     def from_serialization(s, main_ingredients = None): | ||||
|         def empty_node(raw_n): | ||||
|             if raw_n['type'] == "MixNode": | ||||
|                 node = MixNode(raw_n['constant']) | ||||
| @ -1317,7 +1320,7 @@ class Tree(object): | ||||
|             for c in childs: | ||||
|                 nodes[id].add_child(nodes[c]) | ||||
|          | ||||
|         return Tree(nodes[s[0]['id']]) | ||||
|         return Tree(nodes[s[0]['id']], main_ingredients) | ||||
|              | ||||
|      | ||||
|     def __init__(self, root, main_ingredients=None): | ||||
| @ -1354,6 +1357,7 @@ class Tree(object): | ||||
|      | ||||
|     def collect_scores(self): | ||||
|         self._mix_scores = [] | ||||
|         self._mix_weights = [] | ||||
|         self._act_scores = [] | ||||
|         self._ing_scores = [] | ||||
|          | ||||
| @ -1366,6 +1370,7 @@ class Tree(object): | ||||
|         for n in nodes: | ||||
|             if type(n) == MixNode: | ||||
|                 self._mix_scores.append(n.node_score()) | ||||
|                 self._mix_weights.append(len(n.childs())) | ||||
|                 self._n_mix_nodes += 1 | ||||
|             if type(n) == ActionNode: | ||||
|                 self._act_scores.append(n.node_score()) | ||||
| @ -1385,12 +1390,13 @@ class Tree(object): | ||||
|                     seen_ingredients.add(n.name()) | ||||
|          | ||||
|         self._mix_scores = np.array(self._mix_scores) | ||||
|         self._mix_weights = np.array(self._mix_weights) | ||||
|         self._act_scores = np.array(self._act_scores) | ||||
|         self._ing_scores = np.array(self._ing_scores) | ||||
|          | ||||
|      | ||||
|     def mix_scores(self): | ||||
|         return self._mix_scores | ||||
|         return self._mix_scores, self._mix_weights | ||||
|      | ||||
|     def action_scores(self): | ||||
|         return self._act_scores | ||||
| @ -1426,11 +1432,11 @@ class Tree(object): | ||||
|             return self._score | ||||
|          | ||||
|         self.collect_scores() | ||||
|         s_mix = self.mix_scores() | ||||
|         s_mix, s_mix_weights = self.mix_scores() | ||||
|         s_act = self.action_scores() | ||||
|         s_ing = self.ing_scores() | ||||
|          | ||||
|         n = len(s_mix) + len(s_act) + len(s_ing) | ||||
|         #n = len(s_mix) + len(s_act) + len(s_ing) | ||||
|          | ||||
|         avg_mix = np.average(s_mix) if len(s_mix) > 0 else 1 | ||||
|         avg_act = np.average(s_act) if len(s_act) > 0 else 1 | ||||
| @ -1441,21 +1447,34 @@ class Tree(object): | ||||
|         sum_ing = np.sum(s_ing) if len(s_ing) > 0 else 0 | ||||
|          | ||||
|         self._touched = False | ||||
|         contains_main_ingred = True | ||||
|          | ||||
|         # boost creativity | ||||
|         if len(s_act) < 3: | ||||
|             self._score = 0 | ||||
|         elif len(s_ing) < 3: | ||||
|             self._score = 0 | ||||
|         else:         | ||||
|             self._score = (sum_mix + sum_act + sum_ing) / n | ||||
|             self._score *= (len(s_ing) - self._n_duplicates) / len(s_ing) | ||||
|             #self._score = 0.95 * self._score + 0.05 * self.main_ingredient_score() | ||||
|         base_main_ings = [i._base_ingredient for i in self.root().traverse_ingredients()] | ||||
|         for ing in self._main_ingredients: | ||||
|             if ing not in base_main_ings: | ||||
|                 contains_main_ingred = False | ||||
|                 self._score = 0 | ||||
|                 break | ||||
|          | ||||
|         if contains_main_ingred: | ||||
|             # boost creativity | ||||
|             if len(s_act) < 3: | ||||
|                 self._score = 0 | ||||
|             elif len(s_ing) < 3: | ||||
|                 self._score = 0 | ||||
|             else: | ||||
|                 weighted_mix_score = np.array([s_mix[i] * s_mix_weights[i] for i in range(len(s_mix))]) | ||||
|                 #print(weighted_mix_score) | ||||
|                 n = len(s_act) + len(s_ing) + np.sum(s_mix_weights) | ||||
|                 self._score = (np.sum(weighted_mix_score) + sum_act + sum_ing) / n | ||||
|                 #print(self._score) | ||||
|                 self._score *= (len(s_ing) - self._n_duplicates) / len(s_ing) | ||||
|                 #self._score = 0.95 * self._score + 0.05 * self.main_ingredient_score() | ||||
|  | ||||
|         return self._score | ||||
|      | ||||
|     def copy(self): | ||||
|         return Tree.from_serialization(self.serialize()) | ||||
|         return Tree.from_serialization(self.serialize(), self._main_ingredients) | ||||
|  | ||||
|  | ||||
| # ## Population | ||||
| @ -1494,8 +1513,59 @@ class Population(object): | ||||
|          | ||||
|         self.population = new_population | ||||
|      | ||||
|     def crossover(self): | ||||
|         # shuffle indices | ||||
|         indices = list(range(len(self.population) // 2)) | ||||
|         indices = [i + len(self.population) // 2 for i in indices] | ||||
|         random.shuffle(indices) | ||||
|          | ||||
|         # perform crossover for random pairs | ||||
|         for i in range(len(self.population) // 4): | ||||
|             i_a = indices[2*i] | ||||
|             i_b = indices[2*i+1] | ||||
|              | ||||
|             self.pairwise_crossover(self.population[i_a], self.population[i_b]) | ||||
|          | ||||
|      | ||||
|     def pairwise_crossover(self, tree_a, tree_b): | ||||
|         # for crossover: find a random subtree in both trees, and switch them | ||||
|          | ||||
|         # first, select one random mix node from both | ||||
|         a_nodes = tree_a.root().traverse() | ||||
|         b_nodes = tree_b.root().traverse() | ||||
|          | ||||
|         a_mix_nodes = [] | ||||
|         b_mix_nodes = [] | ||||
|          | ||||
|         for n in a_nodes: | ||||
|             if type(n) == MixNode: | ||||
|                 a_mix_nodes.append(n) | ||||
|          | ||||
|         for n in b_nodes: | ||||
|             if type(n) == MixNode: | ||||
|                 b_mix_nodes.append(n) | ||||
|          | ||||
|         a_mix_node = np.random.choice(a_mix_nodes) | ||||
|         b_mix_node = np.random.choice(b_mix_nodes) | ||||
|          | ||||
|         # now select one random child, we will switch the subtrees there | ||||
|         a_child = np.random.choice(list(a_mix_node.childs())) | ||||
|         b_child = np.random.choice(list(b_mix_node.childs())) | ||||
|          | ||||
|         # ...and perform the switch | ||||
|          | ||||
|         # manually remove references | ||||
|         a_mix_node.remove_child(a_child) | ||||
|         b_mix_node.remove_child(b_child) | ||||
|          | ||||
|         # and add child to other subtree | ||||
|         a_mix_node.add_child(b_child) | ||||
|         b_mix_node.add_child(a_child) | ||||
|          | ||||
|          | ||||
|      | ||||
|     def hold_best(self, n=10): | ||||
|         scores = [tree.score() for tree in self.population] | ||||
|         scores = np.array([tree.score() for tree in self.population]) | ||||
|          | ||||
|         sorted_indices = np.argsort(-scores) | ||||
|          | ||||
| @ -1505,8 +1575,8 @@ class Population(object): | ||||
|         avg_scores = [] | ||||
|         for i in tqdm(range(n), desc="run evolutionary cycles"): | ||||
|             self.mutate() | ||||
|             #self.mutate() | ||||
|             #self.collect_scores() | ||||
|  | ||||
|             self.crossover() | ||||
|              | ||||
|             self.pairwise_competition() | ||||
|             #self.collect_scores() | ||||
| @ -1530,17 +1600,13 @@ class Population(object): | ||||
|  | ||||
| # ## Run Evolutionary Algorithm | ||||
|  | ||||
| #p = Population(["noodle"],['noodle'], min_additional=4, max_additional=13, n_population = 50) | ||||
| p = Population(["noodle"],['noodle'], min_additional=4, max_additional=13, n_population = 50, mutations=1) | ||||
|  | ||||
|  | ||||
| #p_ingredient_unprepared(list(p.population[0].root().childs())[0]._name) < 0.2 | ||||
|  | ||||
|  | ||||
| #p.run(50) | ||||
| #avg = p.run(10) | ||||
|  | ||||
|  | ||||
| #p.plot_population(n_best=20) | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user