Skip to content

Commit 436f516

Browse files
committed
v0.0.22 TSP, VRP examples with plain score calculator; sampling fix in mover; some refactor
1 parent 33a6bd4 commit 436f516

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1915
-30
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
/.vscode
33
/greyjack/target
4+
/data
45

56
# Byte-compiled / optimized / DLL files
67
__pycache__/

examples/object_oriented/nqueens/scripts/solve_nqueens.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
import os
33
import sys
44

5-
# To launch normally from console without setup.py greyjack (just for developing)
6-
# Inside console run from from project dir: >python ./{path_to_example_script.py}
5+
# To launch normally from console
76
script_dir_path = Path(os.path.dirname(os.path.realpath(__file__)))
87
project_dir_id = script_dir_path.parts.index("greyjack-solver-python")
98
project_dir_path = Path(*script_dir_path.parts[:project_dir_id+1])
@@ -23,16 +22,16 @@
2322
if __name__ == "__main__":
2423

2524
# build domain model
26-
domain_builder = DomainBuilderNQueens(1024, random_seed=45)
25+
domain_builder = DomainBuilderNQueens(256, random_seed=45)
2726
cotwin_builder = CotwinBuilderNQueens()
2827

2928
#termination_strategy = StepsLimit(step_count_limit=1000)
30-
#termination_strategy = TimeSpentLimit(time_seconds_limit=60)
29+
termination_strategy = TimeSpentLimit(time_seconds_limit=60)
3130
#termination_strategy = ScoreNoImprovement(time_seconds_limit=15)
32-
termination_strategy = ScoreLimit(score_to_compare=[0])
31+
#termination_strategy = ScoreLimit(score_to_compare=[0])
3332
agent = TabuSearch(neighbours_count=128, tabu_entity_rate=0.0,
34-
mutation_rate_multiplier=None, move_probas=[0, 1, 0, 0, 0, 0],
35-
migration_frequency=1, termination_strategy=termination_strategy)
33+
mutation_rate_multiplier=None, move_probas=None,
34+
migration_frequency=10, termination_strategy=termination_strategy)
3635
"""agent = GeneticAlgorithm(population_size=128, crossover_probability=0.5, p_best_rate=0.05,
3736
tabu_entity_rate=0.0, mutation_rate_multiplier=1.0, move_probas=[0, 1, 0, 0, 0, 0],
3837
migration_rate=0.00001, migration_frequency=1, termination_strategy=termination_strategy)"""
@@ -41,7 +40,7 @@
4140
migration_frequency=10, termination_strategy=termination_strategy)"""
4241

4342
solver = Solver(domain_builder, cotwin_builder, agent,
44-
ParallelizationBackend.Multiprocessing, LoggingLevel.FreshOnly,
43+
ParallelizationBackend.Multiprocessing, LoggingLevel.Info,
4544
n_jobs=10, score_precision=[0])
4645
solution = solver.solve()
4746
#print( "Cotwin solution looks that: " )

examples/object_oriented/tsp/__init__.py

Whitespace-only changes.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
3+
class CotStop():
4+
def __init__(self, stop_id, location_list_id):
5+
6+
self.stop_id = stop_id
7+
self.location_list_id = location_list_id
8+
9+
pass
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
3+
class EdgeDistance():
4+
5+
def __init__(self, from_stop, to_stop, distance):
6+
7+
self.from_stop = from_stop
8+
self.to_stop = to_stop
9+
self.distance = distance
10+
11+
pass
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
from greyjack.cotwin.CotwinBase import CotwinBase
3+
4+
class TSPCotwin( CotwinBase ):
5+
6+
def __init__(self):
7+
super().__init__()
8+
9+
pass
10+

examples/object_oriented/tsp/cotwin/__init__.py

Whitespace-only changes.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
import math
3+
4+
class Location():
5+
def __init__(self, id, name, latitude, longitude, distances_to_other_locations_dict):
6+
7+
self.id = id
8+
self.name = name
9+
self.latitude = latitude
10+
self.longitude = longitude
11+
self.distances_to_other_locations_dict = None
12+
13+
pass
14+
15+
def __str__(self):
16+
return "Location id: " + str(self.id) + " | " + self.name + ": " + "lat=" + str(self.latitude) + ", " + "lon=" + str(self.longitude)
17+
18+
def get_distance_to_other_location(self, other_location):
19+
20+
if self.distances_to_other_locations_dict is None:
21+
distance = math.sqrt((other_location.latitude - self.latitude)**2 + (other_location.longitude - self.longitude)**2)
22+
else:
23+
distance = self.distances_to_other_locations_dict[ other_location.name ]
24+
25+
return distance
26+
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import numpy as np
2+
import matplotlib.pyplot as plt
3+
4+
class TravelSchedule():
5+
def __init__(self, name, vehicle, locations_list, distance_matrix):
6+
7+
self.name = name
8+
self.vehicle = vehicle
9+
self.locations_list = locations_list
10+
self.distance_matrix = distance_matrix
11+
12+
pass
13+
14+
def get_unique_stops_count(self):
15+
unique_stops = set(self.vehicle.trip_path)
16+
unique_stops_count = len(unique_stops)
17+
return unique_stops_count
18+
19+
def get_travel_distance(self):
20+
21+
depot = self.vehicle.depot
22+
trip_path = self.vehicle.trip_path
23+
if trip_path is None or trip_path == []:
24+
raise Exception("Vehicle trip_path is not initialized. Probably, a TSP task isn't solved yet or domain model isn't updated.")
25+
26+
depot_to_first_stop_distance = depot.get_distance_to_other_location( trip_path[0] )
27+
last_stop_to_depot_distance = trip_path[-1].get_distance_to_other_location( depot )
28+
29+
interim_stops_distance = 0
30+
for i in range(1, len(trip_path)):
31+
stop_from = trip_path[i-1]
32+
stop_to = trip_path[i]
33+
current_distance = stop_from.get_distance_to_other_location( stop_to )
34+
interim_stops_distance += current_distance
35+
36+
travel_distance = depot_to_first_stop_distance + interim_stops_distance + last_stop_to_depot_distance
37+
38+
return travel_distance
39+
40+
def print_metrics(self):
41+
print("Solution distance: {}".format(self.get_travel_distance()))
42+
print("Unique stops (excluding depot): {}".format(self.get_unique_stops_count()))
43+
44+
def print_path(self):
45+
path_names_string = self.build_string_of_path_names()
46+
path_ids_string = self.build_string_of_path_ids()
47+
48+
print( path_names_string )
49+
print( path_ids_string )
50+
51+
def build_string_of_path_names(self):
52+
path_names_string = [str(self.vehicle.depot.name)]
53+
for stop in self.vehicle.trip_path:
54+
path_names_string.append( str(stop.name) )
55+
path_names_string.append( str(self.vehicle.depot.name) )
56+
path_names_string = " --> ".join( path_names_string )
57+
return path_names_string
58+
59+
def build_string_of_path_ids(self):
60+
path_ids_string = [str(self.vehicle.depot.id)]
61+
for stop in self.vehicle.trip_path:
62+
path_ids_string.append( str(stop.id) )
63+
path_ids_string.append( str(self.vehicle.depot.id) )
64+
path_ids_string = " --> ".join( path_ids_string )
65+
return path_ids_string
66+
67+
68+
def plot_path(self, image_file_path=None, dpi=200):
69+
70+
x_coordinates = []
71+
y_coordinates = []
72+
labels = []
73+
for location in self.locations_list:
74+
x = location.latitude
75+
y = location.longitude
76+
label = location.name
77+
78+
x_coordinates.append( x )
79+
y_coordinates.append( y )
80+
labels.append( label )
81+
82+
plt.scatter( x=x_coordinates, y=y_coordinates, s=1)
83+
for x, y, label in zip(x_coordinates, y_coordinates, labels):
84+
plt.text( x, y, label, fontsize=8, fontfamily="calibri" )
85+
86+
edges_x = [self.vehicle.depot.latitude]
87+
edges_y = [self.vehicle.depot.longitude]
88+
trip_path = self.vehicle.trip_path
89+
for stop_point in trip_path:
90+
edges_x.append( stop_point.latitude )
91+
edges_y.append( stop_point.longitude )
92+
93+
edges_x.append(self.vehicle.depot.latitude)
94+
edges_y.append(self.vehicle.depot.longitude)
95+
96+
plt.plot( edges_x, edges_y, linewidth=0.5 )
97+
98+
if image_file_path is None:
99+
plt.show()
100+
else:
101+
plt.savefig(image_file_path, dpi=dpi)
102+
plt.close()
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
3+
class Vehicle():
4+
5+
def __init__(self, depot, trip_path):
6+
7+
self.depot = depot
8+
self.trip_path = trip_path
9+
10+
pass

examples/object_oriented/tsp/domain/__init__.py

Whitespace-only changes.
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import random
2+
import numpy as np
3+
4+
from examples.object_oriented.tsp.cotwin.CotStop import CotStop
5+
from examples.object_oriented.tsp.cotwin.EdgeDistance import EdgeDistance
6+
from examples.object_oriented.tsp.cotwin.TSPCotwin import TSPCotwin
7+
from examples.object_oriented.tsp.score.TSPPlainScoreCalculator import TSPPlainScoreCalculator
8+
9+
from greyjack.persistence.CotwinBuilderBase import CotwinBuilderBase
10+
from greyjack.variables.GJInteger import GJInteger
11+
12+
13+
class CotwinBuilder(CotwinBuilderBase):
14+
15+
def __init__(self):
16+
17+
super().__init__()
18+
19+
pass
20+
21+
def build_cotwin(self, domain_model, is_already_initialized):
22+
23+
tsp_cotwin = TSPCotwin()
24+
25+
tsp_cotwin.add_planning_entities_list(self._build_planning_path_stops(domain_model), "path_stops")
26+
27+
# (!) better use distance matrix mapping than building and joining large distance dataframe!
28+
#tsp_cotwin.add_problem_facts_list(self._build_edge_distances(domain_model), "edge_distances")
29+
30+
score_calculator = TSPPlainScoreCalculator()
31+
score_calculator.utility_objects["distance_matrix"] = domain_model.distance_matrix
32+
tsp_cotwin.set_score_calculator( score_calculator )
33+
34+
return tsp_cotwin
35+
36+
def _build_edge_distances(self, domain_model):
37+
38+
distance_matrix = domain_model.distance_matrix
39+
n_stops = len(distance_matrix)
40+
41+
edge_distances = []
42+
for i in range(n_stops):
43+
for j in range(n_stops):
44+
current_edge_distance = EdgeDistance( i, j, distance_matrix[i][j] )
45+
edge_distances.append( current_edge_distance )
46+
47+
return edge_distances
48+
49+
def _build_planning_path_stops(self, domain_model):
50+
51+
planning_path_stops = []
52+
locations_list = domain_model.locations_list
53+
n_locations = len(locations_list)
54+
n_stops = n_locations - 1 # excluding depot
55+
56+
# greed heuristic for initializing
57+
initial_stop_ids = []
58+
current_approx_stop = 0
59+
for i in range(1, n_locations):
60+
candidate_stops = domain_model.distance_matrix[current_approx_stop]
61+
candidate_stops = np.argsort( candidate_stops )#[::-1]#[5:] #<-- for experiments
62+
existing_stop_ids = set(initial_stop_ids)
63+
for candidate_stop in candidate_stops:
64+
if ((candidate_stop not in existing_stop_ids)
65+
and (candidate_stop != current_approx_stop)
66+
and (candidate_stop != 0)):
67+
initial_stop_ids.append( candidate_stop )
68+
current_approx_stop = candidate_stop
69+
break
70+
71+
for i in range(0, n_stops):
72+
# initial_value=1+i for simulating situation, in which we don't
73+
# know good start solution or greed heuristic, but know, what solution must contain unique stops
74+
# initial_stop_ids[i] for using greed heuristic
75+
planning_stop = CotStop(stop_id=i, location_list_id=GJInteger(1, n_locations-1, False, initial_stop_ids[i]))
76+
planning_path_stops.append(planning_stop)
77+
78+
return planning_path_stops

0 commit comments

Comments
 (0)