Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

kickoff

  • Loading branch information...
commit 7d28a662db103a0db917b911370adcc84ef85e58 0 parents
@douglascamata authored
5 data.txt
@@ -0,0 +1,5 @@
+2 28
+1898 440 22507 270 14148 3100 4650 30800 615 4975 1160 4225 510 11880 479 440 490 330 110 560 24355 2885 11748 4550 750 3720 1950 10500
+600 600
+45 5 85 150 65 95 30 12 170 20 40 25 20 3 7 25 12 22 25 9 165 2 85 15 9 2 4 100
+30 20 125 5 80 25 35 73 12 15 15 40 5 10 10 12 10 9 10 20 60 40 50 36 49 40 19 150
5 data2.txt
@@ -0,0 +1,5 @@
+2 28
+1898 440 22507 270 14148 3100 4650 30800 615 4975 1160 4225 510 11880 479 440 490 330 110 560 24355 2885 11748 4550 750 3720 1950 10500
+500 500
+45 0 85 150 65 95 30 0 170 0 40 25 20 0 0 25 0 0 25 0 165 0 85 0 0 0 0 100
+30 20 125 5 80 25 35 73 12 15 15 40 5 10 10 12 10 9 0 20 60 40 50 36 49 40 19 150
5 data3.txt
@@ -0,0 +1,5 @@
+2 105
+41850 38261 23800 21697 7074 5587 5560 5500 3450 2391 761 460 367 24785 47910 30250 107200 4235 9835 9262 15000 6399 6155 10874 37100 27040 4117 32240 1600 4500 70610 6570 15290 23840 16500 7010 16020 8000 31026 2568 2365 4350 1972 4975 29400 7471 2700 3840 22400 3575 13500 1125 11950 12753 10568 15600 20652 13150 2900 1790 4970 5770 8180 2450 7140 12470 6010 16000 11100 11093 4685 2590 11500 5820 2842 5000 3300 2800 5420 900 13300 8450 5300 750 1435 2100 7215 2605 2422 5500 8550 2700 540 2550 2450 725 445 700 1720 2675 220 300 405 150 70
+400 400
+75 40 365 95 25 17 125 20 22 84 75 50 15 0 0 12 0 10 0 50 0 0 10 0 0 50 60 150 0 0 75 0 102 0 0 40 60 0 165 0 0 0 45 0 0 0 25 0 150 0 0 0 158 0 85 95 0 89 20 0 0 0 0 0 0 80 0 110 0 15 0 60 5 135 0 0 25 0 300 35 100 0 0 25 0 0 225 25 0 0 0 0 0 0 0 5 0 60 0 100 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 5 10 10 50 2 5 5 10 5 6 11 41 30 5 40 2 6 100 10 25 39 30 13 30 15 60 5 5 10 5 15 91 24 10 15 90 15 60 5 55 60 50 75 100 65 15 10 30 35 50 15 45 80 40 110 80 80 36 20 90 50 25 50 35 30 60 10 150 110 70 10 20 30 104 40 40 94 150 50 10 50 50 16 10 20 50 90 10 15 39 20 20
5 knapsack/__init__.py
@@ -0,0 +1,5 @@
+from initial_solution import *
+from knapsack import *
+from local_search import *
+from neighborhood import *
+from tabu import *
17 knapsack/initial_solution.py
@@ -0,0 +1,17 @@
+from copy import deepcopy
+from random import shuffle
+
+def random_add_solution(knapsack):
+ all_items = deepcopy(knapsack.all_items)
+ parar = False
+ shuffle(all_items)
+ for item in all_items:
+ if knapsack.can_add_item(item):
+ knapsack.add_item(item)
+ else:
+ continue
+
+
+def greedy_solution(knapsack):
+ items = knapsack.sorted_items(knapsack.all_items)
+ [knapsack.add_item(item) for item in items]
173 knapsack/knapsack.py
@@ -0,0 +1,173 @@
+from time import clock
+from copy import deepcopy
+
+
+class Item(object):
+
+ def __init__(self, name, value, weight, volume):
+ self.name = name
+ self.value = value
+ self.weight = weight
+ self.volume = volume
+
+ def __repr__(self):
+ return "<%s>" % self.name
+ # return "<%s | %d >" % (self.name, self.value)
+
+ def ratio(self):
+ return float(self.value) / (self.weight + self.volume)
+
+ def __eq__(self, item):
+ return self.name == item.name and self.value == item.value and self.weight == item.weight and self.volume == item.volume
+
+
+class Knapsack(object):
+
+ def __init__(self, weight, volume, all_items, **kwargs):
+ self.weight = self.initial_weight = weight
+ self.volume = self.initial_volume = volume
+ self.value = 0
+ self.all_items = all_items
+ self.initial_value = 0
+ self._items = []
+ self.movement_counter = 0
+ self.moves_made = []
+ for key in kwargs.keys():
+ setattr(self, key, kwargs[key])
+
+ def set_items(self, items):
+ if len(items) == 0:
+ self._items = []
+ total_weight = reduce(lambda x, y: x + y, map(lambda item: item.weight, items))
+ total_volume = reduce(lambda x, y: x + y, map(lambda item: item.volume, items))
+ total_value = reduce(lambda x, y: x + y, map(lambda item: item.value, items))
+ if total_weight < self.initial_weight and total_volume < self.initial_volume:
+ self._items = items
+ self.weight = self.initial_weight - total_weight
+ self.volume = self.initial_volume - total_volume
+ self.value = total_value
+ else:
+ return False
+ def get_items(self):
+ return self._items
+ def del_items(self):
+ del self._items
+ items = property(get_items, set_items, del_items, 'Items')
+
+ def optimize(self, initial_solution_function, heuristic_function, neighborhood_function):
+ start = clock()
+ initial_solution_function(self)
+ self.initial_solution = deepcopy(self.items)
+ self.initial_value = self.value
+ heuristic_function(neighborhood_function, self)
+ end = clock()
+ print 'Best solution found with %d move(s).' % len(self.moves_made)
+ print 'Initial solution was: %s' % self.initial_solution
+ print 'Movements made: '
+ for move in self.moves_made:
+ print '-'*3 + " %s " % str(move)
+ print 'Initial value: %d' % self.initial_value
+ print 'Final value: %d' % self.value
+ print 'Total improvement: %d' % (self.value - self.initial_value)
+ print 'Weight left: %d' % self.weight
+ print 'Volume left: %d' % self.volume
+ print 'Number of items in solution: %s' % len(self.items)
+ print 'Ran in %f milliseconds.' % ((end-start)*1000)
+
+ def execute_movement(self, movement, silent=False):
+ for item in movement.remove_items:
+ if not item in self:
+ return False
+ self.remove_item(item)
+ for item in movement.add_items:
+ if not self.can_add_item(item):
+ return False
+ self.add_item(item)
+ if not silent:
+ self.movement_counter += 1
+ self.moves_made.append(movement)
+ return True
+
+ def add_item(self, item):
+ if self.can_add_item(item):
+ self.items.append(item)
+ self.weight -= item.weight
+ self.volume -= item.volume
+ self.value += item.value
+ self.all_items.remove(item)
+ return True
+ return False
+
+ def evaluate_swap(self, item, another_item):
+ return self.can_swap(item, another_item)
+
+ def remove_item(self, item):
+ if item in self.items:
+ self.weight += item.weight
+ self.volume += item.volume
+ self.value -= item.value
+ self.items.remove(item)
+ self.all_items.append(item)
+ return True
+ return False
+
+ def can_swap(self, inside_item, another_item):
+ if not inside_item in self or another_item in self:
+ return False
+ new_weight = self.weight + inside_item.weight
+ new_volume = self.volume + inside_item.volume
+ if (another_item.weight <= new_weight and another_item.volume <= new_volume):
+ return self.value - inside_item.value + another_item.value
+ return False
+
+ def swap(self, item, another_item):
+ if self.can_swap(item, another_item):
+ self.remove_item(item)
+ self.add_item(another_item)
+ return True
+ return False
+
+ def __contains__(self, item):
+ return any(map(lambda x: x == item, self.items))
+
+ def can_add_item(self, item):
+ if (self.weight >= item.weight and self.volume >= item.volume and not item in self.items):
+ return True
+ return False
+
+ def __repr__(self):
+ return "<Knapsack (%d) %s>" % (len(self.items), repr(self.items))
+
+ def sorted_items(self, items, key=Item.ratio):
+ return sorted(items, key=key, reverse=True)
+
+ def solution_neighborhood(self, f):
+ return f(self)
+
+
+class Movement(object):
+
+ def __init__(self, add_items=[], remove_items=[]):
+ self.add_items = add_items
+ self.remove_items = remove_items
+
+ @property
+ def movement_avaliation(self):
+ remove_value = add_value = 0
+ if not len(self.remove_items) == 0:
+ remove_value = reduce(lambda x, y: x + y, [item.value for item in self.remove_items])
+ if not len(self.add_items) == 0:
+ add_value = reduce(lambda x, y: x + y, [item.value for item in self.add_items])
+ return add_value - remove_value
+
+ def reverse(self):
+ return Movement(add_items=self.remove_items, remove_items=self.add_items)
+
+ def __eq__(self, another_move):
+ if not isinstance(another_move, Movement):
+ return False
+ return self.add_items == another_move.add_items and self.remove_items == another_move.remove_items
+
+ def __repr__(self):
+ # return "<Improve %d>" % self.movement_avaliation
+ return "<Remove %s | Add %s | Improve %d>" % (self.remove_items, self.add_items, self.movement_avaliation)
13 knapsack/local_search.py
@@ -0,0 +1,13 @@
+def best_improving(solutions, knapsack):
+ sorted_solutions = sorted(solutions, key=lambda move: move.movement_avaliation, reverse=True)
+ if len(sorted_solutions) == 0:
+ return False
+ if any(map(lambda solution: solution.movement_avaliation > 0, sorted_solutions)):
+ return sorted_solutions[0]
+ return False
+
+def first_improving(solutions, knapsack):
+ for solution in solutions:
+ if solution.movement_avaliation > 0:
+ return solution
+ return False
66 knapsack/neighborhood.py
@@ -0,0 +1,66 @@
+from knapsack import Movement
+from random import choice, shuffle
+from copy import deepcopy
+
+def add_and_or_remove_neighborhood(knapsack):
+ neighborhood = []
+ improving = []
+ shuffle(knapsack.items)
+ for item in knapsack.items:
+ if knapsack.can_add_item(item):
+ movement = Movement(add_items=[item,])
+ neighborhood.append(movement)
+ else:
+ weight_to_lose = item.weight
+ volume_to_lose = item.volume
+ items = deepcopy(knapsack.items)
+ to_remove = choice(items)
+ items.remove(to_remove)
+ while not knapsack.can_swap(to_remove, item):
+ print to_remove
+ print item
+ print '-'*80
+ if len(items) == 0:
+ break
+ to_remove = choice(items)
+ items.remove(to_remove)
+ else:
+ movement = Movement(add_items=[item,], remove_items=[to_remove,])
+ neighborhood.append(movement)
+ print neighborhood
+ return neighborhood
+
+
+def all_neighborhood(knapsack):
+ neighborhood = []
+ improving_solutions = []
+ shuffle(knapsack.all_items)
+ for item in knapsack.all_items:
+ actual_value = knapsack.value
+ shuffle(knapsack.items)
+ for solution_item in knapsack.items:
+ if knapsack.can_swap(solution_item, item):
+ new_value = knapsack.evaluate_swap(solution_item, item)
+ movement = Movement(add_items=[item,], remove_items=[solution_item,])
+ neighborhood.append(movement)
+ else:
+ continue
+ return neighborhood
+
+def first_improving_neighborhood(knapsack):
+ neighborhood = []
+ improving_solution = None
+ for item in knapsack.sorted_items(knapsack.all_items):
+ actual_value = knapsack.value
+ for solution_item in knapsack.sorted_items(knapsack.items):
+ if knapsack.can_swap(solution_item, item):
+ new_value = knapsack.evaluate_swap(solution_item, item)
+ movement = Movement(add_items=[item,], remove_items=[solution_item,])
+ if new_value > knapsack.value:
+ improving_solution = movement
+ neighborhood.append(movement)
+ return neighborhood
+ neighborhood.append(movement)
+ else:
+ pass
+ return neighborhood
90 knapsack/tabu.py
@@ -0,0 +1,90 @@
+from copy import deepcopy
+
+class TabuList(list):
+
+ def __init__(self, size=3):
+ self.size = size
+ super(TabuList, self).__init__()
+
+ def append(self, element):
+ if len(self) == self.size:
+ self.pop(0)
+ return super(TabuList, self).append(element)
+ return super(TabuList, self).append(element)
+
+ def __contains__(self, move):
+ for i in range(len(self)):
+ if move == self[i]:
+ return True
+ return False
+
+
+class TabuSearch(object):
+
+ def __init__(self, max_iter=2):
+ self.iter_counter = 0
+ self.iter_better = 0
+ self.max_iter = max_iter
+
+ def __call__(self, neighborhood_function, knapsack):
+ solutions = neighborhood_function(knapsack)
+ sorted_moves = self.sort_moves(solutions)
+ [sorted_moves.remove(tabu.reverse()) for tabu in knapsack.tabu_list if tabu.reverse() in sorted_moves]
+ best_move = None
+ best_solution = knapsack.value
+ best_solution_moves = deepcopy(knapsack.moves_made)
+ best_solution_items = deepcopy(knapsack.items)
+ tabu_ended = False
+
+ while self.iter_counter - self.iter_better < self.max_iter:
+ self.iter_counter += 1
+ if not len(sorted_moves) == 0: # se a lista tabu nao eliminou todos vizinhos
+ candidate_move = sorted_moves.pop(0) # pegar o melhor movimento possivel
+ knapsack.execute_movement(candidate_move, silent=True)
+ actual_solution = knapsack.value
+ knapsack.execute_movement(candidate_move.reverse(), silent=True)
+ knapsack.execute_movement(candidate_move)
+ knapsack.tabu_list.append(candidate_move.reverse())
+ if actual_solution > best_solution:
+ best_solution = actual_solution
+ best_solution_moves = deepcopy(knapsack.moves_made)
+ best_solution_items = deepcopy(knapsack.items)
+ self.iter_better = self.iter_counter
+ else: # se eliminou todos vizinhos
+ # encontra o tabu com melhor melhora
+ if len(knapsack.tabu_list) == 0:
+ return False
+ best_tabu = reduce(lambda x, y: x if x.movement_avaliation > y.movement_avaliation else y, knapsack.tabu_list)
+ if best_tabu.movement_avaliation > 0: # se ele apresentar uma melhora real na solucao atual
+ knapsack.execute_movement(best_tabu, silent=True)
+ actual_solution = knapsack.value
+ knapsack.execute_movement(best_tabu.reverse(), silent=True)
+ if actual_solution > knapsack.value:
+ # print 'Aspiration criteria applied, yay!'
+ if actual_solution > best_solution:
+ best_solution = actual_solution
+ best_solution_moves = deepcopy(knapsack.moves_made)
+ best_solution_items = deepcopy(knapsack.items)
+ self.iter_better = self.iter_counter
+ knapsack.execute_movement(best_tabu)
+ else:
+ print knapsack.tabu_list
+ print 'Ended by tabu list.'
+ tabu_ended = True
+ break
+ solutions = neighborhood_function(knapsack)
+ sorted_moves = self.sort_moves(solutions)
+ [sorted_moves.remove(tabu.reverse()) for tabu in knapsack.tabu_list if tabu.reverse() in sorted_moves]
+ print "Current iter %d, actual solution %d, better solution found in %d with %d" % (self.iter_counter, actual_solution, self.iter_better, best_solution)
+ knapsack.items = best_solution_items
+ knapsack.moves_made = best_solution_moves
+ print knapsack.value
+ print "Better solution found in %d with %d" % (self.iter_better, best_solution)
+ print 'Script ran with tabu search using a max of %d iterations and a tabu list with size %d.' % (self.max_iter, knapsack.tabu_list.size)
+ if not tabu_ended:
+ print 'Ended by iteration limit.'
+ return False
+
+ def sort_moves(self, moves):
+ return sorted(moves, key=lambda x: x.movement_avaliation, reverse=True)
+
44 main.py
@@ -0,0 +1,44 @@
+import sys
+from copy import deepcopy
+from knapsack import *
+
+def items_from_file(filename):
+ items = []
+ lines = open(filename).readlines()
+ lines = [line.strip().split(' ') for line in lines]
+ numbers_of_items = int(lines[0][1])
+ for i in range(numbers_of_items):
+ item = Item("Item %d" % i, int(lines[1][i]), int(lines[3][i]), int(lines[4][i]))
+ items.append(item)
+ return items
+
+def bag_constraints_from_file(filename):
+ items = []
+ lines = open(filename).readlines()
+ lines = [line.strip().split(' ') for line in lines]
+ return int(lines[2][0]), int(lines[2][1])
+
+def bag_from_file(filename):
+ constraints = bag_constraints_from_file(filename)
+ return (constraints[0], constraints[1], items_from_file(filename))
+
+if __name__ == '__main__':
+ # items = [
+ # Item(name, value, weight, volume) for name, value, weight, volume in \
+ # [
+ # ('Apple', 2, 1, 2), ('Laptop', 3, 2, 1), ('Pen', 3, 1, 3),
+ # ('Cap', 4, 3, 2), ('Cookie', 4, 2, 2), ('iPod', 5, 3, 3)
+ # ]
+ # ]
+ if len(sys.argv) > 1:
+ max_iter = int(sys.argv[1])
+ tabu_list_size = int(sys.argv[2])
+
+ bag = Knapsack(*bag_from_file('data3.txt'), tabu_list=TabuList(tabu_list_size))
+ bag.optimize(random_add_solution, TabuSearch(max_iter), all_neighborhood)
+ # bag.optimize(random_add_solution, first_improving_neighborhood, first_improving)
+
+ # greedy_solution(bag, items)
+ # print solution_neighborhood(bag, items)
+
+
Please sign in to comment.
Something went wrong with that request. Please try again.