示例#1
0
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