Beispiel #1
0
    def run_algorithm(self, num_solution_before_stop=100000, time_out=1000000):
        """
        This is where we implement our logic and algorithms

        Useful Parameters:
        self.P -- max weight we can carry
        self.M -- max purchasing power in dollars
        self.N -- total number of avaliable items
        self.C -- total number of constraints
        self.items -- all items avaliable for choice
        self.constraints -- a Constraint class with constraints
        """

        # STEP: Create a hashmap from class number to its items
        item_map = dict()
        for item in self.items:
            if item.classNumber not in item_map:
                item_map[item.classNumber] = set()
            item_map[item.classNumber].add(item)

        # STEP: Calculate the total weight, cost, value, and profit of each class
        def get_class_stats(items):
            total_weight = 0
            total_cost = 0
            total_value = 0
            total_profit = 0
            for item in items:
                total_weight += item.weight
                total_cost += item.cost
                total_value += item.value
                total_profit += item.profit
            return (total_weight, total_cost, total_value, total_profit)

        class_stats = dict() # Format: key: class -> value: (weight, cost, value, profit)
        for classNumber in item_map.keys():
            class_stats[classNumber] = get_class_stats(item_map[classNumber])

        # STEP: Create a BAG instance
        bag = Bag(self.P, self.M, self.constraints)

        # STEP: PriorityQueues of class's values

        fn_extract_profit_per_weight_ratio = lambda x: x.profit_per_weight_ratio()
        
        def fn_extractclass_ratio(x):
            weight, _, _, profit = class_stats[x]
            if weight == 0:
                ratio = float("inf")
            else:
                ratio = profit / weight
            return ratio


        class_queue = PriorityQueue(lowest_priority=False) # based on class's item profit_per_weight_ratio
        for classNumber in item_map.keys():
            class_queue.push(classNumber, fn_extractclass_ratio(classNumber))

        def add_to_queue(items, fn_extract_priority, queue):
            for item in items:
                priority_value = fn_extract_priority(item)
                queue.push(item, -priority_value)
            return queue

        def get_queue_of_items(items, fn_extract_priority):
            queue = PriorityQueue(lowest_priority=False)
            return add_to_queue(items, fn_extract_priority, queue)


        # STEP: pick from the bag with highest ratio
        solutions_found = dict()
        num_solution_found = 0
        iteration = 0

        class_not_used_due_to_conflict = Queue()

        add_back_conflicts = True

        while num_solution_found <= num_solution_before_stop and iteration <= time_out:
            while not class_queue.isEmpty() and iteration <= time_out:
                iteration += 1
                if iteration % (time_out / 1000) == 0:
                    print("iteration {0} -- rate: {1:.2f} %".format(iteration, iteration / time_out * 100), end="\r")
                if not class_not_used_due_to_conflict.isEmpty():
                    class_to_use  = class_not_used_due_to_conflict.pop()
                    add_back_conflicts = not add_back_conflicts
                else: 
                    class_to_use = class_queue.pop()
                    add_back_conflicts = not add_back_conflicts
                if bag.can_take(class_to_use):
                    items_queue = get_queue_of_items(item_map[class_to_use], \
                                                fn_extract_profit_per_weight_ratio)
                    item = items_queue.pop()
                    while bag.take(item):
                        if not items_queue.isEmpty():
                            item = items_queue.pop()
                        else:
                            break
                    num_solution_found += 1
                    solutions_found[bag.score()] =  bag.items()
                    print("solution {0} found".format(num_solution_found))
                else:
                    class_not_used_due_to_conflict.push(class_to_use)
                if num_solution_found >= num_solution_before_stop:
                    break
            # print("iteration {0}".format(iteration))
            iteration += 1
            if add_back_conflicts:
                add_to_queue(class_not_used_due_to_conflict.list, fn_extractclass_ratio, class_queue)
            if num_solution_found >= num_solution_before_stop:
                break

        # STEP: return the best combination found
        bestSolution = []
        bestProfit = 0
        for profit, soln in solutions_found.items():
            if profit > bestProfit:
                bestProfit = profit
                bestSolution = soln
        return bestSolution
