1+ #!/usr/bin/env python
2+ # -*- coding: utf-8 -*-
3+
4+ """
5+ Parsing utilities for the Vehicle Routing Problem with Time Window Constraints
6+
7+ This script contains functions for parsing input data and creating the necessary
8+ graph structures for solving the Vehicle Routing Problem with Time Window Constraints (VRPTW).
9+ It includes functions for reading and processing node, edge, request, and vehicle data from CSV files.
10+
11+ Functions included:
12+ - get_full_graph: Read input data and construct the full graph.
13+ - convert_to_minutes: Convert a time string in HH:MM format to total minutes.
14+ - read_nodes: Read node data from a CSV file and classify nodes based on requests and vehicles.
15+ - read_edges: Read edge data from a CSV file.
16+ - create_graph: Create a directed graph using nodes and edges data.
17+ - get_requests: Read and parse request data from a CSV file.
18+ - get_vehicles: Read and parse vehicle data from a CSV file.
19+
20+ Dependencies:
21+ - csv: For reading CSV files.
22+ - networkx: For graph operations.
23+ """
24+
25+ __author__ = "Danial Chekani"
26+ __email__ = "danialchekani@arizona.edu"
27+ __status__ = "Dev"
28+
129import csv
230import networkx as nx
331
4- def get_full_graph (base_directory ):
5- # Read input data including vehicles, request, nodes and edges
32+ def get_full_graph (base_directory : str ) -> tuple :
33+ """
34+ Read input data including vehicles, requests, nodes, and edges, and construct the full graph.
35+
36+ Parameters
37+ ----------
38+ base_directory : str
39+ The base directory containing the CSV files for nodes, edges, requests, and vehicles.
40+
41+ Returns
42+ -------
43+ tuple
44+ A tuple containing the graph, requests dictionary, and vehicles dictionary.
45+ """
646 nodes_file = base_directory + "Nodes.csv"
747 edges_file = base_directory + "Edges.csv"
848 requests = get_requests (base_directory + "Requests.csv" )
@@ -11,28 +51,56 @@ def get_full_graph(base_directory):
1151
1252 return graph , requests , vehicles
1353
14- def convert_to_minutes (time_str ):
15- # Split the string into hours and minutes
54+ def convert_to_minutes (time_str : str ) -> int :
55+ """
56+ Convert a time string in HH:MM format to total minutes.
57+
58+ Parameters
59+ ----------
60+ time_str : str
61+ The time string in HH:MM format or just hours.
62+
63+ Returns
64+ -------
65+ int
66+ The total time in minutes.
67+ """
1668 parts = time_str .split (':' )
1769
18- # Convert hours to minutes
1970 if len (parts ) == 2 :
2071 hours = int (parts [0 ])
2172 minutes = int (parts [1 ])
2273 else :
2374 hours = int (time_str )
2475 minutes = 0
2576
26- # Convert to total minutes
2777 total_minutes = hours * 60 + minutes
2878 return total_minutes
2979
30- def read_nodes (nodes_file , requests , vehicles ):
80+ def read_nodes (nodes_file : str , requests : dict , vehicles : dict ) -> dict :
81+ """
82+ Read node data from a CSV file and classify nodes based on requests and vehicles.
83+ Each line has a format of (Node_ID, X, Y, Name : Optional)
84+
85+ Parameters
86+ ----------
87+ nodes_file : str
88+ The file path to the nodes CSV file.
89+ requests : dict
90+ A dictionary of requests where keys are request IDs.
91+ vehicles : dict
92+ A dictionary of vehicles where keys are vehicle IDs.
93+
94+ Returns
95+ -------
96+ dict
97+ A dictionary where keys are node IDs and values are node attributes.
98+ """
3199 nodes = {}
32100 with open (nodes_file , 'r' ) as file :
33101 reader = csv .reader (file )
34102 next (reader , None )
35- for i , line in enumerate ( reader ) :
103+ for line in reader :
36104 node_id = int (line [0 ])
37105 x = float (line [1 ])
38106 y = float (line [2 ])
@@ -46,25 +114,58 @@ def read_nodes(nodes_file, requests, vehicles):
46114 nodes [destination ]['node_type' ] = 'Delivery Node'
47115
48116 for vehicle_id , vehicle in vehicles .items ():
49- origin , destination , _ = vehicle
117+ origin , destination , _ , _ = vehicle
50118 nodes [origin ]['node_type' ] = 'Depot Node'
51119 nodes [destination ]['node_type' ] = 'Depot Node'
52120
53121 return nodes
54122
55- def read_edges (filename ):
123+ def read_edges (filename : str ) -> dict :
124+ """
125+ Read edge data from a CSV file.
126+ Each line has a format of (Edge_ID, Origin, Destination, Travel_Time, Distance)
127+
128+ Parameters
129+ ----------
130+ filename : str
131+ The file path to the edges CSV file.
132+
133+ Returns
134+ -------
135+ dict
136+ A dictionary where keys are edge IDs and values are edge attributes.
137+ """
56138 edges = {}
57139 with open (filename , 'r' ) as file :
58140 reader = csv .reader (file )
59141 next (reader , None )
60- for i , line in enumerate ( reader ) :
142+ for line in reader :
61143 edge_id , source , target , travel_time , distance = line
62144 edges [edge_id ] = {'edge_id' : edge_id , 'origin' : int (source ),
63145 'destination' : int (target ), 'travel_time' : float (travel_time ),
64146 'distance' : float (distance )}
65147 return edges
66148
67- def create_graph (nodes_file , edges_file , requests , vehicles ):
149+ def create_graph (nodes_file : str , edges_file : str , requests : dict , vehicles : dict ) -> nx .DiGraph :
150+ """
151+ Create a directed graph using nodes and edges data.
152+
153+ Parameters
154+ ----------
155+ nodes_file : str
156+ The file path to the nodes CSV file.
157+ edges_file : str
158+ The file path to the edges CSV file.
159+ requests : dict
160+ A dictionary of requests where keys are request IDs.
161+ vehicles : dict
162+ A dictionary of vehicles where keys are vehicle IDs.
163+
164+ Returns
165+ -------
166+ nx.DiGraph
167+ A directed graph with nodes and edges added.
168+ """
68169 G = nx .DiGraph ()
69170
70171 nodes = read_nodes (nodes_file , requests , vehicles )
@@ -73,6 +174,7 @@ def create_graph(nodes_file, edges_file, requests, vehicles):
73174 for index , (key , value ) in enumerate (nodes .items (), start = 0 ):
74175 G .add_node (index , ** value )
75176
177+ # Add edges in both directions
76178 for index , (key , edge ) in enumerate (edges .items (), start = 0 ):
77179 G .add_edge (edge ['origin' ], edge ['destination' ], travel_time = edge ['travel_time' ],
78180 distance = edge ['distance' ], id = edge ['edge_id' ])
@@ -81,12 +183,28 @@ def create_graph(nodes_file, edges_file, requests, vehicles):
81183
82184 return G
83185
84- def get_requests (filename ):
186+ def get_requests (filename : str ) -> dict :
187+ """
188+ Read and parse request data from a CSV file.
189+ Each line has a format of (Request_ID, Origin_ID, Destination_ID, Number_of_people,
190+ Earliest_departure_origin, Latest_departure_origin, service_time_origin,
191+ Earliest_departure_destination, Latest_departure_destination, service_time_destination)
192+
193+ Parameters
194+ ----------
195+ filename : str
196+ The file path to the requests CSV file.
197+
198+ Returns
199+ -------
200+ dict
201+ A dictionary where keys are request IDs and values are tuples containing request details.
202+ """
85203 requests = {}
86204 with open (filename , 'r' ) as file :
87205 reader = csv .reader (file )
88206 next (reader , None )
89- for i , line in enumerate ( reader ) :
207+ for line in reader :
90208 request_id = int (line [0 ])
91209 origin = int (line [1 ])
92210 destination = int (line [2 ])
@@ -102,15 +220,30 @@ def get_requests(filename):
102220 latest_departure_d , service_time_d )
103221 return requests
104222
105- def get_vehicles (filename ):
223+ def get_vehicles (filename : str ) -> dict :
224+ """
225+ Read and parse vehicle data from a CSV file.
226+ Each line has a format of (Vehicle_ID, Origin_depot, Destination_depot, Capacity, Bus_type)
227+
228+ Parameters
229+ ----------
230+ filename : str
231+ The file path to the vehicles CSV file.
232+
233+ Returns
234+ -------
235+ dict
236+ A dictionary where keys are vehicle IDs and values are tuples containing vehicle details.
237+ """
106238 buses = {}
107239 with open (filename , 'r' ) as file :
108240 reader = csv .reader (file )
109241 next (reader , None )
110- for i , line in enumerate ( reader ) :
242+ for line in reader :
111243 bus_id = int (line [0 ])
112244 origin_id = int (line [1 ])
113245 destination_id = int (line [2 ])
114246 capacity = int (line [3 ])
115- buses [bus_id ] = (origin_id , destination_id , capacity )
247+ bus_type = int (line [4 ])
248+ buses [bus_id ] = (origin_id , destination_id , capacity , bus_type )
116249 return buses
0 commit comments