def __init__(self, model, **settings): O.__init__(self) self.model = model self.settings = default().update(**settings) self.de = DE(model, gens = self.settings.k1) self.mutator = Mutator(model.get_tree())
class Star1(O): def __init__(self, model, **settings): O.__init__(self) self.model = model self.settings = default().update(**settings) self.de = DE(model, gens = self.settings.k1) self.mutator = Mutator(model.get_tree()) # def sample(self, sub_folder): # stat = self.de.run() # self.to_csv(stat, "csv/"+sub_folder+"/"+self.model.get_tree().name+".csv") # stat.settings.gen_step = self.settings.gen_step # stat.tiles() # population = set() # for point in stat.generations[0]: # population.add(point) # for point in stat.generations[-1]: # population.add(point) # best_size = int(len(population) * self.settings.best_percent/100) # best = sel_nsga2(self.model, list(population), best_size) # rest = population - set(best) # return best, list(rest) def sample(self, sub_folder): stat = self.de.run() self.to_csv(stat, "csv/"+sub_folder+"/"+self.model.get_tree().name+".csv") stat.settings.gen_step = self.settings.gen_step stat.tiles() best = set() population = set() for point in stat.generations[0]: population.add(point) for point in stat.generations[-1]: population.add(point) for obj_index in range(len(self.de.settings.better)): sorted_pop = sorted(list(population), key=lambda x: x.objectives[obj_index], reverse=True)[:len(stat.generations[-1])//5] best.update(sorted_pop) rest = population - best return list(best), list(rest) def rank(self, best, rest): best_size = len(best) rest_size = len(rest) p_best = best_size / (best_size + rest_size) p_rest = rest_size / (best_size + rest_size) decisions = [] for dec_node in self.model.bases: f_best, pos_count, neg_count = 0, 0, 0 for point in best: if point.decisions[dec_node.id] > 0: pos_count += 1 elif point.decisions[dec_node.id] < 0: neg_count += 1 f_pos_best = pos_count / best_size l_pos_best = f_pos_best * p_best f_neg_best = neg_count / best_size l_neg_best = f_neg_best * p_best f_pos_rest, f_neg_rest = 0, 0 for point in rest: if point.decisions[dec_node.id] > 0: f_pos_rest += 1 else: f_neg_rest += 1 f_pos_rest /= rest_size f_neg_rest /= rest_size l_pos_rest = f_pos_rest * p_rest l_neg_rest = f_neg_rest * p_rest if l_pos_best == 0 and l_pos_rest == 0: sup_pos = 0 else: sup_pos = l_pos_best ** 2 / (l_pos_best + l_pos_rest) if l_neg_best == 0 and l_neg_rest == 0: sup_neg = 0 else: sup_neg = l_neg_best ** 2 / (l_neg_best + l_neg_rest) decisions.append(Decision(id = dec_node.id, name = dec_node.name, support=sup_pos, value = 1, type = dec_node.type, container=dec_node.container, cost = dec_node.base_cost, benefit = dec_node.base_benefit)) decisions.append(Decision(id = dec_node.id, name = dec_node.name, support=sup_neg, value = -1, type = dec_node.type, container=dec_node.container, cost = dec_node.base_cost, benefit = dec_node.base_benefit)) decisions.sort(key=lambda x:x.support, reverse=True) sorted_decs = [] aux = set() for dec in decisions: if dec.id not in aux: sorted_decs.append(dec) aux.add(dec.id) assert len(sorted_decs) == len(self.model.bases), "Mismatch after sorting support" return sorted_decs def generate(self, presets = None, check_validity = False): population = list() while len(population) < self.settings.k2: point = Point(self.mutator.generate()) if not point in population: for preset in presets: point.decisions[preset.id] = preset.value if check_validity: self.model.reset_nodes(point.decisions) self.model.eval(self.model.get_tree().root) if self.model.get_tree().root.value != 1: continue population.append(point) return population @staticmethod def objective_stats(generations): stats = [] obj_len = len(generations[0][0].objectives) objective_map = {} for i in range(obj_len): objectives = [] data_map = {} meds = [] iqrs = [] for gen, pop in enumerate(generations): objs = [pt.objectives[i] for pt in pop] objectives.append(objs) med, iqr = median_iqr(objs) meds.append(med) iqrs.append(iqr) objective_map[i] = objectives data_map["meds"] = meds data_map["iqrs"] = iqrs stats.append(data_map) return stats, objective_map def evaluate(self, point, decisions): model = self.model if not point.objectives: model.reset_nodes(point.decisions) self.model.eval(self.model.get_tree().root) point.objectives = self.model.get_tree().evaluate(model, point) point.objectives.append(sum(decision.cost for decision in decisions if decision.value > 0)) point._nodes = [node.clone() for node in model.get_tree().nodes.values()] point.objectives = [0 if one is None else one for one in point.objectives] return point.objectives def prune(self, support, check_validity): gens = [] for i in range(len(support)): decisions = support[:i] population = self.generate(decisions, check_validity=check_validity) for point in population: self.evaluate(point, decisions) gens.append(population) obj_stats, objective_map = self.objective_stats(gens) return obj_stats, gens, objective_map def report(self, stats, sub_folder, fig_name): #headers = [obj.__name__.split("_")[-1] for obj in self.de.settings.obj_funcs] headers = ["root cost", "root benefit", "softgoals", "preset decisions cost"] headers = ["root cost", "root benefit", "softgoals"] med_spread_plot(stats, headers, fig_name="img/"+sub_folder+"/"+fig_name+".png") return "img/"+sub_folder+"/"+fig_name+".png" def to_csv(self, stats, fname): directory = fname.rsplit("/", 1)[0] mkdir(directory) last_gen = sorted(stats.generations[-1], key=lambda x:x.objectives[1]-x.objectives[0], reverse=True) self.plot_objectives(last_gen, directory) ids = self.model.get_tree().nodes.keys() names = [self.model.get_tree().nodes[key].name for key in ids] + ["?cost", "?benefit", "?softgoals"] table = [names] max_cost, max_benefit = -1, -1 for point in last_gen: row = [point.get_nodes()[key].value for key in ids] + point.objectives max_cost = max(point.objectives[0], max_cost) max_benefit = max(point.objectives[1], max_benefit) table.append(row) with open(fname, "wb") as file_obj: writer = csv.writer(file_obj) writer.writerows(table) def plot_objectives(self, points, directory): directory = directory.replace("csv/", "img/") objectives = [] for point in points: dec_lens = sum([1 if dec == 1 else 0 for dec in point.decisions.values()]) obj = [dec_lens] for o in point.objectives[:2]: obj.append(o) objectives.append(obj) zipped = zip(*objectives) x = zipped[0] costs = zipped[1] benefits = zipped[2] tree_name = self.model.get_tree().name mkdir(directory) point_plot(x, {"cost":costs}, ['ro'], "%s/%s_costs.png"%(directory, tree_name)) point_plot(x, {"benefit":benefits}, ['bx'], "%s/%s_benefits.png"%(directory, tree_name)) point_plot_3d(x, costs, benefits, 'r', 'x', "%s/%s_3d.png"%(directory, tree_name), "Number of Decisions", "Costs", "Benefits") def visualize(self, decisions): tracks = [] for i in range(len(decisions)): pos_decs, neg_decs = [], [] for j in range(len(decisions)): if j < i: pos_decs.append(Decision(id = decisions[j].id, value = decisions[j].value, cost = decisions[j].cost, benefit = decisions[j].benefit)) neg_decs.append(Decision(id = decisions[j].id, value = decisions[j].value, cost = decisions[j].cost, benefit = decisions[j].benefit)) elif j == i: pos_decs.append(Decision(id = decisions[j].id, value = +1, cost = decisions[j].cost, benefit = decisions[j].benefit)) neg_decs.append(Decision(id = decisions[j].id, value = -1, cost = decisions[j].cost, benefit = decisions[j].benefit)) # else: # pos_decs.append(Decision(id = decisions[j].id, value = -1 * decisions[j].value)) # neg_decs.append(Decision(id = decisions[j].id, value = -1 * decisions[j].value)) if decisions[i].value == 1: pos_pop = self.generate(pos_decs, check_validity=True) neg_pop = self.generate(neg_decs, check_validity=False) else: pos_pop = self.generate(pos_decs, check_validity=False) neg_pop = self.generate(neg_decs, check_validity=True) for pos, neg in zip(pos_pop, neg_pop): self.evaluate(pos, pos_decs) self.evaluate(neg, neg_decs) p_meds, p_iqrs = [], [] n_meds, n_iqrs = [], [] for o_i in range(len(pos_pop[0].objectives)): p_objs = [pt.objectives[o_i] for pt in pos_pop] n_objs = [pt.objectives[o_i] for pt in neg_pop] med, iqr = median_iqr(p_objs) p_meds.append(med) p_iqrs.append(iqr) med, iqr = median_iqr(n_objs) n_meds.append(med) n_iqrs.append(iqr) tracks.append(O(id = decisions[i].id, name = decisions[i].name, pos_meds = p_meds, pos_iqrs = p_iqrs, neg_meds = n_meds, neg_iqrs = n_iqrs, prefered_value = decisions[i].value, cost = decisions[i].cost, benefit = decisions[i].benefit)) return tracks @staticmethod def get_elbow(gens, index, obj_index=None): pop = gens[index] pop = sorted(pop, key=lambda x: x.objectives[obj_index]) point = pop[len(pop)//2] return point