Beispiel #2
0
    def run_algorithm(self, num_solution_before_stop=100000, time_out=1000000):
        """
        This is where we implement our logic and algorithms

        Useful Parameters:
        self.P -- max weight we can carry
        self.M -- max purchasing power in dollars
        self.N -- total number of avaliable items
        self.C -- total number of constraints
        self.items -- all items avaliable for choice
        self.constraints -- a Constraint class with constraints
        """

        # STEP: Create a hashmap from class number to its items
        item_map = dict()
        for item in self.items:
            if item.classNumber not in item_map:
                item_map[item.classNumber] = set()
            item_map[item.classNumber].add(item)

        # STEP: Calculate the total weight, cost, value, and profit of each class
        def get_class_stats(items):
            total_weight = 0
            total_cost = 0
            total_value = 0
            total_profit = 0
            for item in items:
                total_weight += item.weight
                total_cost += item.cost
                total_value += item.value
                total_profit += item.profit
            return (total_weight, total_cost, total_value, total_profit)

        class_stats = dict() # Format: key: class -> value: (weight, cost, value, profit)
        for classNumber in item_map.keys():
            class_stats[classNumber] = get_class_stats(item_map[classNumber])

        # STEP: Create a BAG instance
        bag = Bag(self.P, self.M, self.constraints)

        # STEP: PriorityQueues of class's values

        fn_extract_profit_per_weight_ratio = lambda x: x.profit_per_weight_ratio()
        
        def fn_extractclass_ratio(x):
            weight, _, _, profit = class_stats[x]
            if weight == 0:
                ratio = float("inf")
            else:
                ratio = profit / weight
            return ratio


        class_queue = PriorityQueue(lowest_priority=False) # based on class's item profit_per_weight_ratio
        for classNumber in item_map.keys():
            class_queue.push(classNumber, fn_extractclass_ratio(classNumber))

        def add_to_queue(items, fn_extract_priority, queue):
            for item in items:
                priority_value = fn_extract_priority(item)
                queue.push(item, -priority_value)
            return queue

        def get_queue_of_items(items, fn_extract_priority):
            queue = PriorityQueue(lowest_priority=False)
            return add_to_queue(items, fn_extract_priority, queue)


        # STEP: pick from the bag with highest ratio
        solutions_found = dict()
        num_solution_found = 0
        iteration = 0

        class_not_used_due_to_conflict = Queue()

        add_back_conflicts = True

        while num_solution_found <= num_solution_before_stop and iteration <= time_out:
            while not class_queue.isEmpty() and iteration <= time_out:
                iteration += 1
                if iteration % (time_out / 1000) == 0:
                    print("iteration {0} -- rate: {1:.2f} %".format(iteration, iteration / time_out * 100), end="\r")
                if not class_not_used_due_to_conflict.isEmpty():
                    class_to_use  = class_not_used_due_to_conflict.pop()
                    add_back_conflicts = not add_back_conflicts
                else: 
                    class_to_use = class_queue.pop()
                    add_back_conflicts = not add_back_conflicts
                if bag.can_take(class_to_use):
                    items_queue = get_queue_of_items(item_map[class_to_use], \
                                                fn_extract_profit_per_weight_ratio)
                    item = items_queue.pop()
                    while bag.take(item):
                        if not items_queue.isEmpty():
                            item = items_queue.pop()
                        else:
                            break
                    num_solution_found += 1
                    solutions_found[bag.score()] =  bag.items()
                    print("solution {0} found".format(num_solution_found))
                else:
                    class_not_used_due_to_conflict.push(class_to_use)
                if num_solution_found >= num_solution_before_stop:
                    break
            # print("iteration {0}".format(iteration))
            iteration += 1
            if add_back_conflicts:
                add_to_queue(class_not_used_due_to_conflict.list, fn_extractclass_ratio, class_queue)
            if num_solution_found >= num_solution_before_stop:
                break

        # STEP: return the best combination found
        bestSolution = []
        bestProfit = 0
        for profit, soln in solutions_found.items():
            if profit > bestProfit:
                bestProfit = profit
                bestSolution = soln
        return bestSolution