preparing new evaluation method
This commit is contained in:
parent
006bf59eb0
commit
7d6d835a01
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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user