diff options
| -rw-r--r-- | configOPP.py | 52 | ||||
| -rw-r--r-- | example1.py | 151 | ||||
| -rw-r--r-- | nodeOPP.py | 68 | ||||
| -rw-r--r-- | readerOPP.py | 75 |
4 files changed, 206 insertions, 140 deletions
diff --git a/configOPP.py b/configOPP.py new file mode 100644 index 0000000..3caad8d --- /dev/null +++ b/configOPP.py @@ -0,0 +1,52 @@ +""" +Global Variables go here + +OPP = OdiParPack +""" + +config = { + 'depot_num': 3, # number of depots + 'veh_types': { # Vehicle type properties (capacity) + 'typeA': 90, + 'typeB': 45, + 'typeC': 30 + }, + 'veh_fleet': { # Initial vehicle fleet locations + 'Lima': { + 'typeA': 4, + 'typeB': 7, + 'typeC': 10 + }, + 'Areq': { + 'typeA': 1, + 'typeB': 3, + 'typeC': 6 + }, + 'Truj': { + 'typeA': 1, + 'typeB': 5, + 'typeC': 8 + } + }, + 'veh_speed': { # Vehicle speed (depends on natural region) (km/h) + 'costa': { + 'costa': 70, + 'sierra': 50, + 'selva': 60 # temporal, no deberian haber tramos costa-selva + }, + 'sierra': { + 'sierra': 60, + 'selva': 55 + }, + 'selva': { + 'selva': 65 + } + }, + 'veh_maint': {}, # Vehicle maintenance plans + 'veh_breakdown_downtime': { # Segun tipo de averia de vehiculos (minutes) + # TODO: double check if values are correct + 'moderada': 12 * 60, + 'fuerte': 72 * 60, + 'siniestro': 0 + } +} diff --git a/example1.py b/example1.py index fdacd9d..da01dd4 100644 --- a/example1.py +++ b/example1.py @@ -1,76 +1,17 @@ +""" +Run project like this: $ python example1 + +TODO: Read "raw" or preprocessed ventas data + +""" + from vrptw_base import VrptwGraph from multiple_ant_colony_system import MultipleAntColonySystem -import numpy as np -import csv import math -import random +import numpy as np import networkx as nx -import matplotlib.pyplot as plt - - -class Node: - """ - Attributes - ---------- - index : int - index - ubigeo : str - 6 digits - lat : float - Latitud (angulo de los Paralelos) en grados sexagesimales - lon : float - Longitud (angulo de los Meridianos) en grados sexagesimales - is_depot : bool - demand : int - ready_time : float - due_time : float - service_time : float - x : float - Aproximacion local, en Km respecto - y : float - Aproximacion local, en Km respecto ("Lima") - - Notes - ----- - Web Mercator projection (BAD): - - x = floor(256 / (2 * math.pi) * 2**(zoom_level) * (lon + math.pi)) - y = floor(265 / (2 * math.pi) * 2**(zoom_level) * (math.pi - math.ln(math.tan( math.pi / 4 + lat / 2 )))) - - x = R * lon - y = R * ln(tan(pi/4 + lat/2) - - Both `lon` and `lat` in radians. - - "Lima": -12.04591952,-77.03049615 (lat, long) - """ - - def __init__(self, index: int, ubigeo, lat, lon, is_depot, - demand, ready_time, due_time, service_time): - super() - self.index = index - self.ubigeo = ubigeo - - if is_depot: - self.is_depot = True - else: - self.is_depot = False - - earth_radius_km = 6371 # Avg. radius - lima_lat = -12.04591952 - lima_lon = -77.03049615 - - self.lat = lat - self.lon = lon - self.x = (lon - lima_lon) * (math.pi / 180) * earth_radius_km - self.y = (lat - lima_lat) * (math.pi / 180) * earth_radius_km - self.x = round(self.x, 3) - self.y = round(self.y, 3) - self.demand = demand - self.ready_time = 0 # ready_time - self.due_time = due_time - self.service_time = service_time +from readerOPP import read_nodes, read_tramos def _deg2rad(degrees): @@ -93,76 +34,6 @@ def distance_between_coordinates(lat1, lon1, lat2, lon2): return earth_radius_km * c -def _read_nodes(depot_num): - """ - Read nodes from input file. - - Attributes - ---------- - depot_num : int - Number of depots - - Returns - ------- - list - List of Nodes. The first `depot_num` nodes are the depots. - """ - depots = [] - no_depots = [] - with open('odiparpack/inf226.oficinas_mod.csv', newline='') as csvfile: - orders = csv.reader(csvfile) - count = 1 - index_customer = depot_num - index_depot = 0 - for row in orders: - if count == 1: - count += 1 - continue - - ubigeo, dept, prov, lat, lon, region_natural, is_depot = row[:7] - demand, ready_time, due_time, service_time = row[7:] - - n = Node( - -1, ubigeo, float(lat), float(lon), - int(is_depot), - demand=float(demand), ready_time=0, - due_time=float(due_time), service_time=60 - ) - - if n.is_depot: - n.index = index_depot - depots.append(n) - index_depot += 1 - else: - n.index = index_customer - no_depots.append(n) - index_customer += 1 - - count += 1 - - return depots + no_depots - - -def _read_tramos(): - """ - Lee archivo de tramos - - Returns - ------- - list - Lista de tuplas con los tramos (ubigeo1, ubigeo2) - """ - tramos = [] - with open('odiparpack/inf226.tramos.v.2.0.csv', newline='') as f: - rows = csv.reader(f) - count = 1 - for row in rows: - if count >= 2: - tramos.append([row[0], row[1]]) - count += 1 - return tramos - - def make_complete_customer_node_graph(nodes, tramos): """ Nodes + Tramos make a network. An undirected graph. But we only care @@ -227,8 +98,8 @@ def make_complete_customer_node_graph(nodes, tramos): def lab(): depot_num = 3 - nodes = _read_nodes(depot_num) - tramos = _read_tramos() + nodes = read_nodes(depot_num) + tramos = read_tramos() nodes, node_dist_mat, len_path = \ make_complete_customer_node_graph(nodes, tramos) diff --git a/nodeOPP.py b/nodeOPP.py new file mode 100644 index 0000000..0f792f4 --- /dev/null +++ b/nodeOPP.py @@ -0,0 +1,68 @@ +""" +Custom Node class for OdiParPack +""" + +import math + +class Node: + """ + Attributes + ---------- + index : int + Index in some arrays + ubigeo : str + 6 digit ID + lat : float + Latitud (angulo de los Paralelos) en grados sexagesimales + lon : float + Longitud (angulo de los Meridianos) en grados sexagesimales + is_depot : bool + demand : int + ready_time : float + due_time : float + service_time : float + x : float + Aproximacion local, en Km respecto + y : float + Aproximacion local, en Km respecto ("Lima") + + Notes + ----- + Web Mercator projection (BAD): + + x = floor(256 / (2 * math.pi) * 2**(zoom_level) * (lon + math.pi)) + y = floor(265 / (2 * math.pi) * 2**(zoom_level) * (math.pi - math.ln(math.tan( math.pi / 4 + lat / 2 )))) + + x = R * lon + y = R * ln(tan(pi/4 + lat/2) + + Both `lon` and `lat` in radians. + + "Lima": -12.04591952,-77.03049615 (lat, long) + """ + + def __init__(self, index: int, ubigeo, lat, lon, is_depot, + demand, ready_time, due_time, service_time): + super() + self.index = index + self.ubigeo = ubigeo + + if is_depot: + self.is_depot = True + else: + self.is_depot = False + + earth_radius_km = 6371 # Avg. radius + lima_lat = -12.04591952 + lima_lon = -77.03049615 + + self.lat = lat + self.lon = lon + self.x = (lon - lima_lon) * (math.pi / 180) * earth_radius_km + self.y = (lat - lima_lat) * (math.pi / 180) * earth_radius_km + self.x = round(self.x, 3) + self.y = round(self.y, 3) + self.demand = demand + self.ready_time = 0 # ready_time + self.due_time = due_time + self.service_time = service_time diff --git a/readerOPP.py b/readerOPP.py new file mode 100644 index 0000000..ccd213e --- /dev/null +++ b/readerOPP.py @@ -0,0 +1,75 @@ +""" +Functions to read input data from files +""" +import csv +from nodeOPP import Node + + +def read_nodes(depot_num): + """ + Read nodes from input file. + + Attributes + ---------- + depot_num : int + Number of depots + + Returns + ------- + list + List of Nodes. The first `depot_num` nodes are the depots. + """ + depots = [] + no_depots = [] + with open('odiparpack/inf226.oficinas_mod.csv', newline='') as csvfile: + orders = csv.reader(csvfile) + count = 1 + index_customer = depot_num + index_depot = 0 + for row in orders: + if count == 1: + count += 1 + continue + + ubigeo, dept, prov, lat, lon, region_natural, is_depot = row[:7] + demand, ready_time, due_time, service_time = row[7:] + + n = Node( + -1, ubigeo, float(lat), float(lon), + int(is_depot), + demand=float(demand), ready_time=0, + due_time=float(due_time), service_time=60 + ) + + if n.is_depot: + n.index = index_depot + depots.append(n) + index_depot += 1 + else: + n.index = index_customer + no_depots.append(n) + index_customer += 1 + + count += 1 + + return depots + no_depots + + +def read_tramos(): + """ + Lee archivo de tramos + + Returns + ------- + list + Lista de tuplas con los tramos (ubigeo1, ubigeo2) + """ + tramos = [] + with open('odiparpack/inf226.tramos.v.2.0.csv', newline='') as f: + rows = csv.reader(f) + count = 1 + for row in rows: + if count >= 2: + tramos.append([row[0], row[1]]) + count += 1 + return tramos |
