def vertex_cover_cost(first_node, second_node): return { 'headers': [first_node, second_node], 0: ResultSet((Vector(*(inf for _ in range(len(first_node.cost)))), )), 1: ResultSet((first_node.cost, )), 2: ResultSet((second_node.cost, )), 3: ResultSet((first_node.cost + second_node.cost, )), }
def _next_best_assignment(self, assignment): # try each value of the next unassigned variable possible_results = ResultSet() results = {} for possible_value in (0, 1): this_assignment = tuple(assignment) + (possible_value, ) this_result = None this_index = len(this_assignment) - 1 # add costs in this bucket node = self.order[this_index] for cost_function in self.buckets[node]['costs'] + self.buckets[ node]['heuristics']: key = self.get_assignment_table_key(this_assignment, cost_function['headers']) if not this_result: this_result = cost_function[key] else: this_result = this_result + cost_function[key] if all(item == tuple(inf for _ in range(self.dimensions)) for item in this_result): break # save result for this value - majority vote when returning results[possible_value] = this_result # save possible results possible_results |= this_result # check which is the next best value total_results = len(possible_results) if len(results[1] & possible_results) > total_results / 2: return 1 else: return 0
def eliminate_variable(table, node): full_headers = table['headers'] heuristic_headers = [item for item in full_headers if item != node] heuristic_table = {'headers': heuristic_headers, 'from': node} heuristic_table.update( {i: ResultSet() for i in range(2**len(heuristic_headers))}) if len(full_headers) == 1: raise Exception('Should not happen') # populate heuristic with joint non-dominated values for heuristic_key, value in heuristic_table.items(): if heuristic_key in {'headers', 'from'}: continue # build index and mask index, mask = MiniBucket.get_index_mask_cost( heuristic_key, heuristic_headers, full_headers) # join corresponding full table keys for full_key in table: if full_key in {'headers', 'from'}: continue if full_key & mask == index: heuristic_table[heuristic_key] |= table[full_key] return heuristic_table
def _partial_parent_crossover(self): for count in range(int(self.population_size * self.crossover_chance)): chosen_parents = random.sample(self.next_population, self.k_parents) new_individual = {'chromosome': [], 'cost': None} # choose each position according to best partial assignment of parent for position in range(self.nodes_count): # compute all partial assignments of the chosen parents parent_costs = [] result_set = ResultSet() for parent in chosen_parents: this_cost = self.heuristics.compute_cost( parent['chromosome'][:position + 1])[0] parent_costs.append(this_cost) result_set |= this_cost best_cost, index = max( (len(result_set & cost), count) for count, cost in enumerate(parent_costs)) new_individual['chromosome'].append( chosen_parents[index]['chromosome'][position]) # compute cost of new individual new_individual['cost'] = self.heuristics.compute_cost( new_individual['chromosome'])[0].pop() # replace worst parent with new child worst_parent = min(chosen_parents, key=lambda k: k['cost']) self.next_population.remove(worst_parent) self.next_population.append(new_individual)
def create_cost_table(self, headers): cost_table = {'headers': list(headers)} for i in range(2**len(headers)): # sum costs of chosen nodes total_cost = Vector.add_vectors( *(node.cost for count, node in enumerate(headers) if i & (1 << count)), dimensions=self.dimensions) cost_table[i] = ResultSet((total_cost, )) return cost_table
def _compute_cost_full(self, assignment): zipped = list(zip(assignment, self.original_order)) total_cost = None nodes_included = {node for value, node in zipped if value} for count, (first_value, first_node) in enumerate(zipped): # check if any hard constraints violated for second_value, second_node in zipped[count:]: if not first_value and not second_value: if second_node in first_node.neighbors: return ResultSet( (Vector(*(inf for _ in range(self.dimensions)), includes=nodes_included), )), None # add total cost from cost functions if first_value: total_cost = first_node.cost if total_cost is None else \ total_cost + first_node.cost return ResultSet((total_cost, )), None
def _compute_cost_partial(self, assignment): assigned_count = len(assignment) assigned_nodes = tuple(self.order[:assigned_count + 1]) # try each value of the next unassigned variable possible_results = ResultSet() for possible_value in (0, 1): this_assignment = tuple(assignment) + (possible_value, ) this_result = self._compute_fixed_partial(this_assignment, assigned_nodes) # save possible results possible_results |= this_result # check which is the next best value next_node = self.order[assigned_count] for result in possible_results: if next_node not in result.includes: return possible_results, 0 else: return possible_results, 1
def _compute_cost_partial_backup(self, assignment): assigned_count = len(assignment) # try each value of the next unassigned variable assigned_nodes = set(self.order[:assigned_count + 1]) possible_results = ResultSet() for possible_value in (0, 1): this_result = None this_assignment = assignment + [possible_value] # compute sum of costs for assigned variables for node in assigned_nodes: # add actual constraints and heuristics coming from unassigned nodes for cost_function in self.buckets[node][ 'costs'] + self.buckets[node]['heuristics']: if 'from' in cost_function and cost_function[ 'from'] in assigned_nodes: continue key = self.get_assignment_table_key( this_assignment, cost_function['headers']) if not this_result: this_result = cost_function[key] else: this_result = this_result + cost_function[key] if all(item == tuple(inf for _ in range(self.dimensions)) for item in this_result): return this_result, random.choice((0, 1)) # save possible results possible_results |= this_result # check which is the next best value next_node = self.order[assigned_count] for result in possible_results: if next_node in result.includes: return possible_results, 1 else: return possible_results, 0