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
 | 
					        return r
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    def serialize_subtree(self):
 | 
				
			||||||
 | 
					        return [n.serialize() for n in self.traverse()]
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    def node_score(self):
 | 
					    def node_score(self):
 | 
				
			||||||
        raise NotImplementedError()
 | 
					        raise NotImplementedError()
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
@ -781,8 +784,8 @@ class MixNode(RecipeTreeNode):
 | 
				
			|||||||
                #if c_grouped_mix[ia,ib] > 0 or c_grouped_mix[ib,ia] > 0:
 | 
					                #if c_grouped_mix[ia,ib] > 0 or c_grouped_mix[ib,ia] > 0:
 | 
				
			||||||
                #    s += 1
 | 
					                #    s += 1
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
                ia = m_mix._label_index[grouped_ing_a.to_json()]
 | 
					                ia = m_mix._label_index[ing_a.to_json()]
 | 
				
			||||||
                ib = m_mix._label_index[grouped_ing_b.to_json()]
 | 
					                ib = m_mix._label_index[ing_b.to_json()]
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
                if c_mix[ia,ib] > 0 or c_mix[ib,ia] > 0:
 | 
					                if c_mix[ia,ib] > 0 or c_mix[ib,ia] > 0:
 | 
				
			||||||
                    s += 1
 | 
					                    s += 1
 | 
				
			||||||
@ -1290,10 +1293,10 @@ class Tree(object):
 | 
				
			|||||||
                if node.name() in constant_ingredients:
 | 
					                if node.name() in constant_ingredients:
 | 
				
			||||||
                    node._constant = True
 | 
					                    node._constant = True
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        return Tree(root)
 | 
					        return Tree(root, main_ingredients)
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def from_serialization(s):
 | 
					    def from_serialization(s, main_ingredients = None):
 | 
				
			||||||
        def empty_node(raw_n):
 | 
					        def empty_node(raw_n):
 | 
				
			||||||
            if raw_n['type'] == "MixNode":
 | 
					            if raw_n['type'] == "MixNode":
 | 
				
			||||||
                node = MixNode(raw_n['constant'])
 | 
					                node = MixNode(raw_n['constant'])
 | 
				
			||||||
@ -1317,7 +1320,7 @@ class Tree(object):
 | 
				
			|||||||
            for c in childs:
 | 
					            for c in childs:
 | 
				
			||||||
                nodes[id].add_child(nodes[c])
 | 
					                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):
 | 
					    def __init__(self, root, main_ingredients=None):
 | 
				
			||||||
@ -1354,6 +1357,7 @@ class Tree(object):
 | 
				
			|||||||
    
 | 
					    
 | 
				
			||||||
    def collect_scores(self):
 | 
					    def collect_scores(self):
 | 
				
			||||||
        self._mix_scores = []
 | 
					        self._mix_scores = []
 | 
				
			||||||
 | 
					        self._mix_weights = []
 | 
				
			||||||
        self._act_scores = []
 | 
					        self._act_scores = []
 | 
				
			||||||
        self._ing_scores = []
 | 
					        self._ing_scores = []
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
@ -1366,6 +1370,7 @@ class Tree(object):
 | 
				
			|||||||
        for n in nodes:
 | 
					        for n in nodes:
 | 
				
			||||||
            if type(n) == MixNode:
 | 
					            if type(n) == MixNode:
 | 
				
			||||||
                self._mix_scores.append(n.node_score())
 | 
					                self._mix_scores.append(n.node_score())
 | 
				
			||||||
 | 
					                self._mix_weights.append(len(n.childs()))
 | 
				
			||||||
                self._n_mix_nodes += 1
 | 
					                self._n_mix_nodes += 1
 | 
				
			||||||
            if type(n) == ActionNode:
 | 
					            if type(n) == ActionNode:
 | 
				
			||||||
                self._act_scores.append(n.node_score())
 | 
					                self._act_scores.append(n.node_score())
 | 
				
			||||||
