Skip to content

Commit 91cd353

Browse files
authored
Merge pull request #25 from david-sk/Backtracking
Backtracking
2 parents ef2b0b5 + ff96df7 commit 91cd353

File tree

7 files changed

+104
-14
lines changed

7 files changed

+104
-14
lines changed

binpacking/solver/__main__.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@
3030
bin_packing, tabu_size, max_iterations, getattr(Neighborhood, 'find_one_mutation_neighbor')
3131
)
3232

33-
s_star = ts.run(sol_init)
34-
print('best solution')
35-
print(s_star)
33+
solutions = ts.run(sol_init)
34+
print('best solutions')
35+
print(solutions)
3636

37-
plot_handler = PlotHandler(bin_packing, s_star)
38-
results_filepath = plot_handler.save_to_file('cool_plot.png')
37+
for i, solution in enumerate(solutions):
38+
plot_handler = PlotHandler(bin_packing, solution)
39+
results_filepath = plot_handler.save_to_file(f'cool_plot_{i}_.png')

binpacking/solver/backtracking.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from typing import List
2+
import copy
3+
4+
from binpacking.solver.bin_packing_2d import BinPacking2D
5+
from binpacking.solver.solution import Solution, Coordinate
6+
from binpacking.solver.optimisation_algo import OptimisationAlgo
7+
8+
9+
class Backtracking(OptimisationAlgo):
10+
def __init__(self, bin_packing: BinPacking2D):
11+
self.bin_packing = bin_packing
12+
13+
def run(self, sol: Solution) -> List[Solution]:
14+
return self.backtracking(sol)
15+
16+
def backtracking(self, sol: Solution, number_of_valid_items: int = 0) -> List[Solution]:
17+
width, height = self.bin_packing.capacity.get_width_height()
18+
valid_solutions: List[Solution] = []
19+
for x in range(width):
20+
for y in range(height):
21+
for r in [0, 90]:
22+
sol[number_of_valid_items] = Coordinate(x, y)
23+
sol[number_of_valid_items].set_is_rotated(r == 90)
24+
self.bin_packing.evaluate(sol)
25+
if number_of_valid_items < len(sol) - 1:
26+
if 0 <= sol.get_fitness():
27+
valid_solutions.extend(
28+
self.backtracking(copy.deepcopy(sol), number_of_valid_items + 1)
29+
)
30+
else:
31+
if sol.get_fitness() == len(sol):
32+
valid_solutions.append(copy.deepcopy(sol))
33+
return valid_solutions

binpacking/solver/iterated_local_search.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# Universitat Pompeu Fabra, https://EconPapers.repec.org/RePEc:upf:upfgen:513.
55
# (https://econ-papers.upf.edu/papers/513.pdf)
66
import copy
7-
7+
from typing import List
88
from binpacking.solver.bin_packing_2d import BinPacking2D
99
from binpacking.solver.solution import Solution
1010
from binpacking.solver.neighborhood import Neighborhood
@@ -19,7 +19,7 @@ def __init__(
1919
self.max_iterations = max_iterations
2020
self.optimisation_algo = optimisation_algo
2121

22-
def run(self, sol: Solution) -> Solution:
22+
def run(self, sol: Solution) -> List[Solution]:
2323
# Best known solution
2424
s_star = copy.deepcopy(sol)
2525
if not s_star.has_valid_fitness():
@@ -41,4 +41,4 @@ def run(self, sol: Solution) -> Solution:
4141
print(s_star)
4242
iterations += 1
4343

44-
return s_star
44+
return [s_star]
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from abc import ABCMeta, abstractmethod
2-
2+
from typing import List
33
from binpacking.solver.solution import Solution
44

55

@@ -8,5 +8,5 @@ class OptimisationAlgo:
88
__metaclass__ = ABCMeta
99

1010
@abstractmethod
11-
def run(self, sol: Solution) -> Solution:
11+
def run(self, sol: Solution) -> List[Solution]:
1212
pass

binpacking/solver/solution.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ def invalidate(self) -> None:
2424
self.x, self.y = self.INVALID_COORDINATE
2525

2626
def rotate(self, is_rotated: bool = True) -> None:
27-
self.is_rotated = is_rotated # not self.is_rotated
27+
self.is_rotated = not self.is_rotated
28+
29+
def set_is_rotated(self, is_rotated: bool) -> None:
30+
self.is_rotated = is_rotated
2831

2932

3033
class Solution(List[Coordinate]):

binpacking/solver/tabu_search.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# @brief : F. Glover, "Future paths for integer programming and links to artificial intelligence,"
22
# Computers & Operations Research, vol. 13, pp. 533-549, 1986.
33

4-
from typing import Deque, Callable
4+
from typing import Deque, Callable, List
55
from collections import deque
66
import copy
77

@@ -24,7 +24,7 @@ def __init__(
2424
self.find_neighborhood = find_neighborhood
2525
self.tabu_deque: Deque[Solution] = deque(maxlen=self.tabu_size)
2626

27-
def run(self, sol: Solution) -> Solution:
27+
def run(self, sol: Solution) -> List[Solution]:
2828
# Best known solution
2929
s_star = copy.deepcopy(sol)
3030
if not s_star.has_valid_fitness():
@@ -53,4 +53,4 @@ def run(self, sol: Solution) -> Solution:
5353
self.tabu_deque.append(s_prim)
5454

5555
iterations += 1
56-
return s_star
56+
return [s_star]
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
from tests.base import BaseTestCase
2+
3+
from binpacking.solver.bin_packing_2d import BinPacking2D, Rectangle
4+
from binpacking.solver.solution import Solution, Coordinate
5+
6+
from binpacking.solver.backtracking import Backtracking
7+
8+
9+
class BacktrackingTest(BaseTestCase):
10+
@BaseTestCase.timeConsumingTest()
11+
def test_run_big_instance(self) -> None:
12+
instance = BinPacking2D(
13+
Rectangle(100, 100),
14+
[
15+
Rectangle(30, 40),
16+
Rectangle(70, 30),
17+
Rectangle(30, 30),
18+
Rectangle(40, 70),
19+
Rectangle(30, 20),
20+
Rectangle(30, 70),
21+
],
22+
)
23+
sol = Solution(instance.get_instance_size())
24+
sol[0] = Coordinate(-1, -1)
25+
sol[1] = Coordinate(-1, -1)
26+
sol[2] = Coordinate(-1, -1)
27+
sol[3] = Coordinate(-1, -1)
28+
sol[4] = Coordinate(-1, -1)
29+
sol[5] = Coordinate(-1, -1)
30+
31+
backtracking = Backtracking(instance)
32+
backtracking.run(sol)
33+
34+
def test_run_small_instance(self) -> None:
35+
instance = BinPacking2D(Rectangle(2, 2), [Rectangle(1, 2), Rectangle(1, 2)],)
36+
sol = Solution(instance.get_instance_size())
37+
sol[0] = Coordinate(-1, -1)
38+
sol[1] = Coordinate(-1, -1)
39+
40+
backtracking = Backtracking(instance)
41+
valid_solutions = backtracking.run(sol)
42+
43+
self.assertEqual(
44+
str(valid_solutions),
45+
str(
46+
[
47+
[(0, 0, 0), (1, 0, 0)],
48+
[(0, 0, 90), (0, 1, 90)],
49+
[(0, 1, 90), (0, 0, 90)],
50+
[(1, 0, 0), (0, 0, 0)],
51+
]
52+
),
53+
)

0 commit comments

Comments
 (0)