-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbase_solver.py
148 lines (120 loc) · 4.47 KB
/
base_solver.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/env python
# encoding: utf-8
from datetime import datetime, timedelta
from helpers import TimeoutError, INF
class RunSolverFirst(Exception):
pass
class BaseSolver(object):
task = None
best_solution = None
best_distance = float('inf')
search_time = None
cycles = 0
a_solver = True # just to find solvrs easier
# timeout related
timedout = False
time_to_get_out = None
start_time = None
def __init__(self, task):
self.task = task
def run(self):
self.start_time = datetime.now()
try:
self.best_solution, self.best_distance, self.cycles = self.run_search()
except TimeoutError:
self.handle_timeout()
finish_time = datetime.now()
self.search_time = finish_time - self.start_time
self.task.verify_route(self.best_solution, self)
def run_search(self):
# dummy - this is where one should implement the algorithm
# this should include calls to self.check_timeout
pass
def check_timeout(self):
if self.time_to_get_out:
if self.time_to_get_out < datetime.now():
self.timedout = True
raise TimeoutError
elif self.task.timeout:
self.time_to_get_out = self.start_time + timedelta(
seconds=self.task.timeout)
def handle_timeout(self):
# this can vary a lot between diffrent algorithms
# (it may be usefull to get best solution found till now)
self.cycles = 0
self.best_solution = []
self.best_distance = INF
def get_summary(self):
if self.best_solution is None and not self.timedout:
raise RunSolverFirst(u'Run the solver first')
if self.timedout and self.best_solution:
txt = (
'========== {solver_name} ==========\n'
'* TIMEDOUT *\n'
'run {cycles} cycles for: {search_time}\n'
'best found solution: {best_solution}\n'
'distance: {distance}\n'
)
elif self.timedout:
txt = (
'========== {solver_name} ==========\n'
'TIMEDOUT after {search_time}\n'
)
else:
txt = (
'========== {solver_name} ==========\n'
'run {cycles} cycles for: {search_time}\n'
'best found solution: {best_solution}\n'
'distance: {distance}\n'
)
return txt.format(
solver_name=str(self.__class__),
cycles=self.cycles,
search_time=self.search_time,
best_solution=self.best_solution,
distance=self.best_distance
)
def save_solution(self, cursor):
# fail fast
if self.best_solution is None and not self.timedout:
raise RunSolverFirst(u'Run the solver first')
# if solver is deterministic - keep only one record in db
insert_new_record = True
if getattr(self, 'deterministic', False):
# check if record for this solver already exists
cursor.execute(
'SELECT * FROM solver_runs WHERE solver=? AND task=?',
(str(self.__class__), self.task.name))
# if it does - overwrite it (might be updated solution)
if cursor.fetchone():
sql = ('UPDATE solver_runs SET '
'time=?, '
'cycles=?, '
'solution=?, '
'distance=?, '
'timedout=? '
'WHERE solver=? '
'AND task=?'
)
input = (
str(self.search_time),
str(self.cycles),
unicode(self.best_solution),
self.best_distance,
self.timedout,
str(self.__class__),
self.task.name,
)
insert_new_record = False
if insert_new_record:
sql = 'INSERT INTO solver_runs VALUES (NULL, ?, ?, ?, ?, ?, ?, ?)'
input = (
str(self.__class__),
self.task.name,
str(self.search_time),
str(self.cycles),
unicode(self.best_solution),
self.best_distance,
self.timedout,
)
cursor.execute(sql, input)