@ -1385,12 +1390,13 @@ class Tree(object):
 | 
				
			|||||||
                    seen_ingredients.add(n.name())
 | 
					                    seen_ingredients.add(n.name())
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        self._mix_scores = np.array(self._mix_scores)
 | 
					        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._act_scores = np.array(self._act_scores)
 | 
				
			||||||
        self._ing_scores = np.array(self._ing_scores)
 | 
					        self._ing_scores = np.array(self._ing_scores)
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    def mix_scores(self):
 | 
					    def mix_scores(self):
 | 
				
			||||||
        return self._mix_scores
 | 
					        return self._mix_scores, self._mix_weights
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    def action_scores(self):
 | 
					    def action_scores(self):
 | 
				
			||||||
        return self._act_scores
 | 
					        return self._act_scores
 | 
				
			||||||
@ -1426,11 +1432,11 @@ class Tree(object):
 | 
				
			|||||||
            return self._score
 | 
					            return self._score
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        self.collect_scores()
 | 
					        self.collect_scores()
 | 
				
			||||||
        s_mix = self.mix_scores()
 | 
					        s_mix, s_mix_weights = self.mix_scores()
 | 
				
			||||||
        s_act = self.action_scores()
 | 
					        s_act = self.action_scores()
 | 
				
			||||||
        s_ing = self.ing_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_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
 | 
					        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
 | 
					        sum_ing = np.sum(s_ing) if len(s_ing) > 0 else 0
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        self._touched = False
 | 
					        self._touched = False
 | 
				
			||||||
 | 
					        contains_main_ingred = True
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        # boost creativity
 | 
					        base_main_ings = [i._base_ingredient for i in self.root().traverse_ingredients()]
 | 
				
			||||||
        if len(s_act) < 3:
 | 
					        for ing in self._main_ingredients:
 | 
				
			||||||
            self._score = 0
 | 
					            if ing not in base_main_ings:
 | 
				
			||||||
        elif len(s_ing) < 3:
 | 
					                contains_main_ingred = False
 | 
				
			||||||
            self._score = 0
 | 
					                self._score = 0
 | 
				
			||||||
        else:        
 | 
					                break
 | 
				
			||||||
            self._score = (sum_mix + sum_act + sum_ing) / n
 | 
					        
 | 
				
			||||||
            self._score *= (len(s_ing) - self._n_duplicates) / len(s_ing)
 | 
					        if contains_main_ingred:
 | 
				
			||||||
            #self._score = 0.95 * self._score + 0.05 * self.main_ingredient_score()
 | 
					            # 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
 | 
					        return self._score
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    def copy(self):
 | 
					    def copy(self):
 | 
				
			||||||
        return Tree.from_serialization(self.serialize())
 | 
					        return Tree.from_serialization(self.serialize(), self._main_ingredients)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ## Population
 | 
					# ## Population
 | 
				
			||||||
@ -1494,8 +1513,59 @@ class Population(object):
 | 
				
			|||||||
        
 | 
					        
 | 
				
			||||||
        self.population = new_population
 | 
					        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):
 | 
					    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)
 | 
					        sorted_indices = np.argsort(-scores)
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
@ -1505,8 +1575,8 @@ class Population(object):
 | 
				
			|||||||
        avg_scores = []
 | 
					        avg_scores = []
 | 
				
			||||||
        for i in tqdm(range(n), desc="run evolutionary cycles"):
 | 
					        for i in tqdm(range(n), desc="run evolutionary cycles"):
 | 
				
			||||||
            self.mutate()
 | 
					            self.mutate()
 | 
				
			||||||
            #self.mutate()
 | 
					
 | 
				
			||||||
            #self.collect_scores()
 | 
					            self.crossover()
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            self.pairwise_competition()
 | 
					            self.pairwise_competition()
 | 
				
			||||||
            #self.collect_scores()
 | 
					            #self.collect_scores()
 | 
				
			||||||
@ -1530,17 +1600,13 @@ class Population(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# ## Run Evolutionary Algorithm
 | 
					# ## 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_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)
 | 
					#p.plot_population(n_best=20)
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user