Upload
others
View
0
Download
0
Embed Size (px)
Citation preview
I
Equation Chapter 1 Section 1
Proyecto Fin de Grado
Ingeniería de las Tecnologías Industriales
Autor: Javier Rojas Eugui
Tutor: Alejandro Escudero Santana
Dep. Organización Industrial y Gestión de Empresas II
Escuela Técnica Superior de Ingeniería
Universidad de Sevilla
Sevilla, 2018
Resolución de un VRP orientado al comercio
electrónico mediante el algoritmo basado en colonias
de hormigas
III
Trabajo Fin de Grado
Ingeniería de las Tecnologías Industriales
Resolución de un VRP orientado al comercio
electrónico mediante el algoritmo basado en
colonias de hormigas
Autor:
Javier Rojas Eugui
Tutor:
Alejandro Escudero Santana
Profesor Contratado Doctor
Dep. Organización Industrial y Gestión de Empresas II
Escuela Técnica Superior de Ingeniería
Universidad de Sevilla
Sevilla, 2018
V
Trabajo Fin de Grado: Resolución de un VRP orientado al comercio electrónico mediante el algoritmo basado
en colonias de hormigas
Autor: Javier Rojas Eugui
Tutor: Alejandro Escudero Santana
El tribunal nombrado para juzgar el Proyecto arriba indicado, compuesto por los siguientes miembros:
Presidente:
Vocales:
Secretario:
Acuerdan otorgarle la calificación de:
Sevilla, 2018
El Secretario del Tribunal
VII
A mi familia. AMDG
IX
Resumen
Este trabajo Fin de Grado trata de resolver un problema de rutas de vehículos enfocado al comercio electrónico,
(ecVRP). En dicho problema una flota de vehículos es encaminada para servir a un conjunto de clientes partiendo
y finalizando en un mismo almacén. Cada cliente dispone de tres posibles lugares donde ser atendido y cada
lugar es definido por unas coordenadas y una ventana temporal. A cada cliente se le entrega el pedido en solo
uno de estos tres lugares. La resolución se llevará a cabo mediante un algoritmo basado en la colonia de
hormigas, que minimiza el número de vehículos empleados y la distancia total recorrida.
XI
Abstract
This project solve the eCommerce Vehicle Routing Problem (ecVRP), where a vehicle fleet is guided to attend
a set of customers starting and finishing in the same depot. Each customer has three possible locations where it
can be served and each location is defined by a set of coordinates and a time- window constraint. Each customer
can only be served in one location. The solution to this problem uses an algorithm based on Ant Colony
Optimization that minimises the number of used vehicles and the total distance travelled.
XIII
Índice
Resumen IX
Abstract XI
Índice XIII
Índice de Tablas XV
Índice de Figuras XVII
1 Introducción 1 1.1 Objetivos 1 1.2 Estructura del trabajo 3
2 Antecedentes - El comercio electrónico 5 2.1 Tipos de servicio 5 2.2 Datos 6 2.3 Tendencias 7
3 El ecVRP 9 3.1 Definición 9 3.2 Formulación 11 3.3 Estado del arte 13
4 Metodología de resolución 17 4.1 Los métodos de resolución en problemas de distribución 17
4.1.1 Métodos exactos 17 4.1.2 Algoritmos heurísticos 18 4.1.3 Métodos metaheurísticos 19
4.2 La ACO 21 4.2.1 Algoritmos basados en colonias de hormigas 21 4.2.2 Las hormigas 21 4.2.3 ASO 22 4.2.4 ACS 23 4.2.5 MACS-VRPTW 24
4.3 Adaptación de la ACO al problema 27 4.3.1 MACS-ecVRP 27 4.3.2 Función de visibilidad 28 4.3.3 Insertion Heuristic 28 4.3.4 Criterios de finalización 31
5 Resultados 33 5.1 Definición de la experimentación 33 5.2 Calibrado del método 34 5.3 Resultados del MACS-ecVRP 37 5.4 Comparación de resultados con trabajos previos 41
6 Conclusiones 45
7 Referencias 47
8 Anexo: Código de programación 49 8.1 Código principal (MACS-ecVRP, ACS-VEI y ACS-TIME) 49 8.2 Código auxiliar (Insertion Heuristics) 61
XV
ÍNDICE DE TABLAS
Tabla 1: Peso de los costes logísticos sobre el volumen de ventas (Fuente: “Estudio de caracterización del sector
del transporte y la logística en España, 2011, Everis [1]) 1
Tabla 2: Combinaciones de los parámetros escogidos (m y nºit) para la calibración del MACS-ecVRP 35
Tabla 3: Combinaciones de los parámetros escogidos (𝛼 y 𝛽, y 𝜌) para la calibración del MACS-ecVRP 36
Tabla 4: Valores resultantes de la calibración del MACS-ecVRP para los parámetros 𝛼, 𝛽, 𝜌, m y nºit. 37
Tabla 5: Resultados de la batería de problemas R1 para 25 clientes 38
Tabla 6: Resultados para 50 clientes 40
XVII
ÍNDICE DE FIGURAS
Figura 1.1: Nivel de gasto en logística en 2015 (Fuente: Informe sobre logística para comercio electrónico en
España, 2016, Adigital [2]). 2
Figura 2.1 Problemas en las compras realizadas por Internet (Informe B2C) [3] 6
Figura 2.2 Atributos más importantes de las empresas a la hora de decidir el consumidor dónde comprar online.
7
Figura 3.1: Representación gráfica del problema r101 para 5 clientes. 10
Figura 3.2: Representación gráfica de la solución del problema r101 para 5 clientes. 10
Figura 3.3 Diferentes variantes del VRP [13] 15
Figura 4.1. El proceso del MACS-VRPTW (modificación de Gambardella [12]) 25
Figura 4.2 Proceso del ACS-TIME (modificación Gambardella [12]) 26
Figura 4.3 Proceso del ACS-VEI (modificación Gambardella [12]) 27
Figura 4.4: (a) Caso compatible en el que TWCij = 1, (b) Caso incompatible en el que TWCij = 0, Joubert y
Claasen [26] 30
Figura 5.1: Ejemplo del tipo de problemas de Solomon (problema r101, conjunto de problemas R1) 34
Figura 5.2: Solución gráfica representativa de un problema ecVRP. 34
Figura 5.3: Resultados en distancias de la calibración del MACS-ecVRP para los parámetros m y nºit. 35
Figura 5.4: Resultados en nº de vehículos de la calibración del MACS-ecVRP para los parámetros m y nºit.
36
Figura 5.5: Resultados en distancias de la calibración del MACS-ecVRP para los parámetros α y β, y ρ. 37
Figura 5.6: Resultados en nº de vehículos de la calibración del MACS-ecVRP para los parámetros α y β, y ρ.
37
Figura 5.7: Distancia promedios para los problemas de 25 clientes 39
Figura 5.8: Distancias mínimas para los problemas de 25 clientes 39
Figura 5.9: Distancia promedios para los problemas de 50 clientes 40
Figura 5.10: Distancias mínimas para los problemas de 50 clientes 40
Figura 5.11: Comparación de distancia promedio para 25 clientes 41
Figura 5.12: Comparación de distancia mínima para 25 clientes 42
Figura 5.13: Comparación de tiempos en segundos para 25 clientes 42
Figura 5.14: Comparación de distancia promedio para 50 clientes 43
Figura 5.15: Comparación de distancia mínima para 50 clientes 43
Figura 5.16: Comparación de tiempos en segundos para 50 clientes 44
1
1 INTRODUCCIÓN
1.1 Objetivos
a logística en el eCommerce siempre será necesaria, independientemente del tipo de distribuidor que se
encargue de transportar las mercancías (personas, drone, vehículos autoguiados, etc). Es una parte
importante del comercio electrónico, puesto que en la cadena productiva es el punto de conexión entre
el productor y el cliente, y porque forma una parte importante de los gastos involucrados en la venta y fabricación
del producto.
Por lo tanto, la logística en el eCommerce se puede ver de dos formas: como una parte de la cadena productiva
que ha de ser optimizada para la reducción de gastos, y como una oportunidad para aplicar estrategias
empresariales que afectan directamente al cliente. De estos dos modos de ver la logística se podría obtener dos
variables: la primera, los gastos y la segunda, la calidad de servicio al cliente. Es decir, mejorando dichas
variables, se mejora la logística. Se pude definir entonces el problema logístico en el eCommerce como aquel
que intenta reducir los gastos de transporte al mismo tiempo que intenta mejorar la calidad de servicio al cliente.
Ambas intenciones están relacionadas. Para reducir gastos en el transporte es intrínsecamente necesario la
reducción del tiempo del mismo, puesto que el tiempo afecta al consumo de combustible. Pero en el momento
en el que se reduce el tiempo de transporte, se está mejorando también la calidad de servicio, ya que, se está
reduciendo el tiempo de espera del cliente desde que compra el producto hasta que lo recibe.
Es necesario dar una idea de cuánto supone el gasto logístico medio de una empresa para mostrar el grado de
importancia que tiene el transporte en esta. Según el “Estudio de caracterización del sector del transporte y la
logística en España”, Everis [1], aproximadamente el 6’5% del volumen de venta de los sectores de producción
en España representa los costes logísticos, siendo el de transporte un 4%. Es decir, el transporte representa un
62% aproximadamente del total de los costes logísticos.
SECTOR Volumen de negocio del
sector (M€)
Total costes
logísticos Transporte
Gestión de centros y
manipulaciones
(M€) (%) (M€) (%) (M€) (%)
Automoción 39.155,0 2.248,2 5,7% 1.053,8 2,7% 1.194,4 3,1%
Consumo - Retail 125.153,0 10.124,0 8,1% 5.282,0 4,2% 4.842,0 3,9%
Textil 24.300,0 1.679,0 6,9% 1.085,0 4,5% 594,0 2,4%
Farmac. - Sanidad 19.940,0 939,5 4,7% 584,9 2,9% 354,6 1,8%
High Tech 4.903,0 201,1 4,1% 120,7 2,5% 80,4 1,6%
Editorial 7.184,0 665,5 9,3% 515,7 7,2% 149,7 2,1%
Siderurgia 12.597,0 251,9 2,0% 189,0 1,5% 63,0 0,5%
Construcción 143.281,0 8.448,8 5,9% 6.174,2 4,3% 2.274,6 1,6%
Total sectores 376.513,0 24.557,9 6,5% 15.005,2 4,0% 9.552,7 2,5%
Tabla 1: Peso de los costes logísticos sobre el volumen de ventas (Fuente: “Estudio de caracterización del sector
del transporte y la logística en España, 2011, Everis [1])
L
En cuanto a las empresas involucradas en el eCommerce según el “Informe sobre logística para comercio
electrónico en España, 2016” Adigital, [2] su gasto en logística es un 6’9% de media sobre el volumen de ventas,
parecido al de los sectores productivos.
Tanto para el sector productivo como para las empresas de eCommerce el gasto en logística y transporte supone
un elevado porcentaje con respecto a su volumen de negocio. Es, pues, un aspecto crucial para la economía de
la empresa y un punto donde se deben reducir gastos que afectan directamente al cliente.
Por otro lado, desde el punto de vista del servicio al cliente para cualquier empresa en el mercado del eCommerce
la logística y el transporte suponen una gran oportunidad estratégica, un factor que puede determinar el éxito en
el mercado de las empresas eCommerce. En el “Informe sobre logística para comercio electrónico en España”
mencionado anteriormente, en el que participaron más de 2000 empresas de eCommerce para su elaboración,
un 92% de las empresas consideraron la logística como un factor de ventaja competitiva donde “entregar los
productos sin errores, en perfectas condiciones y en el plazo estipulado es fundamental” [2].
En otro estudio elaborado por el equipo de Estudios del ONTSI (Observatorio Nacional de las
Telecomunicaciones y de la Sociedad de la Información) [3], los compradores de productos físicos en una
encuesta de respuesta múltiple señalan como los dos aspectos más importantes por los que se decantan por
compras a través de Internet en vez de compras en negocios físicos son el precio/promociones ofertas (79’3%)
y la comodidad (70%).
Así, pues, este proyecto trata de reducir los gastos de transporte al mismo tiempo que mejora el servicio al cliente
mediante la resolución de un problema de rutas de vehículos enfocada al comercio eléctronico (ecVRP) usando
un algoritmo basado en la colonia de hormigas (MACS-ecVRP). En dicho problema un distribuidor tiene una
flota de vehículos y una cartera de clientes a los cuales tiene que llegar, y cada cliente tiene tres lugares distintos
en los que pueden recibir la mercancía para un intervalo de tiempo determinado. El algoritmo tratará de buscar
una solución óptima o lo más próxima a esta para que el tiempo de reparto sea el mínimo posible al mismo
tiempo que se lo ofrece al consumidor la posibilidad de recibir su entrega en tres puntos distintos.
Es por ello que este proyecto responde a las necesidades de los negocios eCommerce planteadas anteriormente.
Por un lado los gastos de transporte, mediante el algoritmo, se reducen buscando la ruta más corta para atender
a todos los clientes. Y por otro, mediante la reducción de tiempos y, sobretodo, dando la posibilidad a cada
cliente de escoger tres lugares distintos en los que le sea conveniente recoger la mercancía, ajustándose a su
propio horario, se aprovecha el factor de ventaja competitiva que tiene la logística siendo la empresa quien se
ajusta al cliente y no al contrario.
43%
34%
16%
7%
Nivel de gasto en logística en 2015
Entre el 5% y el 10% sobre ventas Menos del 5% sobre ventas
Entre el 10% y el 15% sobre ventas Más de 15% sobre ventas
Figura 1.1: Nivel de gasto en logística en 2015 (Fuente: Informe sobre logística para comercio
electrónico en España, Adigital [2]).
3
1.2 Estructura del trabajo
Para resolver la problemática y alcanzar los objetivos planteados en el apartado anterior (1.1) se lleva a cabo el
presente proyecto, cuya estructura se expone a continuación.
En el capítulo 0, se plantea el contexto en el que el problema del ecVRP se sitúa, explicando los principales
objetivos a los que intenta responder, al mismo tiempo que se ofrece una visión general de la importancia de
tales objetivos.
En el capítulo 2, se muestran los principales servicios que se encuentran en el mercado del eCommerce para
entender el contexto en que se plantea el nuevo servicio al que responde el ecVRP. A continuación se ofrecen
datos de organismos oficiales y de empresas privadas que permiten entender la importancia de los objetivos a
los que el ecVRP responde, es decir el ahorro de costes y de tiempo y la calidad del servicio. Finalmente, se
exponen las tendencias a las que se dirige el mercado del comercio electrónico y cómo las empresas tendrán que
hacerles frente.
En el capítulo 3 se define el ecVRP, así como las variantes de las que proviene. A continuación se propone la
formulación de VRPTW y las restricciones que se le añaden para transformarlo en el ecVRP. Finalmente, se
plantean las principales variantes de los problemas de rutas de vehículos, donde el ecVRP se enmarca.
En el capítulo 4 se propone la metodología de resolución del ecVRP. Para ello, primero se ofrece una visión
global de los principales tipos de algoritmos empleados para la resolución de problemas de rutas de vehículos.
A continuación se profundiza en los algoritmos metaheurísticos basados en colonias de hormigas y en cómo
estos resuelven problemas similares al ecVRP. Por último, se expone la adaptación de algoritmo multiobjetivo
de colonias de hormigas al ecVRP.
En el capítulo 5 se presenta la batería de problemas que el algoritmo diseñado resolverá, así como, la calibración
de este último. A continuación se mostrarán los resultados obtenidos. Finalmente se compararán dichos
resultados con los de otros algoritmos que han resuelto la misma batería.
En el capítulo 6 se recogen las principales conclusiones a las que se han llegado tras el estudio, desarrollo y
finalización del proyecto.
5
2 ANTECEDENTES - EL COMERCIO
ELECTRÓNICO
or comercio electrónico se entiende la compra y venta de bienes, contenidos o servicios a través de Internet
u otros medios informáticos. Concretamente, se referirá siempre a comercio entre empresa y cliente
(B2C). Este apartado se centrará en mostrar los servicios más comunes que se ofrecen para hacer que el
producto llegue al cliente, así como, los principales datos que muestran la magnitud del mercado del comercio
electrónico, los datos que afecten directamente al objeto de estudio del Proyecto y finalmente las tendencias de
dicho mercado.
2.1 Tipos de servicio
La principal característica de este Proyecto es que al cliente se le ofrece un tipo de servicio que puede llegar a
suponer una ventaja competitiva para quien lo ofrezca. Se trata de darle la posibilidad al comprador de recibir
su pedido en diferentes puntos en determinados intervalos de tiempo. Es, pues, importante dar una breve
descripción de los principales servicios de los que disponen los clientes involucrados en el eCommerce, como
muestra Adigital [4], para ser consciente del tipo de diferenciación que supone el servicio que se plantea.
Click & Collect: Consiste en encargar un pedido a través de Internet y, para su recogida, ir a una tienda
de la propia empresa vendedora. Supone una ventaja frente a las empresas que solo venden online, ya
que estas no disponen de tiendas físicas.
Recogida en punto alternativo: Una vez que el consumidor ha comprado el producto, tiene la
oportunidad de recogerlo en uno de estos puntos de conveniencia cuándo y dónde más le convenga.
Ejemplo de estos puntos en España son: Las oficinas de correos o los puntos de recogida de empresas
como Seur, YuPick, Kiala y Celeritas.
Servicios “Prenium”: Este servicio consiste en que una vez haya sido comprado el producto el cliente
podrá recibirlo 24 horas o 48 horas desde el momento de la compra. Supone un mayor gasto logístico,
lo que se traduce en un aumento del precio del producto que no siempre tiene que estar sufragado por
el consumidor.
Servicios de entrega sostenibles: Se refiere a servicios que disminuyen la contaminación ambiental. El
principal ejemplo son los centros de consolidación que se sitúan en zonas periféricas o cercanas al centro
urbano, a los que llegan los productos en grandes vehículos y desde donde parten pequeños transportes
hacia los puntos de entrega.
P
“En el marco de un modelo de negocio integrado y centrado en el cliente,
los consumidores esperan que los productos puedan entregarse o
recogerse allá donde se encuentren. […] las empresas precisan mejores
sistemas de distribución o socios que puedan hacerlo mejor que ellas.”
- Ana García de Madariaga, directora de Servicios Digitales de KPMG
en España -
Como puede verse, el servicio propuesto en el Proyecto no se clasifica en ninguno de los anteriores y se puede
complementar con ellos, es decir no es incompatible. No es un servicio que requiere un esfuerzo de más para
poder hacerse un hueco en el mercado, lo que hace que la viabilidad de este sea mayor. Y lo que es más
importante, supone un valor añadido al producto.
2.2 Datos
En este apartado se muestran los principales datos que afectan al presente proyecto en relación con el comercio
electrónico. Primero se ofrecen datos sobre el volumen de negocio que representa el eCommerce, a continuación
se ofrecen datos que tienen que ver con los principales problemas o quejas de los consumidores de comercio
electrónico, después, datos de los factores más importantes que los consumidores tienen en cuenta al comprar
online, en penúltimo lugar las preferencias de los consumidores en cuanto al horario y al lugar de entrega de sus
pedidos y finalmente los principales factores de los que depende la fidelidad del cliente en el eCommerce. Dichos
datos se centran sobre todo en aspectos como el transporte, la entrega de productos, la calidad de estos servicios
y la importancia que los clientes le dan a estos.
El volumen de negocio total estimado del sector del comercio electrónico en España en 2016 es de 25.354
millones de euros, un 22’2% superior al de 2015. Dicho aumento se debe al contexto macroeconómico actual y
al aumento del número de consumidores a través de Internet. Del total de volumen de negocio, el 28,5%
representa el comercio electrónico de productos físicos, una cifra que acumula 7.209 millones de euros [3].
De todos los compradores de productos físicos, un 21’1% afirma haber tenido algún problema con la compra.
La mayoría de los problemas (un 82’4%) están relacionados con los envíos (no recepción del producto, retraso
en la entrega, recepción en mal estado o con desperfectos) [3].
Figura 2.1 Problemas en las compras realizadas por Internet (Informe B2C) [3]
Por otra parte, en cuanto a los aspectos mejorables en los servicios prestados por las páginas de compra, un
81,7% sostiene que los gastos de envíos y las garantías de cambio o devolución son cruciales. Un 62% apunta a
los precios y un 48’2% a la calidad de entrega.
En un estudio de UPS sobre la experiencia de compra [5], el 58% afirma haber dejado la compra por el alto
precio de los gastos de envíos y un 50% por no llegar al mínimo para obtener un envío gratuito.
Según el Estudio Anual de eCommerce de la asociación IAB Spain [6], la logística juega un papel fundamental
en la elección de una página web. Los encuestados consideraban de gran importancia en una compra online los
gastos de envío gratuito (55%), el plazo de entrega rápido (52%) y el seguimiento del pedido (44%).
En otro estudio a nivel global sobre el eCommerce realizado por KPMG [7], los dos atributos más importantes
de las empresas a la hora de decidir el consumidor dónde comprar online son: el precio más bajo (57%) y las
opciones de entrega (43%).
38.40%
36.30%
39.20%
82.40%
15.70%
4.40%
19.00%
Llegada del producto con retraso
No recepción del producto
Producto en malas condiciones
QUEJAS RELACIONADASCON ENVÍOS
Problemas para su devolución
Problemas medio pago
QUEJAS NORELACIONADAS CON ENVÍOS
7
Figura 2.2 Atributos más importantes de las empresas a la hora de decidir el consumidor dónde comprar
online.
Es importante destacar que las principales razones que lleva a los consumidores de eCommerce a realizar la
compras a través de Internet y no por medio de una tienda física son: los precios, las promociones y las ofertas
(75’3%); la comodidad (68’6%), y el ahorro de tiempo (45’7%). Como indica el estudio sobre el comercio
electrónico realizado por la ONTSI [3].
Del mismo modo, en el informe de KPMG [7] mencionado anteriormente, los cuatro primeros motivos por los
que los consumidores optan por las tiendas online en vez de las tiendas físicas están relacionados con la
comodidad y los precios. La posibilidad de comprar es la principal razón (58%), seguida de la posibilidad de
comparar precios (54%), la siguiente que se encuentra es la cantidad de ofertas online (46%) y finalmente,
ahorrar tiempo (40%).
Según los estudios de la ONTSI [3], en relación con el lugar de entrega del producto, el 80’1% de las entregas
se producen en casa, mientras el 8’11% en la oficina y el 5’1% en consignas. En relación al momento en el que
los clientes reciben sus compras, la situación es bastante heterogénea. Un 25’3% por la mañana, un 13’8% a
mediodía, un 34’4% por la tarde, un 8’8% por la noche y un 16’5% muestra indiferencia.
Estos últimos datos son de gran importancia en el modelado del proyecto, pues dan una idea de cómo ajustar la
situación de los clientes y, sobretodo, las ventanas temporales. Acercándose así de manera más fiel a la realidad.
El 93’1% de los usuarios de Internet que adquiere un servicio o producto a través de una página web afirma
repetir en la misma. La fidelidad es un factor importante a tener en cuenta, puesto que refleja el grado de
competitividad de una web, así como, la calidad de los servicios que ofrece. Esta supone también uno de los
principales objetivos a seguir por los vendedores. Los factores que determinan la fidelidad en una web son: los
precios (65’7%), la variedad de productos (39’8%) y las garantías (35’5%). [3]
Como se puede comprobar el factor más importante en el comercio electrónico es el precio; tanto el precio de
los productos como el de los gastos de envíos. También se puede ver que el segundo factor más importante es
el tipo de servicio que se adapta al cliente: calidad de entrega, opciones de entrega, comodidad, plazo de entrega,
ahorro de tiempo y seguimiento del pedido. Ambos factores son los recogidos en los objetivos del proyecto.
2.3 Tendencias
Como se mencionó en el apartado 2.2, el volumen de negocio del eCommerce en España fue de 25.354 millones,
un 22’2% más que en 2015, que fue de 20.745 millones. A su vez el crecimiento que supuso en 2015 con
respecto a 2014 fue de un 27’5%. La tendencia creciente se mantiene pero se puede comprobar que se está
produciendo una desaceleración.
57.00%
43.00%
40.00%
34.00%
33.00%
26.00%
23.00%
21.00%
21.00%
20.00%
16.00%
10.00%
Precio más bajo
Opciones de entrega
Política de devoluciones sencilla
Opciones de pago
Posibilidad de comprobar si el producto está en stock
Información sobre elementos y origen del producto
Experiencia de compra consistente y sin barreras en todos los canales
Programa de incentivos o recompensas para nuevos clientes
Promociones personalizadas
Posibilidad de comprar online y recoger en tienda física
Promoción de tiempo limitado
Presencia en redes sociales
Las principales barreras que se está encontrando el comercio electrónico en España y que, en parte, son causa
de la desaceleración son, principalmente, la preferencia por ver el producto físicamente, la desconfianza en la
seguridad de la compra y la falta de necesidad.
Un estudio de análisis del eCommerce realizado por Deloitte [8], propone a las empresas vendedoras centrarse
en varios aspectos que son y seguirán siendo importantes para atraer consumidores. Precisamente sugiere romper
dichas barreras ofreciendo canales de confianza basados en las redes sociales, que influencian en las decisiones
de compra, y al mismo tiempo, sugiere mejorar las herramientas de decisión, que aumentan por ejemplo la
calidad en la que se muestran los artículos o les dan la oportunidad de ver los artículos en 3D.
Otras de las mejoras que propone dicho estudio son que las empresas ofrezcan servicios de entrega inmediata y
que desarrollen estrategias internacionales más personalizadas en los ámbitos locales.
El estudio de KPMG [7], comparte varias de las proposiciones de Deloitte, pero añade otras como las
posibilidades de pago según el país en el que se vende; la importancia de la confianza y el contacto con la
empresa, y el factor estratégico que suponen las opciones de entrega.
En conclusión, las tendencias del mercado del comercio electrónico van enfocados al aumento de la confianza
en los canales de compra, a la reducción de precios de distribución y a la mejora de la calidad de entrega de los
productos. Como se refleja en los datos mostrados el asunto del proyecto responde a una clara necesidad actual
y futura que los consumidores del comercio electrónico demandan.
9
3 EL ECVRP
n este capítulo se define el Problema de rutas de vehículos para el comercio electrónico (ecVRP). A
continuación se muestra la formulación matemática que parte del VRPTW para luego modificarlo y
obtener la formulación del ecVRP. Finalmente se presentan las principales variantes de la familia de
VRP, en la que se encuentra el ecVRP.
3.1 Definición
El problema de rutas de vehículos para el comercio electrónico (eCommerce Vehicle Routing Problem, ecVRP),
surge de la necesidad de mejorar el servicio al cliente en el mercado del eCommerce, reduciendo tiempos de
entrega, gastos de envíos y adaptándose el servicio al cliente y no al contrario. Como se ha mostrado en el
capítulo 2 son muchos los estudios que identifican y avalan dicha necesidad. Todos coinciden en que la logística
y los gastos de envíos son factores clave que condicionan enormemente la compra a través de Internet. Por otro
lado, tanto los estudios actuales como las tendencias del mercado del eCommerce indican la gran importancia
que tiene para el cliente el servicio que recibe, donde se específica concretamente, el ahorro del tiempo y la
calidad de entrega. Además indican que la evolución del mercado dependerá de cómo se superen las barreras
con las que actualmente el comercio electrónico se está topando, donde un factor clave consistirá en cómo el
servicio al cliente, es decir la entrega, se adapta a los consumidores.
Para responder a dicha necesidad de adaptación al cliente, de mejora de la calidad de servicio y de reducción de
los tiempos de entrega surge el ecVRP, donde a cada cliente se le dará la posibilidad de ser atendido en diferentes
lugares y durante intervalos de tiempos determinados, según la necesidad de cada uno. Para ello el distribuidor
dispondrá de una flota de vehículos que atenderá a todos los clientes, al mismo tiempo que intenta reducir los
tiempos de entrega. Las características del problema y sus restricciones se exponen a continuación:
Cada cliente 𝑧 es definido por un conjunto G de lugares en los que ser atendido y una demanda de
productos 𝑞𝑧.
Cada lugar 𝑖, a su vez, es definido por una ventana temporal {𝑒𝑖, 𝑙𝑖} y unas coordenadas {𝑥𝑖, 𝑦𝑖}. Las
ventanas temporales, indican a partir de qué momento un vehículo puede llegar a un destino y a partir
de qué momento dicho destino deja de estar disponible.
Todos los vehículos parten y finalizan en un mismo depósito, además cada uno dispone de una capacitad
de carga limitada 𝑄.
Cada cliente se le atiende una, y solo una, vez en uno de los lugares que tiene asociado.
El depósito también tiene una ventana temporal {𝑒0, 𝑙0}, que se puede entender como el horinzonte
temporal del problema.
En la literatura de los problemas de distribución el ecVRP se puede entender como un problema perteneciente a
la familia de los VRP. Este tipo de problemas nace formalmente al final de los años 50 del siglo pasado en el
que Dantzig y Ramser [9] plantean la formulación del problema de suministrar gasolina desde una terminal de
carga a un gran número de gasolineras (“The Truck Dispatching Problem"). Desde entonces una gran cantidad
de variantes han ido surgiendo dando respuestas a muchos problemas de distribución de la vida real.
Concretamente, el ecVRP deriva de una de las variantes del VRP, el problema de rutas de vehículos con ventanas
temporales (Vehicle Routing Problem with time Windows, VRPTW). De hecho este último se podría entender
como una particularización del ecVRP, donde el conjunto G de lugares asociados a un cliente es de tamaño 1.
El VRPTW ha sido uno de los problemas de distribución más estudiados, lo que implica que muchos de los
estudios que se le han hecho pueden ser aplicados al ecVRP, como se verá a lo largo del documento.
E
Gráficamente el problema del ecVRP se representa del siguiente modo:
Figura 3.1: Representación gráfica del problema r101 para 5 clientes.
En la figura anterior (Figura 3.1) se puede observar la distribución en el mapa de los clientes y del depósito del
problema r101 (este tipo de problema se explicará en el apartado 5.1) en ella cada nodo (𝑧, 𝑔) está definido por
un cliente 𝑧 y un número identificativo del destino 𝑔 donde el cliente puede ser servido. En este caso cada cliente
tiene la posibilidad de recibir el pedido en tres lugares distintos, por lo que 𝑔 puede tomar los valores 1, 2 y 3.
El número de clientes escogido, por facilidad de visualización es 5, por lo tanto 𝑧 ∈ [1,5]. Por ejemplo, el nodo
(4,2) indica el destino número 2 del cliente número 4. Los puntos azules para un cliente cualquiera 𝑧 representan
el destino 𝑔 = 1, los puntos rojos el destino 𝑔 = 2 y los puntos verdes el destino 𝑔 = 3. De tal modo que el
problema resuelto queda del siguiente modo:
Figura 3.2: Representación gráfica de la solución del problema r101 para 5 clientes.
11
Donde se ha resuelto el problema r101 para cinco clientes. Cabe destacar que en este caso la solución obtenida
resuelve un problema en el que la restricción de la capacidad del vehículo es igual a 20, ya que de este modo el
algoritmo se ve obligado a usar más rutas para servir a todos los clientes y por lo tanto se hace más fácil ver y
entender el concepto de ruta. En la Figura 3.2 un vehículo sigue la ruta [0,1,5,2,0], mientras que el otro vehículo
sigue la ruta [0,4,3,0].
3.2 Formulación
Para la formulación del ecVRP, se parte primero del VRPTW, por su facilidad de expresión y compresión, y
finalmente se indican las nuevas modificaciones y se añaden las restricciones que dan lugar al ecVRP.
Formalmente el VRPTW se puede describir de la siguiente manera: dado un gráfico 𝐺 = (𝑉, 𝐴), donde 𝑉
representa el conjunto de vértices del problema de tamaño n + 1, V = (v0, v1, v2, … , v𝑛) y 𝑛 es el número
de clientes o ciudades y 1 representa al depósito; 𝐴 es un conjunto de arcos, 𝐴 = (𝑣𝑖, 𝑣𝑗): 𝑣𝑖, 𝑣𝑗 𝑉 𝑖 ≠ 𝑗.
Existe un número máximo de vehículos 𝐾, para ser escogidos y guiados, con una capacidad 𝑄 idéntica para
todos los vehículos. Cada cliente 𝑖 ∈ 𝑉 tiene una demanda positiva 𝑝𝑖, un tiempo se servicio 𝑠𝑖, y una ventana
temporal {𝑒𝑖, 𝑙𝑖}. Los datos 𝑒𝑖 y 𝑙𝑖 son la hora más temprana y más tardía a la que puede empezar la entrega,
respectivamente. A cada arco se le asocia un coste 𝐶𝑖𝑗 y un tiempo de recorrido 𝑡𝑖𝑗. La variable binaria 𝑥𝑖𝑗𝑘 toma
el valor 1 si el vehículo 𝑘 escoge ir de la ciudad 𝑖 a la ciudad 𝑗 y valor 0 en otro caso. La demanda de todos los
clientes ha de ser satisfecha y las ventanas temporales tienen que ser respetadas. No obstante, el problema se
representa matemáticamente de la siguiente forma:
Minimizar:
∑ ∑ ∑ 𝑐𝑖𝑗
𝑗∈𝑉
𝑥𝑖𝑗𝑘
𝑖∈𝑉𝑘∈𝐾
(1)
Sujeto a:
∑ ∑ 𝑥𝑖𝑗𝑘 = 1
𝑗∈𝑉𝑘∈𝐾
∀𝑖 ∈ 𝑉 (2)
∑ 𝑞𝑖 ∑ 𝑥𝑖𝑗𝑘
𝑗∈𝑉𝑖∈𝑉
≤ 𝑄 ∀𝑘 ∈ 𝐾 (3)
∑ 𝑥0𝑗𝑘
𝑗∈𝑉
= 1 ∀𝑘 ∈ 𝐾 (4)
∑ 𝑥𝑖,𝑛+1𝑘
𝑖∈𝑉
= 1 ∀𝑘 ∈ 𝐾 (5)
∑ 𝑥𝑖𝑢𝑘
𝑖∈𝑉
− ∑ 𝑥𝑢𝑗𝑘 = 0
𝑗∈𝑉
∀𝑢 ∈ 𝑉, ∀𝑘 ∈ 𝐾 (6)
𝑏𝑖𝑘 + 𝑠𝑖 + 𝑡𝑖𝑗 ≤ 𝑏𝑗
𝑘 + 𝐻(1 − 𝑥𝑖𝑗𝑘 ) ∀𝑖, 𝑗 ∈ 𝑉, ∀𝑘 ∈ 𝐾 (7)
𝑒𝑖 ≤ 𝑏𝑖𝑘 ≤ 𝑙𝑖 ∀𝑖 ∈ 𝑉, ∀𝑘 ∈ 𝐾 (8)
𝑥𝑖𝑗𝑘 ∈ {1,0} ∀𝑖, 𝑗 ∈ 𝑉, ∀𝑘 ∈ 𝐾 (9)
La función (1) representa la función objetivo del problema. La inecuación (2) se asegura de que todos los clientes
sean visitados. La inecuación (3) es la correspondiente a la restricción de la capacidad. Las inecuaciones (4) y
(5) obligan a que el vehículo salga del depósito, y al final de la ruta llegue a él. La restricción (6) obliga a un
vehículo salir de una ciudad después de que entre en ella. La inecuación (7) asegura que si el vehículo viaja de
la ciudad 𝑖 a la ciudad 𝑗 no pueda llegar a 𝑗 antes del tiempo (𝑏𝑖𝑘 + 𝑠𝑖 + 𝑡𝑖𝑗), donde 𝐻 es lo suficientemente
grande como para que en caso de que el vehículo no viaje de la ciudad 𝑖 a la ciudad 𝑗 se desprecie dicha
restricción. La inecuación (8) obliga a que el vehículo llegue a la ciudad 𝑖 dentro de los límites temporales. Por
último, la restricción (9) define la variable binaria 𝑥.
Se acaba de mostrar la formulación matemática para el VRPTW, para la variante que se trata en el proyecto,
ecVRP, se debería modificar ligeramente la formulación anterior. Para ello se define 𝑍 como el número de
clientes del problema y 𝐺 como el número de destinos posibles para cada cliente, que en el caso del presente
proyecto vale 3. La variable binaria 𝑦𝑧𝑔𝑘 indica si la ciudad 𝑔 del cliente 𝑧 es visitada por el vehículo 𝑘. Para
poder añadir las nuevas expresiones al problema, es importante aclarar ciertos aspectos de esta nueva variante
en relación con las variables del VRPTW:
La ecuación (2) ha de ser sustituida por las ecuaciones (11) y (12).
El número de ciudades de cada cliente por el número de clientes es proporcional al número de ciudades
del problema anterior, sin tener en cuenta el depósito. Por lo tanto 𝐺 ∗ 𝑍 = 𝑁 − 1.
Para relacionar cada ciudad del problema anterior con las ciudades de cada cliente se usa la siguiente
expresión: 𝑗 = 𝑧 ∗ 𝐺 − (𝐺 − 𝑔), donde z representa un cliente cualquiera y g representa una ciudad
cualquiera de dicho cliente. Por ejemplo, en un problema con 10 clientes y 3 ciudades por cada cliente,
la ciudad 2 del cliente 5 del ecVRP sería la ciudad 5 ∗ 3 − ( 3 − 2) = 14 del VRPTW, o la ciudad 1
del cliente 1 sería la ciudad 1 ∗ 3 − ( 3 − 1) = 1, también se cumpliría para la ciudad 3 del cliente 10:
10 ∗ 3 − ( 3 − 3) = 30.
𝑦𝑧𝑔 𝑘 = {
1, 𝑠𝑖 𝑙𝑎 𝑐𝑖𝑢𝑑𝑎𝑑 𝑔 𝑑𝑒𝑙 𝑐𝑙𝑖𝑒𝑛𝑡𝑒 𝑧 𝑒𝑠 𝑣𝑖𝑠𝑖𝑡𝑎𝑑𝑎 𝑝𝑜𝑟 𝑒𝑙 𝑣𝑒ℎí𝑐𝑢𝑙𝑜 𝑘0, 𝑒𝑛 𝑜𝑡𝑟𝑜 𝑐𝑎𝑠𝑜
(10)
∑ ∑ 𝑦𝑧𝑔𝑘 = 1
𝑔∈𝐺𝑘∈𝐾
∀𝑧 ∈ 𝑍 (11)
∑ 𝑥(𝑖)(𝑧∗𝐺−(𝐺−𝑔))𝑘 = 𝑦𝑧𝑔
𝑘
𝑖∈𝑉
∀𝑧 ∈ 𝑍, ∀𝑔 ∈ 𝐺 (12)
𝑦𝑧𝑔𝑘 ∈ {1,0} ∀𝑧 ∈ 𝑍, ∀𝑔 ∈ 𝐺, ∀𝑘 ∈ 𝐾 (13)
La ecuación (11) obliga a que todos los clientes sean visitados una, y solo un, vez. La ecuación (12) es la que
hace de conexión entre el ecVRP y el problema anterior. Para ello en la variable 𝑥𝑖𝑗𝑘 se ha sustituido el término
𝑗 por 𝑧 ∗ 𝐺 − (𝐺 − 𝑔). La ecuación (13) define los valores que puede tomar la variable 𝑦𝑧𝑔𝑘 .
13
3.3 Estado del arte
El ecVRP es un problema derivado del VRP que surge como respuesta a una necesidad del mundo real, pero no
es la única variante que se puede encontrar del VRP. Son muchas las que han sido desarrollas según el problema
del mundo real al que se intenta adaptar. Entre ellas se pueden destacar el VRPTW, comentada en el apartado
3.1 o el CVRP, que es desde donde parten todas. En este apartado se mostrará las principales variantes del
problema hasta la fecha y algunas de las restricciones más importantes que las diferencian del resto, pero no en
todas puesto que en algunas implicaría la reformulación total del problema.
Existe una variante en la que los vehículos de los que se disponen tienen una capacidad y costes diferentes; este
método es conocido como Heterogeneous Fleet Vehicle Routing Problem (HFVRP). Deriva de este último
problema el Vehicle Routing Problem with a Heterogeneous fleet of vehicles (VRPHE), en el que se añade un
número máximo de vehículos para cada tipo de estos. La introducción de una flota heterogénea implica un
cambio en la función objetivo y otro cambio en la capacidad de los vehículos. Se introduce 𝑇 tipos de vehículos
de manera que 𝑡 ∈ {1,2, … 𝑇}. La constante 𝑄, que en el CVRPTW representa la capacidad de los vehículos,
es sustituida por 𝑝𝑡, que representa la capacidad de un vehículo de tipo 𝑡. Además, el uso de un vehículo de tipo
𝑡 implica un coste 𝑓𝑡. A las restricciones del problema anterior se les añade las siguientes:
Minimizar:
∑ ∑ ∑ 𝑐𝑖𝑗
𝑗∈𝑉
𝑥𝑖𝑗𝑘
𝑖∈𝑉𝑘∈𝐾
+ ∑ ∑ 𝑓𝑘
𝑗∈𝑉
𝑥0𝑗𝑘
𝑘∈𝐾
(14)
Sujeto a:
∑ 𝑞𝑖 ∑ 𝑥𝑖𝑗𝑘 ≤ 𝑝𝑡
𝑗∈𝑉𝑖∈𝑉
∀𝑘 ∈ 𝐾 (15)
En este caso la función (14) sustituye a la función (1) de CVRPTW y la inecuación (15) sustituye a la inecuación
(3).
Otra variante muy estudiada es el Multiple Depot Vehicle Routing Problem (MDVRP), en el cual se dispone de
más de un depósito con una flota de vehículos cada uno y donde a cada cliente se le asigna uno de los almacenes.
De acuerdo con el trabajo de Kulkarni y Bhave (1985) [10], se muestra una formulación matemática cambiando
ciertos aspectos de la formulación del VRP. Se redefine el conjunto de nodos como 𝑉 = {1, … , 𝑁, 𝑁 +1, … , 𝑁 + 𝑀) donde 𝑁 es el número de ciudades y 𝑀 el número de depósitos. Se define la variable auxiliar 𝑦𝑖
para evitar la eliminación del las subrutas. Las restricciones del VRPTW de las ventanas temporales no se tienen
en cuenta para el MDVRP. Se añaden las siguientes restricciones:
∑ ∑ 𝑥𝑖𝑗𝑘 ≤ 1
𝑁
𝑗=1
𝑁+𝑀
i=N+1
∀𝑘 ∈ 𝐾 (16)
∑ ∑ 𝑥𝑖𝑗𝑘 ≤ 1
𝑁
𝑖=1
𝑁+𝑀
i=N+1
∀𝑘 ∈ 𝐾 (17)
𝑦𝑖 − 𝑦𝑗 + (𝑀 + 𝑁)𝑥𝑖𝑗𝑘 ≤ 𝑁 + 𝑀 − 1 Para 1 ≤ 𝑖 ≠ 𝑗 ≤ 𝑁 y
1 ≤ 𝑘 ≤ 𝐾 (18)
Las ecuaciones (16) y (17) verifican la disponibilidad de los vehículos y la ecuación (18) la eliminación de las
subrutas.
En el Open Vehicle Routing Problem el vehículo no finaliza la ruta en el depósito inicial. Este tipo de problema
se emplea, por ejemplo, cuando una empresa que carece de vehículos propio los alquila, por lo que tras finalizar
la última entrega le es indiferente volver al depósito o no. También se puede aplicar para la planificación de rutas
de autobús o de tren, así como para problemas de recogida y entrega donde tras la recogida del último cliente el
vehículo solo tiene que volver por el mismo camino, como propone Salari et al. [11]. El OVRP es conocido,
también por ser un problema NP-Hard, ya que es una generalización del Problema del camino Hamiltoniano.
La única restricción que se ha de modificar en el VRPTW para obtener el modelo del OVRP es la (5), además
de aquellas que guardan relación con las ventanas temporales.
∑ 𝑥𝑖0𝑘
𝑖∈𝑉
= 0 ∀𝑘 ∈ 𝐾 (19)
La ecuación (19) obliga a que el vehículo 𝑘 no se vuelva al depósito.
Otra variante, un poco más simple que la anterior, y muy parecida al VPRP, es la denominada Distance Vehicle
Routing Problem (DVRP) en la que cada vehículo se ve restringido por una distancia máxima que puede
recorrer. Es un tipo de problema que se puede ver fácilmente en la realidad, puesto que dicha distancia suele ser
restringida por factores como el depósito de gasolina o la batería, en el caso de vehículos eléctricos. Para esta
variante se omiten las restricciones del VRPTW que tienen que ver con las ventanas temporales y se añade la
siguiente:
∑ ∑ 𝑥𝑖𝑗𝑘 ∗ 𝑡𝑖𝑗 ≤ 𝐷
𝑗∈𝑉𝑖∈𝑉
∀𝑘 ∈ 𝐾 (20)
La ecuación (20) impide que la distancia recorrida por el vehículo 𝑘 no sea mayor que la distancia máxima
permitida 𝐷.
A la lista de las variantes más estudiadas se le suma el Vehicle Routing Problem with Pick-up and Deliveries,
VRPPD. El objetivo de este problema es que cada vehículo satisfaga una serie de pedidos. Cada pedido está
definido por un punto de recogida, un punto de entrega, y una demanda para ser transportada entre ambos puntos.
Además, no solo tienen por qué ser bienes, también puede referirse a servicios de transporte de animales o
personas, como empresas de transporte privado, como pueden ser Uber o Cabify. Una variante del VRPPD es
el Vehicle Routing Problem with Simultaneous Delivery and Pick-Up Points, VRPSPD, donde la acción de
recoger y entregar se lleva a cabo en el mismo punto, por ejemplo, en el sistema de transporte público, en líneas
de avión o en trenes. Puesto que se habría de reformular el problema completo para el VRPPD no se mostrará
la formulación que la define.
Una variante muy conocida del VRPPD es el Vehicle Routing Problems with Backhauls (VRPB). En este caso
los pedidos de los clientes también son de entrega y recogida, pero al contrario que en el VRPPPD todas las
entregas se han de hacer antes que las recogidas.
El Stochastic Vehicle Routing Problem, SVRP, es un caso más complejo pues ciertas variables del problema no
son deterministas, por lo que pueden ser aleatorias o desconocidas. Casos comunes de este problema son
demandas estocásticas o tiempos de viaje estocásticos.
Por último mencionar una variante más, conocida como Periodic Vehicle Routing Problem (PVRP), introducida
por Christofides and Beasley [12]. En ella un conjunto de planificaciones, 𝑆, es dado y cada planificación
contiene un conjunto de días en los que los clientes reciben el servicio. Asignar un cliente a una planificación
implica que el cliente será visitado, recibiendo la misma cantidad de bienes 𝑤𝑖, en cada día descrito en la
planificación. Para este problema se han de tomar tres decisiones: seleccionar una planificación para cada cliente,
asignar los clientes a los vehículos y generar rutas para ser mejoradas en cada periodo del horizonte temporal.
15
Figura 3.3 Diferentes variantes del VRP [13]
17
4 METODOLOGÍA DE RESOLUCIÓN
l ecVRP es un tipo de problema que se engloba dentro de la familia de los problemas de distribución. En
este capítulo se mostrará una visión amplia de los algoritmos exactos, heurísticos y metaheurísticos que
se han desarrollado para dar respuesta a este tipo de problemas. A continuación, se profundizará en los
algoritmos basados en colonias de hormigas para finalmente adaptar este tipo de algoritmos al ecVRP,
desarrollando así el algoritmo MACS-ecVRP.
4.1 Los métodos de resolución en problemas de distribución
Los problemas de distribución son un tipo de problema de redes en los que se transporta una serie de unidades
a un conjunto de destinos partiendo de un origen. Este tipo de problemas se caracteriza por la gran dificultad que
supone hallar la solución óptima del problema y por la utilidad que tienen en la vida real. Esto ha dado lugar a
una gran cantidad de métodos que o intentan obtener el óptimo del problema, o bien acercarse lo máximo posible
a él.
4.1.1 Métodos exactos
Los métodos exactos como indica Framiñan et al. [14] son aquellos que garantizan que la solución obtenida tras
aplicar el método es la mejor existente para el problema y según el objetivo marcado. Para poder aplicar un
algoritmo exacto en un tiempo de ejecución razonable es necesario tener en cuenta el tipo de problema y el
tamaño. Hay problemas en los que por su propia naturaleza se han estudiado sus características y se han podido
lograr métodos exactos para garantizar una solución óptima. Sin embargo, hay otros métodos que para poder
obtener una solución óptima se han de evaluar todas las regiones del espacio del problema. Esto implica o
calcular todas las soluciones existentes o bien, evaluar todas las regiones según las soluciones que se van
calculando. El problema de este tipo de métodos en los problemas de distribución es que a medida que los
destinos o clientes van aumentando, aumenta exponencialmente el número de soluciones posibles, lo que hace
que el tiempo de ejecución crezca exponencialmente.
4.1.1.1 Ramificación y poda
El método de Ramificación y poda (Branch and Bound) fue propuesto por primera vez por Christofides,
Mingozzi y Toth [15]. La idea principal del algoritmo es desarrollar un árbol donde cada rama representa una
solución, a su vez, de cada rama saldrán más ramas que representarán más soluciones. Gracias a la información
generada por estas ramas se conoce cuáles son aquellas de las que no saldrá la solución óptima. Por lo tanto,
estas últimas se pueden eliminar (podar) por lo que al final se llegará a la rama con la mejor solución encontrada.
Para el desarrollo y exploración de las ramas se pueden seguir tres estrategias distintas:
Estrategia FIFO: Explora el espacio de soluciones en sentido horizontal, es una búsqueda en anchura.
Estrategia LIFO: La exploración de las soluciones es en profundidad, se explora primero una rama y
todas sus ramificaciones en sentido vertical, cuando se hayan explorado todas estas se pasa a la siguiente
rama.
Estrategia LC: Mediante una función se calcula el coste de las posibles ramas por explorar y según el
coste se escoge la rama con menor coste.
E
4.1.1.2 Ramificación y corte
Este algoritmo se aplica en problemas de enteros lineales en los que algunas restricciones son de carácter entero.
El método resuelve el problema original sin las restricciones enteras, cuando obtiene una solución examina las
variables obtenidas y si una de las que debiera ser entera resulta ser fraccional se busca una desigualdad que sea
satisfecha por todas las variables menos por aquella que no debiera ser fraccional. Una vez encontrada dicha
desigualdad, se añade al problema y se busca de nuevo otra solución, para así aplicarle el mismo procedimiento.
Al final, o se encuentra una solución entera, o no se pueden encontrar más planos de corte.
Cuando se ha encontrado una solución entera no óptima o no se encuentran más planos se procede a emplear el
algoritmo de Ramificación y poda (apartado 4.1.1.2)
4.1.1.3 Ramificación y precio
Conocido en inglés como Branch-and-Price, es un método híbrido entre el de Ramificación y poda y el método
de generación de columnas. Este método consiste en la adicción de columnas para relajar linealmente el
problema cada vez que se explora una nueva rama. Cuando el algoritmo es iniciado la cantidad de columnas es
desmesurada, por lo que se procede a la extracción de algunas de ellas. No existe problema alguno en eliminarlas
pues en una solución óptima el valor de la mayoría de las columnas es nulo. A medida que el algoritmo avanza
se van añadiendo más columnas cada vez que estas sean requeridas.
4.1.2 Algoritmos heurísticos
Los algoritmos heurísticos son aquellos con los que se obtienen soluciones admisibles, sin garantías de que sean
óptimas, de un problema determinado en un tiempo de ejecución menor que un algoritmo exacto. Estos
algoritmos se aplican para problemas en los que, como se comentó en el apartado 4.1.1, los tiempos de ejecución
son desmesurados. Normalmente, suelen encontrar buenas soluciones, de acuerdo a un objetivo, pero dicha
bondad no se garantiza.
4.1.2.1 El Algoritmo de ahorros
El Algoritmo de ahorros, propuesto por Clarke y Wright [16], comienza asignando a cada cliente una ruta propia,
es decir, un vehículo por cada cliente. A continuación, dada dos rutas distintas, (0, … , 𝑖, 0) y (0, 𝑗, … ,0) el
algoritmo intenta unirlas basándose en el coste que proporciona dicha unión:
𝑠𝑖𝑗 = 𝑐𝑖0 + 𝑐0𝑗 − 𝑐𝑖𝑗
Cuando ambas rutas se unen, los arcos (𝑖, 0) y (0, 𝑗) se eliminan para crear el arco (𝑖, 𝑗). El algoritmo siempre
escogerá de todas las uniones posibles aquella cuyo ahorro sea mayor.
Uno de los problemas que suele ocurrir cuando se implementa el algoritmo es que genere rutas circulares, lo que
en ocasiones puede suponer un inconveniente. Por ello se puede modificar la definición de coste original del
siguiente modo:
𝑠𝑖𝑗 = 𝑐𝑖0 + 𝑐0𝑗 − λ𝑐𝑖𝑗
El parámetro λ penaliza aquellas uniones cuya distancia entre nodos sea grande.
4.1.2.2 Heurísticas de Inserción
Las heurísticas de inserción pueden partir o de rutas incompletas o de rutas vacías. Para ello, en el caso de las
rutas incompletas, se calcula el coste de introducir los nodos no incluidos en la solución entre los nodos ya
incluidos. Como en el caso del Algoritmo de ahorros, se escoge el nodo que mayor ahorro proporcione. Para el
caso en el que la ruta esté vacía, el algoritmo simplemente añadirá nuevas rutas cuando sea necesario.
Por otro lado, el método de inserción puede realizarse paralelo o secuencial. En la inserción en paralelo, primero
se crean todas las rutas que se vayan a necesitar y luego según una regla de costes se van completando las rutas,
mientras que en la inserción secuencial, se usa una regla de costes doble. Primero se calcula el mejor cambio
posible para cada nodo con la primera regla de costes, y segundo para todos los mejores cambios posibles de
cada nodo se calcula el coste de inserción según la segunda regla de costes. El máximo de esta última regla es
el que se escoge, y así hasta que no quede ningún nodo fuera de la solución.
19
La inserción secuencial se explicará detalladamente en el apartado 4.3.3, pues se ha empleado como función
auxiliar en el algoritmo del presente proyecto.
4.1.2.3 Algoritmo del vecino más próximo
El algoritmo del vecino más próximo (The nearest neighbour algorithm en inglés) fue uno de los primero
algoritmos en resolver el TSP. Para el VRP cada ruta empieza con el cliente no visitado más “cercano” al
depósito. En cada iteración se selecciona el cliente más “cercano” al último cliente añadido a la ruta. Este
procedimiento finaliza cuando las restricciones (capacidad y ventanas temporales) impidan añadir más clientes.
Una vez se llega a este punto, se inicia una nueva ruta. La cercanía en este algoritmo se entiende como el
resultado de un conjunto de ecuaciones dependientes del tiempo y la distancia.
4.1.2.4 Heurística de asignar primero y encaminamiento después
En este tipo de heurística (cluster first - route second) la resolución de un CVRP se estructura en dos partes:
1. Se reparten todos los clientes en distintos grupos (llamados clusters), según las restricciones del
problema.
2. Para cada cluster se resuelve el problema individualmente como si de un TSP se tratara.
Para el paso primero, son varios los métodos para agrupar clientes en clusters. Se puede, por ejemplo, usar la
técnica de Barrido o Sweep en la que una semirrecta con origen en el depósito va recorriendo el mapa donde se
encuentran los clientes y los va agrupando según se los vaya encontrando. Otra heurística conocida es la
propuesta por Fisher y Jaikumar [17] en la que la agrupación de los clusters se lleva a cabo resolviendo un
Problema de asignación generalizada (GAP). Dicha agrupación se lleva a cabo en dos pasos:
1. Se construyen 𝐾 clusters con un cliente en cada uno.
2. Se reparten los clientes restantes según la asignación generalizada.
4.1.2.5 Búsqueda local
Este tipo de métodos son aquellos que intentan mejora una solución dada mediante pequeñas modificaciones
buscando una nueva solución que mejore y remplace a la anterior. Dichas modificaciones se pueden ejecutar
tanto dentro de una misma ruta como entre diferentes rutas. Cuando una nueva mejora se encuentra se vuelve a
realizar el mismo procedimiento hasta que no se obtenga ninguna mejora más. Son dos las principales estrategias
que se usan para escoger la nueva solución:
First Improvement: Se escoge la primera solución encontrada que mejore a la solución inicial.
Best Improvement: Una vez se han analizado todas las posibles soluciones que superen a la solución
inicial, se escoge la mejor entre todas ellas.
Caben destacar dentro de este tipo de métodos el Operador 𝜆-intercambio y el Algoritmo de Kin-Kernigham.
4.1.3 Métodos metaheurísticos
Los algoritmos metaheurísticos, como define Herrera [18], son aquellos en los que mediante procedimientos
iterativos de carácter general se guían los pasos de una heurística subordinada para explorar y explotar los
espacios de búsqueda de un problema. La metaheurística se suele inspirar en sistemas de la naturaleza como
pueden ser las colonias de hormigas, el proceso de recocido del acero o los mecanismos de evolución entre otros,
al mismo tiempo que emplean técnicas estadísticas para la intensificación y diversificación en la búsqueda de
soluciones.
4.1.3.1 Algoritmos genéticos
Los algoritmos genéticos, introducidos por Holland en 1975 [19], se basan en el proceso genético que existe tras
la evolución biológica. Los seres vivos se agrupan en poblaciones en las que se ven obligado a competir por la
supervivencia, lo más fuertes son los que generan descendencia, la cual será más fuerte y se volverá a ver
obligada a competir, generando, así seres vivos cada vez más fuertes. Este es el principio básico del que parten
los algoritmos genéticos. La forma en la que se aplica es la siguiente:
1. Generación de un conjunto de soluciones factibles y aleatorias del problema a solucionar.
2. Aplicación de una función llamada fitness o de adaptación que comprueba la bondad de las soluciones
obtenidas.
3. Selección de las mejores soluciones de la población anterior según la función fitness.
4. Generación de un nuevo conjunto de poblaciones a partir de las soluciones obtenidas en el paso 3
mediante modificaciones y combinaciones de estas.
5. Vuelta al punto 2 partiendo de las soluciones creadas en el paso 5.
Las soluciones suelen ser representadas de forma vectorial binaria, vectorial real, vectorial directa o en forma de
árbol. La forma vectorial binaria se caracteriza por una gran facilidad de manejo de soluciones durante el
desarrollo del algoritmo, pero de una gran dificultad para la traducción y representación de las soluciones reales.
La vectorial real mejora este último aspecto, pero la complejidad computacional aumenta ligeramente. La
vectorial directa representa directamente los valores exactos de la solución real por lo que la facilidad de
representación es enorme y se elimina la necesidad de conversión. La forma en árbol representa la solución en
forma de árbol de objetos de programación.
4.1.3.2 Recocido simulado
Conocido como Simulated annealing se inspira en la técnica de recocido de metales o cerámicas. Este proceso
consiste en calentar el material a temperaturas suficientemente altas como para que los átomos puedan
desplazarse con cierta facilidad a posiciones de mínima energía, poco a poco el material se va enfriando,
obteniendo así un resultado con mejores propiedades.
El algoritmo comienza con un estado 𝑠 y siguiendo reglas probabilísticas decide entre permanecer en 𝑠 o pasar
a un nuevo estado 𝑠′. A continuación se evalúa el estado vecino, 𝑠′, si resulta ser mejor que el anterior 𝑠′pasa a
ser el nuevo estado 𝑠. En caso contrario, es decir, en caso de que 𝑠′ sea peor que 𝑠, existe una probabilidad de
moverse a dicho estado peor que depende de la función:
𝑃(Δ𝑓, 𝑇) = 𝑒Δ𝑓 𝑇⁄
Siendo Δ𝑓 = 𝑓(𝑠) − 𝑓(𝑠′) y 𝑇 la temperatura, que va disminuyendo a lo largo del desarrollo del algoritmo. De
esta manera el algoritmo puede huir de estancamientos en óptimos locales.
4.1.3.3 Búsqueda tabú
La búsqueda tabú consiste en un algoritmo con ‘memoria’, que partiendo de una solución inicial, se va moviendo
por soluciones vecinas en el espacio del problema al mismo tiempo que almacena datos sobre estas para
encaminar la búsqueda hacia mejores soluciones. La técnica principal consiste en una lista de soluciones que
contiene aquellas que no han dado un resultado favorable, estas se consideran prohibidas, es decir que no pueden
ser escogidas. Cuando se evalúan las soluciones vecinas a la actual para dar el siguiente paso, automáticamente
las que se encuentren en la lista tabú son descartadas. Las soluciones que se encuentren en la lista podrán ser
eliminadas de esta a lo largo del problema según unos determinados criterios. Dependiendo de esta última
habilidad la memoria se puede considerar de corto o largo plazo.
El principal objetivo de la memoria del algoritmo es huir de los óptimos locales evitando soluciones que hayan
dado problemas anteriormente, por lo que una solución no favorable se convierte en una información de mucho
valor para la mejora de la búsqueda.
4.1.3.4 Algoritmo de Colonias de Abejas Artificiales
Conocido globalmente como Bee Colony Optimization, el Algoritmo de Colonias de Abejas Artificiales se
inspira en el funcionamiento de una colmena de abejas y en el modo en que estas encuentran la comida para
resolver problemas de optimización. Para ello la colmena se compone de tres tipos de abejas: empleadas, en
espera y exploradoras. Las abejas empleadas se posicionan en fuentes de alimento, que representan a una
solución, y buscan en la vecindad de ésta solución, la cantidad de fuente de alimentación indica la bondad de
21
dicha solución. La abejas en espera son aquellas que una vez que las empleadas hayan terminado la recolecta
recibirán información de todas estas y elegirán, según una función llamada función danza, las nuevas fuentes de
alimentación a explotar que sustituirán a las anteriores. Por otro lado, las abejas de exploración se encargan de
buscar nuevas fuentes de alimentación. El número de soluciones con las que se trabaja en el problema equivale
al número de abejas empleadas.
4.1.3.5 Búsqueda Cuco (Cuckoo Search)
Este algoritmo se inspira en las características parásitas de puesta o de nido del pájaro cuco. Estos ponen sus
huevos en los nidos de otras aves para aumentar su reproductividad, lo que les proporciona una ventaja evolutiva.
En el algoritmo cada huevo representa una solución, estos son depositados en los nidos de otras aves, donde los
mejores huevos serán los que compongan la siguiente generación de cucos, además estos pueden ser descartados
con una probabilidad 𝑝 ∈ [0,1], que permite la exploración de nuevas soluciones. La forma en la que cada pájaro
cuco escoge el nido donde depositar el huevo es aleatoria lo que, también evita el estancamiento en óptimos
locales. Cabe destacar que este algoritmo fue empleado por Uribe y Escudero [20] para resolver el mismo tipo
de problema del presente trabajo, el ecVRP.
4.2 La ACO
Ant Colony Optimization (ACO) es una metaheurística diseñada para resolver problemas de optimización
combinatoria inspirada en los rastros de feromonas que ciertas especies de hormigas usan para comunicarse
entre ellas. Es un tipo de algoritmo que se engloba dentro de los algoritmos de enjambre, que se caracterizan por
imitar los mecanismos que permiten la inteligencia colectiva en la naturaleza. En este apartado de explicarán
tres algoritmos basados en la ACO: Ant System Optimization (ASO), Ant Colony System (ACS) y Multiple Ant
Colony System (MACS). ASO fue el primero y fue aplicado al TSP, ACS fue aplicado también al TSP y es una
evolución del primero y, por último, MACS fue aplicado al VRP y es una evolución de ACS.
4.2.1 Algoritmos basados en colonias de hormigas
El primer algoritmo basado en las colonias de hormigas fue desarrollado por Marco Dorigo en 1992 [21] en su
tesis doctoral. Para ello usó como base el conocido problema del TSP, aunque no obtuvo resultados que
superaran a los algoritmos de entonces, sí despertó un gran interés por este tipo de algoritmos que se ha visto
reflejado en la cantidad de problemas para los que ha sido desarrollado. Las principales características que hacen
a este tipo de algoritmos tan interesantes son las siguientes:
Versatilidad: Puede ser adapto a una gran cantidad de problemas, por ejemplo, en los primeros años del
algoritmo, se aplicó a la conocida extensión del TSP, Asymmetric Traveling Salesman Problem (ATSP).
Robustez: Puede ser aplicado a otros problemas solo con pequeñas modificaciones como es el caso del
VRP o del ecVRP.
Está basado en poblaciones: Lo que permite estudiar muchos grados de retroalimentación y, además,
como se verá más adelante (apartado 4.2.5), es permite emplear procesos en paralelo.
4.2.2 Las hormigas
En muchas especies de hormigas el mecanismo de comunicación que usan entre ellas se basa en rastros de un
tipo de sustancias químicas llamadas feromonas. Una hormiga individual puede segregar feromona mientras se
dirige a una fuente de alimento. Al mismo tiempo otra, que describe movimientos aleatorios, detecta el rastro y
las probabilidades de seguir a la primera hormiga aumentan considerablemente gracias a la feromona. Este tipo
de comportamiento genera una retroalimentación positiva: mientras más hormigas pasen por el mismo camino,
más hormigas se verán atraídas por este, y más hormigas lo cruzaran hasta que las probabilidades de no seguirlo
sean ínfimas.
En una situación de elección dicotómica una hormiga puede elegir entre dos caminos que le llevarán a una fuente
de alimentación, uno largo y otro corto. Si una hormiga cualquiera aleatoriamente elige el corto y otra del mismo
modo elige el largo, evidentemente la primera llegará antes a la comida. Una vez haya alcanzado la comida
volverá por el mismo camino que había escogido, segregando más feromona que en el camino de ida. Si en este
punto apareciera otra hormiga, esta se sentiría más atraída por el camino corto pues la cantidad de feromona en
el camino sería menor ya que al ser más corto, el tiempo que tarda la feromona en evaporarse es menor. Por lo
tanto, la nueva hormiga tendría más probabilidades de seguir el camino corto que el camino largo. En el
horizonte temporal esta probabilidad sería retroalimentada positivamente por lo que al final la mayoría de las
hormigas escogerían el camino corto.
Este es el principio básico de los algoritmos basados en colonias de hormigas. En un problema de distribución
las soluciones serán construidas mediante mecanismos estocásticos de elección en los que la feromona que se
encontrarán en los distintos caminos del problema jugará un papel fundamental. Gracias a la probabilidad
existente las hormigas no son obligadas a escoger el camino con más feromonas lo que hace posible el aumento
de la búsqueda por regiones del espacio de soluciones aún sin explorar.
4.2.3 ASO
El Ant System Optimization fue introducido por Marco Dorigo en 1996 [22]. Para explicarlo implementó el
algoritmo en el problema del TSP por la facilidad gráfica que este supone y por la facilidad de comparar los
resultados con otras metaheurísticas.
En el TSP dado un número 𝑉 de ciudades y un conjunto de caminos 𝐴, que conecta dichas ciudades, se busca el
camino más corto para visitar a todas y cada una de las ciudades. Para ello se emplea una colonia de hormigas
artificiales con 𝑚 hormigas donde cada una de ellas generará soluciones individualmente. Cada una comienza
en una ciudad distinta escogida al azar y desde allí mediante una función de elección, que depende de la
feromona y de la distancia, selecciona la próxima ciudad a la que visitar hasta que haya visitado todas. Para
evitar que una hormiga 𝑘 visite dos veces la misma ciudad se emplea una lista tabú que guarda todas las ciudades
que vaya visitando, para así prohibir la elección de dicha ciudad otra vez. En la lista 𝐽𝑘(𝑟) se guardarán todas
las ciudades que queden por visitar a la hormiga 𝑘 en el momento 𝑟.
Por otro lado, se define 𝜏𝑖𝑗 como la cantidad de feromona asociado al camino 𝑎𝑖𝑗, es decir, el arco que une la
ciudad 𝑖 con la ciudad 𝑗. En cada iteración del algoritmo todas las hormigas se mueven a otra nueva ciudad al
mismo tiempo, por lo que para que las 𝑚 hormigas completen una solución deben pasar 𝑛 iteraciones. Una vez
se hayan completado todas las iteraciones y se hayan obtenido 𝑚 soluciones, la feromona se actualiza del
siguiente modo:
𝜏𝑖𝑗(𝑡 + 𝑛) = 𝜌𝜏𝑖𝑗(𝑡) + Δ𝜏𝑖𝑗 (21)
Donde 𝜌 es el coeficiente de evaporación (1 < 𝜌 < 0) y Δ𝜏𝑖𝑗 el incremento de feromona entre el tiempo 𝑡 y
𝑡 + 𝑛, que viene dado por la siguiente ecuación:
Δ𝜏𝑖𝑗 = ∑ Δ𝜏𝑖𝑗𝑘
𝑚
𝑘=1
(22)
Donde Δ𝜏𝑖𝑗𝑘 es la feromona que segrega la hormiga artificial 𝑘 en el arco 𝑎𝑖𝑗 entre los tiempos 𝑡 y 𝑡 + 𝑛 y viene
dada por la siguiente ecuación:
Δ𝜏𝑖𝑗𝑘 = {
𝑄
𝐿𝑘, 𝑠𝑖 𝑙𝑎 ℎ𝑜𝑟𝑚𝑖𝑔𝑎 𝑘 𝑢𝑠𝑎 𝑒𝑙 𝑎𝑟𝑐𝑜 𝑎𝑖𝑗 𝑒𝑛𝑡𝑟𝑒 𝑙𝑜𝑠 𝑡𝑖𝑒𝑚𝑝𝑜𝑠 𝑡 𝑦 𝑡 + 𝑛
0 , 𝑒𝑛 𝑜𝑡𝑟𝑜 𝑐𝑎𝑠𝑜
(23)
Donde 𝐿𝑘 es el camino recorrido total por la hormiga 𝑘. Como se ha comentado anteriormente, la feromona es
la encargada de guiar el paso a las hormigas durante la construcción de soluciones. Para ello cada vez que una
hormiga se sitúa en una ciudad 𝑖 tiene una probabilidad 𝑝𝑖𝑗 de elegir a la ciudad 𝑗. Dicha probabilidad se define
con la siguiente expresión:
𝑝𝑖𝑗 = {
[𝜏𝑖𝑗(𝑡)]𝛼 ∗ [𝜂𝑖𝑗(𝑡)]𝛽
∑ [𝜏𝑖𝑢(𝑡)]𝛼 ∗ [𝜂𝑖𝑢(𝑡)]𝛽𝑢∈𝐽𝑘(𝑟)
, 𝑠𝑖 𝑢 ∈ 𝐽𝑘(𝑟) 𝑒𝑛 𝑒𝑙 𝑖𝑛𝑠𝑡𝑎𝑛𝑡𝑒 𝑡 + 𝑛
0, 𝑒𝑛 𝑜𝑡𝑟𝑜 𝑐𝑎𝑠𝑜
(24)
23
La variable 𝜂𝑖𝑗 es conocida como la visibilidad y se define como la inversa entre la distancia euclídea entre dos
ciudades 𝑖 y 𝑗 (𝑑𝑖𝑗 = [(𝑥𝑖 − 𝑥𝑗)2
+ (𝑦𝑖 − 𝑦𝑗)2]1/2), es una constante que en el ASO depende de los datos del
problema.
𝜂𝑖𝑗 = 𝑑𝑖𝑗−1 (25)
Gracias a la visibilidad y a la actualización de la feromona la probabilidad de escoger el camino más corto
aumenta y el algoritmo poco a poco converge hacia una solución que se puede acercar al óptimo del problema
o alcanzarlo. El hecho de que sea una selección estocástica permite que el algoritmo explore otras regiones del
espacio aún sin explorar, lo que permite huir a este de óptimo locales. Los pasos que definen al algoritmo son
los siguientes:
1. Se inicializan los datos, como por ejemplo, Δ𝜏𝑖𝑗 = 𝑐, donde 𝑐 es una constante cualquiera.
2. Las 𝑚 hormigas generan 𝑚 soluciones.
3. Se actualiza la feromona, según las 𝑚 soluciones del paso 2.
4. Se vuelve al paso 2 si no se ha cumplido el criterio elegido para terminar el algoritmo.
5. Fin del algoritmo.
Finalmente, queda remarcar que para el ASO se comprobó que la solución mejoraba considerablemente al iniciar
cada hormiga en un nodo escogido al azar. Es decir, para cada hormiga se escoge aleatoriamente un nodo desde
donde empezará la solución y al que tendrá que llegar tras finalizarla. Este concepto será de relativa importancia
para el MACS-VRPTW.
4.2.4 ACS
Un año después de la publicación del Ant System Optimization se presenta una evolución de este, el Ant Colony
System, Dorigo y Gambardella [23]. En ACS se introducen tres grandes cambios en el algoritmo original:
modificación de la función de selección (exploración-explotación), actualización global y elitista de la
feromona y por último, actualización local de la feromona. Para este algoritmo se parte con las mismas
ecuaciones del algoritmo anterior y con la misma nomenclatura; las variaciones propias del nuevo algoritmo
serán aclaradas.
4.2.4.1 Exploración o explotación
Por explotación se entiende la estrategia que usa el algoritmo para aprovechar todo el conocimiento acumulado
en la variable feromona (𝜏𝑖𝑗) para buscar en la vecindad de las mejores soluciones encontradas hasta la fecha.
Ya que, en los arcos que componen estas soluciones habrá mayor cantidad de feromona que en el resto de arcos.
Por exploración se entiende la estrategia que usa el algoritmo para buscar por nuevas regiones del espacio.
Ambos conceptos se ven reflejado en la siguiente ecuación:
𝑗 = {arg 𝑚𝑎𝑥𝑢∈𝐽𝑘(𝑟) ([𝜏𝑖𝑢(𝑡)]𝛼 ∗ [𝜂𝑖𝑢(𝑡)]𝛽 ) 𝑠𝑖 𝑞 < 𝑞0 (𝐸𝑥𝑝𝑙𝑜𝑡𝑎𝑐𝑖ó𝑛)
𝑆 𝑒𝑛 𝑜𝑡𝑟𝑜 𝑐𝑎𝑠𝑜 (𝐸𝑥𝑝𝑙𝑜𝑟𝑎𝑐𝑖ó𝑛) (26)
Donde 𝑞 es una variable aleatoria uniformemente distribuida que toma valores entre 0 y 1 (1 < 𝑞 < 0) y 𝑞0 es
un parámetro del problema que también toma valores entre 0 y 1 (1 < 𝑞0 < 0). Por otra parte 𝑆 es una variable
aleatoria seleccionada según la ecuación (24), es decir, si 𝑗 = 𝑆 entonces la ciudad 𝑗 vendrá escogida según la
probabilidad 𝑝𝑖𝑗 dada por la ecuación (24). El parámetro 𝑞0 determina la importancia relativa de la explotación
sobre la exploración. Si 𝑞 < 𝑞0 entonces el mejor arco 𝑎𝑖𝑗 según la ecuación (26) es escogido (explotación), de
lo contario se escoge según la ecuación (24) (exploración).
4.2.4.2 Actualización global de la feromona
Mientras que en el ASO tras cada 𝑛 iteraciones se actualizaba globalmente la feromona según la solución creada
por todas las hormigas, en el ACS solo se actualiza según la mejor solución encontrada hasta el momento. En
un principio se barajó la posibilidad de actualizar la feromona según la mejor solución de cada 𝑛 iteraciones, los
resultados eran muy similares, pero actualizar según la mejor solución encontrada hasta el momento superaba
levemente a la otra opción.
Para introducir esta modificación solo se ha de sustituir la ecuación (22) por la siguiente:
Δ𝜏𝑖𝑗 = {
1
𝐿𝑔𝑏, 𝑠𝑖 𝑒𝑙 𝑎𝑟𝑐𝑜 𝑎𝑖𝑗 𝑝𝑒𝑟𝑡𝑒𝑛𝑒 𝑎 𝑙𝑎 𝑚𝑒𝑗𝑜𝑟 𝑠𝑜𝑙𝑢𝑐𝑖ó𝑛 𝑒𝑐𝑜𝑛𝑡𝑟𝑎𝑑𝑎 𝑑𝑒𝑠𝑑𝑒 𝑒𝑙 𝑖𝑛𝑖𝑐𝑖𝑜
0 , 𝑒𝑛 𝑜𝑡𝑟𝑜 𝑐𝑎𝑠𝑜
(27)
Dónde 𝐿𝑔𝑏 representa la longitud de la mejor solución encontrada.
4.2.4.3 Actualización local de la feromona
Actualizar localmente la feromona quiere decir que cada vez que una hormiga 𝑘 pasa por el arco 𝑎𝑖𝑗 la feromona
𝜏𝑖𝑗 asociada a dicho arco es modificada. Esto ocurre en cada iteración y viene dado por la siguiente ecuación:
𝜏𝑟𝑠 = (1 − 𝛾)𝜏𝑟𝑠 + γΔ𝜏𝑟𝑠 (28)
Donde γ es un parámetro que cumple: 0 < γ < 1 y Δ𝜏𝑟𝑠 = 𝜏0. La constante 𝜏0 es la cantidad de feromona
inicial en cada arco 𝑎𝑖𝑗 y viene calculada después de generar una solución inicial:
𝜏0 = (𝑛 ∗ 𝐿𝑛𝑛)−1 (29)
Donde 𝐿𝑛𝑛 es la longitud de la solución obtenida por la heurística encargada de generar la solución inicial, que
para este caso fue la conocida, Nearest Neighbor Heuristic, explicada en el apartado 4.1.2.3.
4.2.5 MACS-VRPTW
El Multiple Ant Colony System es una metaheurística desarrollada por Gambardella, Taillard y Agazzi [24], que
nace como evolución del ACS para ser aplicado al VRPTW. En este problema, ya comentado en el apartado
3.1, se ha de encaminar a una flota de vehículos que se dispone a visitar a un conjunto de clientes cuyos horarios
de visita están restringidos por ventanas temporales. Para ello emplean un algoritmo que intenta minimizar al
mismo tiempo dos objetivos jerarquizados: el primer objetivo es minimizar el número de vehículos empleado y
el segundo es minimizar la distancia total recorrida por todos los vehículos. Al ser jerarquizado, una solución
con menos vehículos se prefiere a una solución con menor distancia.
La forma en la que se adapta esta estrategia a los algoritmos basados en colonias de hormigas es definiendo dos
colonias de hormigas que actúan al mismo tiempo y que comparten cierta información. El objetivo de la primera
colonia, ACS-VEI, es minimizar el número de vehículos empleados, mientras que el objetivo de la segunda
colonia, ACS-TIME, se encarga de mejorar la solución encontrada por ACS-VEI. Ambas colonias actúan al
mismo tiempo y son independientes la una de la otra, solo se comunican a través de la solución factible 𝜓𝑔𝑏.
Esta comunicación es controlada por el MACS-VRPTW. En el caso de que cualquiera de las dos colonias
encuentre una solución factible 𝜓𝑔𝑏 con un menor número de vehículos, esta le enviará la información al
MACS-VRPTW y este eliminará en el momento las dos colonias para así comenzar de nuevo empezando por
la nueva solución encontrada
Por otro lado como se comentó en el apartado 4.2.3 los resultados obtenidos por los algoritmos de colonias de
hormiga mejoran cuando las hormigas comienzan el camino desde un nodo aleatorio del problema. Para el
MACS-VRPTW sucede lo mismo, aunque debido a la naturaleza del VRPTW se hace imposible empezar en un
nodo que no sea el depósito. Por la tanto, para acercarse lo más posible al problema original, se crean tantos
depósitos cómo número de vehículos se dispongan. Estos depósitos, son simple copias virtuales del depósito
original, tienen las mismas coordenadas. La diferencia se refleja en la feromona 𝜏𝑖𝑗, ya que la cantidad de
feromona acumulada en el arco 𝑎0𝑗 o en el arco 𝑎𝑗(𝑛+1), que son los arcos que salen y llegan al depósito
respectivamente, disminuyen porque la feromona se ve repartida entre los distintos depósitos virtuales, lo que
proporciona un aumento de la exploración. Esta es la razón por la que se eliminan las colonias cuando el
algoritmo encuentra una solución con menor número de vehículos, ya que el número de depósitos depende del
25
número de vehículos. Se hace necesario entonces, para modificar el número de depósitos, redefinir totas las
matrices del problema.
A continuación se presenta el pseudocódigo de MACS-VRPTW:
4.2.5.1 ACS-TIME y ACS-VEI
El algoritmo ACS-TIME es el clásico algoritmo de colonia de hormigas, es decir, tiene la misma funcionalidad
y estructura que el ACS pero con ciertas particularidades:
Si el algoritmo encuentra una solución factible 𝜓 con un número menor de vehículos se la envía al
algoritmo principal MACS-VRPTW.
Existe la posibilidad de realizar una búsqueda local para cada solución construida por una hormiga.
La ecuación (21) se modifica del siguiente modo:
𝜏𝑖𝑗 = (1 − 𝜌)𝜏𝑖𝑗 + 𝜌/𝐽𝜓𝑔𝑏
(30)
Donde 𝐽𝜓𝑔𝑏
representa la distancia recorrida en la mejor solución encontrada hasta el momento.
La ecuación que define a la visibilidad cambia totalmente:
𝑇𝑖𝑗 = 𝑏𝑗 − (𝑏𝑖 + 𝑠𝑖) (31)
𝑉𝑖𝑗 = 𝑙𝑗 − (𝑏𝑖 + 𝑠𝑖) (32)
𝜂𝑖𝑗 = (𝑇𝑖𝑗 ∗ 𝑉𝑖𝑗)−1 (33)
Donde 𝑇𝑖𝑗 se refiere a la diferencia entre el tiempo en el que se visita al cliente 𝑗 (𝑏𝑗) y el tiempo
en que se termina de visitar al cliente 𝑖. 𝑉𝑖𝑗 se define como la urgencia que existe en visitar al cliente
𝑗 partiendo del cliente 𝑖. Como se comentó en el apartado 0, 𝑙𝑗 es el último momento en que puede
ser visitado el cliente 𝑗.
/* MACS-VRPTW: Multiple Ant Colony System for Vehicle Routing Problems with Time Windows */
Procedure MACS-VRPTW()
1. /* Inicialización */
/* 𝜓𝑔𝑏 es la menor solución encontrada: menor número de vehículos y menor distancia recorrida
#active_vehicles(𝜓) calcula el número de vehículos empleados en una solución*/
𝜓𝑔𝑏 ←Función inicial factible con un número ilimitado de vehículos
disponibles
2. /* Bucle principal */
Repeat
v ←#active_vehicles(𝜓𝑔𝑏 )
Activate ACS-VEI(v - 1)
Activate ACS-TIME(v)
While ACS-VEI y ACS-TIME están activos
Wait una solución mejorada 𝜓 por ACS-VEI o ACS-TIME
𝜓𝑔𝑏 ← 𝜓
if #active_vehicles(𝜓𝑔𝑏 ) < v then
kill ACS-TIME y ACS-VEI
End While
until llegar a un criterio de finalización
Figura 4.1. El proceso del MACS-VRPTW (modificación Gambardella [12])
A continuación se presenta el pseudocódigo de ACS- TIME.
Figura 4.1. El proceso del MACS-VRPTW (modificación Gambardella [12])
En lo que respecta a la otra colonia de hormigas, ACS-VEI, busca reducir el número de vehículos empleados
maximizando el número de ciudades visitadas por una determinada flota. Para ello, ACS-VEI comienza con un
número menos de vehículos disponibles, 𝑣 − 1, donde 𝑣 representa el menor número de vehículos empleados
en una solución factible hasta la fecha. El primer paso de este algoritmo consiste en generar una solución a partir
de 𝑣 − 1 vehículos mediante el Nearest Neighbor Heuristic (este algoritmo se ha presentado en el apartado
4.1.2.3). Lo más probable es que la solución obtenida no sea factible, es decir que no todos los clientes hayan
sido visitados. Por ello, a diferencia del ACS-TIME, la función objetivo no intenta minimizar la distancia
recorrida, sino maximizar el número de clientes visitados. La solución no factible obtenida se conoce como
𝜓𝐴𝐶𝑆−𝑉𝐸𝐼, esta solución se irá actualizando cada vez que una nueva solución con mayor número de clientes haya
sido encontrada. Para favorecer la búsqueda por los clientes que normalmente no suelen ser visitados, se
introduce la variable 𝐼𝑁𝑗. Esta variable consiste en un vector que cuenta cuántas veces el cliente 𝑗 no ha sido
visitado e influirá en la probabilidad de las hormigas al escoger un nuevo cliente al que moverse:
𝜂𝑖𝑗 = (𝑇𝑖𝑗 ∗ 𝑉𝑖𝑗 − 𝐼𝑁𝑗)−1 (34)
Ya que la variable 𝜂𝑖𝑗 es uno de los datos de entrada de la función de probabilidad, ecuación (26), cada vez
que un cliente no sea visitado, la probabilidad de que este sea escogido será mayor. Favoreciendo así la
búsqueda por el espacio no recorrido del problema.
Por último, comentar que en el ACS-VEI, también cambia la forma en la que se actualiza la feromona de
manera global. Para ello, se hacen dos actualizaciones, una con la mejor solución factible obtenida hasta el
momento, 𝜓𝑔𝑏, y otra con la solución no factible mejor obtenida hasta el momento, 𝜓𝐴𝐶𝑆−𝑉𝐸𝐼.
A continuación se presenta el pseudocódigo de ACS- VEI:
/* ACS-TIME: Minimizar la distancia total recorrida. */
Procedure ACS-TIME(v)
/* El parámetro 𝑣 es el número más pequeño de vehículos usados hasta el momento */
1. /* Inicialización */
initialize la feromona usando v
2. /* Bucle */
Repeat
for each hormiga k
/* Contruye la solución 𝜓𝑘 */
new_active_ant(k, local_search=TRUE, 0)
end for each
/* Actualizar la mejor solución si ha sido mejorada */
if ∃ 𝑘 ∶ 𝜓𝑘 es factible and 𝐽𝜓𝑘 < 𝐽𝜓
𝑔𝑏 then
send 𝜓𝑘 to MACS-VRPTW
/* Actualizar la feromona total de acuerdo con la ecuación (30)*/
𝜏𝑖𝑗 = (1 − 𝜌)𝜏𝑖𝑗 + 𝜌/𝐽𝜓𝑔𝑏
until llegar a un criterio de finalización
Figura 4.2 Proceso del ACS-TIME (modificación Gambardella [12])
27
4.3 Adaptación de la ACO al problema
Para resolver el ecVRP se ha escogido el MACS-VRPTW, por la cercanía del VRPTW con el ecVRP. En el
MACS-VRPTW se usa como función auxiliar para generar soluciones iniciales el Nearest Neighbor Heuristic,
mientras que para el ecVRP, se ha escogido el Sequential Insertion Heuristic.
En este apartado se explica cómo se ha adaptado el algoritmo de colonia de hormigas al ecVRP. Del mismo
modo se presentan las principales modificaciones que se le han hecho a los problemas originales del ACO. Por
último se explica el algoritmo auxiliar Insertion Heuristic y las modificaciones que este ha sufrido para la mejora
de su eficiencia.
4.3.1 MACS-ecVRP
El ecVRP es una variante del VRPTW en el que cada cliente tiene varios destinos posibles en los que recibir el
pedido, para ello una flota de vehículos se encargará de entregar la mercancía a todos los clientes. El objetivo es
llegar a todos los clientes usando el mínimo número de vehículos y minimizando la distancia total recorrida.
Como se puede apreciar el MASC-VRPTW, puede ser adaptado perfectamente al ecVRP, puesto que los
objetivos siguen siendo los mismos, y la única diferencia se encuentra en que no todas las ciudades serán
visitadas, pero sí todos los clientes.
En el apartado 4.2.1 se ha hablado de la gran robustez que presentan los algoritmos basados en colonias de
hormigas, ya que se pueden adaptar con pequeños cambios a distintos problemas. Para el ecVRP no iba a ser
una excepción, la principal modificación que se ha de realizar es en la construcción individual de soluciones por
parte de cada hormiga. En el VRPTW cuando una hormiga va construyendo soluciones tiene una lista tabú que
va guardando las ciudades ya visitadas para así no volverlas a visitar, mientras que en el ecVRP la lista tabú no
/* ACS-VEI: Minimizar el número de vehículos empleados. */
Procedure ACS-VEI(s)
/* El parámetro s es el número más pequeño de vehículos usados hasta el momento menos 1 */
#visited_costumers(𝜓) calcula el número de vehículos empleados en una solución 𝜓 */
1. /* Inicialización */
initialize la feromona usando v
𝜓𝐴𝐶𝑆−𝑉𝐸𝐼 ←Función inicial factible con un número s de vehículos
disponibles/* 𝜓𝐴𝐶𝑆_𝑉𝐸𝐼 no es necesariamente factible y es obtenida por el Nearest Neighbor Heuristic */
2. /* Bucle */
Repeat
for each hormiga k
/* Construye la solución 𝜓𝑘 */
new_active_ant(k, local_search=FALSE, 0)
∀cliente j ∉ 𝜓𝑘 ∶ 𝐼𝑁𝑗 ← 𝐼𝑁𝑗 + 1
end for each
/* Actualizar la mejor solución si ha sido mejorada */
if ∃ 𝑘 ∶ #visited_customers(𝜓𝑘) > #visited_customers(𝜓𝐴𝐶𝑆−𝑉𝐸𝐼) then
𝜓𝐴𝐶𝑆−𝑉𝐸𝐼 ← 𝜓𝑘
∀j ∶ 𝐼𝑁𝑗 ← 0
If 𝜓𝐴𝐶𝑆−𝑉𝐸𝐼 es factible then
send 𝜓𝐴𝐶𝑆−𝑉𝐸𝐼 to MACS-VRPTW
/* Actualizar dos veces la feromona total de acuerdo con la ecuación (30)*/
𝜏𝑖𝑗 = (1 − 𝜌)𝜏𝑖𝑗 + 𝜌/𝐽𝜓𝑔𝑏
𝜏𝑖𝑗 = (1 − 𝜌)𝜏𝑖𝑗 + 𝜌/𝐽𝜓𝐴𝐶𝑆−𝑉𝐸𝐼
until llegar a un criterio de finalización
Figura 4.3 Proceso del ACS-VEI (modificación Gambardella [12])
guarda las ciudades visitadas, sino todas las ciudades asociadas a los clientes ya visitados. De esta manera las
hormigas no visitan a un mismo cliente más de una vez en sus distintas ciudades asociadas.
4.3.2 Función de visibilidad
En un artículo publicado por Ellabib, Basir y Camai [25] se plantean tres tipos de funciones de visibilidad para
el ACS al mismo tiempo que se comparan dos métodos para las generar soluciones iniciales: Sequential Insertion
Heuristic y Nearest Neighbor Heuristic, basándose un estudio de Solomon que analiza las principales heurísticas
para el VRPTW [26].Para ello se analiza cada heurística con los tres tipos de visibilidad, es decir, en total se
realizan seis experimentos.
Como se ha comentado en el apartado 4.2.3 la visibilidad 𝜂𝑖𝑗 es una medida del atractivo de un nodo 𝑗 visto
desde el nodo 𝑖 y cumple una función fundamental en el cálculo de la probabilidad de elección, ecuación (26).
En el estudio anterior [25] se introduce una novedosa definición de visibilidad para el VRPTW. Partiendo de las
ecuaciones de visibilidad ((31), (32), (33)) definidas por Gambardella [24], y tras varios experimentos, los
resultados obtenidos por el ACS para el VRPTW dan peores resultados para problemas en los que los clientes
se encuentran dispersados por el espacio euclídeo de forma aleatoria. Para solucionarlo se introduce como datos
de entrada de la visibilidad 𝜂𝑖𝑗 los ángulos polares que definen al nodo 𝑖 y al nodo 𝑗, 𝜃𝑖 y 𝜃𝑗, respectivamente.
𝑃𝑖𝑗 = |𝜃𝑗 − 𝜃𝑖| (35)
𝜂𝑖𝑗 = (𝑤1 ∗ (𝑇𝑖𝑗 ∗ 𝑉𝑖𝑗) + 𝑤2 ∗ 𝑃𝑖𝑗)−1 (36)
Donde 𝑇𝑖𝑗 y 𝑉𝑖𝑗 vienen dados por las ecuaciones (31) y (32) respectivamente, y 𝑤1 y 𝑤2representan los pesos
de los términos de la ecuación (36).
Los resultados mostraron que las mejores soluciones fueron para los algoritmos que tenían implementada
la visibilidad según los ángulos polares. Por otro lado, Insertion Heuristic también mostró mejores
resultados en comparación con Nearest Neighbor Heuristic.
4.3.3 Insertion Heuristic
En el MACS-ecVRP en varias partes del algoritmo se ha de usar Inserion Heuristic. Por un lado, la heurística
se usa para generar una función inicial tanto en el MACS-ecVRP, como dentro del ACS-VEI. La solución
generada inicialmente en el MACS-ecVRP sirve de entrada para el ACS-TIME y el número de vehículos de
dicha solución sirve de entrada para el ACS-VEI. Además en el ACS-VEI se ha de generar una nueva solución
con dicho número de vehículos.
Por otro lado, la heurística se emplea para mejorar las soluciones generadas por las hormigas. Para ello, intenta
insertar las ciudades que hubieran quedado sin visitar entre las ciudades de las diferentes rutas. En la práctica se
ha visto fundamental este uso de la heurística, pues de lo contario la mayoría de las soluciones generadas por las
hormigas serían inviables, lo que supondría una pérdida de tiempo y recursos computacionales. Se ha escogido
Insertion Heuritic por dar mejores resultados en comparación con otras heurísticas del mismo tipo [25] [26].
Concretamente se ha escogido una heurística secuencial, es decir, que los procesos se hacen uno de tras de otro
y no simultáneamente, diseñada por Solomon [26] llamada I1.
Para el desarrollo del algoritmo primero se generan 𝐾 rutas, siendo 𝐾 un número menor que el número de
vehículos disponibles. Las rutas se van rellenando inicialmente según la estrategia del cliente más lejano, esta
consiste en seleccionar de entre todos los clientes que quedan por visitar, aquel cuya distancia al depósito sea
mayor. Una vez que se han iniciado las rutas se procede a completarlas introduciendo donde sea posible a todos
los clientes restantes según dos criterios 𝑐1(𝑖, 𝑢, 𝑗) y 𝑐2(𝑖, 𝑢, 𝑗), donde 𝑐(𝑖, 𝑢, 𝑗) es el coste asociado a la inserción
del cliente 𝑢 entre los clientes 𝑖 y 𝑗. Se define (𝑖0, 𝑖1, 𝑖2, … , 𝑖𝑚) la ruta actual donde 𝑖0 = 𝑖𝑚.
Primero para cada cliente 𝑢 sin visitar se calcula su mejor inserción posible, es decir, se prueba la inserción entre
todos los clientes de la ruta actual y para las inserciones posibles se calcula el coste asociado a cada una de ellas,
tras esto se escoge la mejor de las inserciones:
𝑐1(𝑖(𝑢), 𝑢, 𝑗(𝑢)) = min[𝑐1(𝑖𝑝−1, 𝑢, 𝑖𝑝)] , 𝑝 = 1, … , 𝑚 (37)
29
Lo que se obtiene tras este proceso es una lista en la que se guarda para cada cliente el mejor cambio posible. A
continuación, de todos los clientes que quedan por visitar se calcula cual sería el mejor entre ellos para ser
introducido en la solución:
𝑐2(𝑖(𝑢∗), 𝑢∗, 𝑗(𝑢∗)) = óptimo[𝑐2(𝑖(𝑢), 𝑢, 𝑗(𝑢))] , 𝑝 = 1, … , 𝑚 (38)
El cliente 𝑢∗ es, entonces, introducido en la ruta entre el cliente 𝑖(𝑢∗) y el 𝑗(𝑢∗). Este procedimiento se repite
hasta que no sea posible introducir más clientes, momento en el cual, se inicia una nueva ruta. En este punto se
ha de aclarar que en el algoritmo la función Insertion Heuristic solo tiene libertad para generar nuevas rutas
ilimitadamente la primera vez que genera una solución, es decir, en el MACS-ecVRP, el resto de veces en las
que se usa la función el número de vehículos es limitado. Las ecuaciones que definen a los costes 1 y 2 son las
siguientes:
𝑐11(𝑖(𝑢), 𝑢, 𝑗(𝑢)) = 𝑑𝑖𝑢 + 𝑑𝑢𝑗 − 𝜇𝑑𝑖𝑗 , 𝜇 ≥ 0 (39)
𝑐12(𝑖(𝑢), 𝑢, 𝑗(𝑢)) = 𝑏𝑗𝑢 − 𝑏𝑗 (40)
Donde 𝑏𝑗𝑢 sería el nuevo tiempo de llegada a la ciudad 𝑗 si el cambio se diera y 𝑏𝑗 el tiempo de llegada antes del
cambio. La constante 𝑑𝑖𝑗 es la distancia más corta entre el cliente 𝑖 y el cliente 𝑗.
𝑐1(𝑖(𝑢), 𝑢, 𝑗(𝑢)) = 𝛼1𝑐11(𝑖(𝑢), 𝑢, 𝑗(𝑢)) + 𝛼2𝑐12(𝑖(𝑢), 𝑢, 𝑗(𝑢)) (41)
𝛼1 + 𝛼2 = 1 (42)
𝑐2(𝑖(𝑢), 𝑢, 𝑗(𝑢)) = 𝜆𝑑0𝑢 − 𝑐1(𝑖(𝑢), 𝑢, 𝑗(𝑢)) (43)
Gracias al 𝑐2 se puede comprobar que esta heurística intenta maximizar el ahorro obtenido de servir a un cliente
𝑢 entre los cliente 𝑖 y 𝑗 en vez de servirlo directamente (𝑑0𝑢). Con el 𝑐1 se puede ver que el mejor cambio
factible para un cliente 𝑢 es aquel que minimiza tanto la distancia como el tiempo que se ahorran con el cambio.
4.3.3.1 La matriz de compatibilidad
El gran problema del Insertion Heuristic es que es un algoritmo que en cada iteración comprueba todas las
posiciones que pueda tener un cliente no visitado en la ruta de los ya visitados, lo que genera un gran gasto
computacional. Además, para el caso del ecVRP, si el Insertion Heuristic se introduce para mejorar la solución
generada por cada hormiga, el gasto computacional aumenta exponencialmente. Surge, por tanto, la necesidad
de mejorar la eficiencia de la heurística. Para ello, se introduce la matriz de compatibilidad, que hará evitar al
algoritmo comprobar la posición incompatible de un cliente entre dos posibles clientes. Se entiende por posición
incompatible aquella en la que siempre será imposible introducir al cliente 𝑢 entre los cliente 𝑖 y 𝑗, sea cual sea
la circunstancia.
La matriz de compatibilidad, conocida en la literatura inglesa como Time Window Compatibility Matrix
(TWCM) es introducida por Joubert y Claasen [27], se define como una matriz asimétrica 𝑁 × 𝑁, donde 𝑁
representa el número de clientes. Mide la compatibilidad de ir desde la posición del cliente 𝑖 hasta la posición
del cliente 𝑗. Para ello se introducen tres nuevas variables, a parte de las propias del VRPTW:
𝑎𝑗𝑒𝑖: La hora de llegada el cliente 𝑗, después de haber visitado al cliente 𝑖 en el tiempo 𝑒𝑖.
𝑎𝑗𝑙𝑖: La hora de llegada el cliente 𝑗, después de haber visitado al cliente 𝑖 en el tiempo 𝑙𝑖.
𝑇𝑊𝐶𝑖𝑗: Medida de la compatibilidad de ir al nodo 𝑗 desde el nodo 𝑖.
En el problema original la TWCM viene dada por la siguiente ecuación:
𝑇𝑊𝐶𝑖𝑗 = { min {𝑎𝑗
𝑙𝑖 , 𝑙𝑗} − max {𝑎𝑗𝑒𝑖 , 𝑒𝑗} 𝑠𝑖 𝑙𝑗 − 𝑎𝑗
𝑒𝑖 > 0
−∞ 𝑒𝑛 𝑜𝑡𝑟𝑜 𝑐𝑎𝑠𝑜 (44)
Para el ecVRP se ha optado por simplificar el problema pues la principal ventaja de la TWCM puede ser
aprovechada sin necesidad de emplear valores tan grandes. La 𝑇𝑊𝐶𝑖𝑗 queda del siguiente modo:
𝑇𝑊𝐶𝑖𝑗 = {
1 𝑠𝑖 𝑙𝑗 − 𝑎𝑗𝑒𝑖 > 0
0 𝑒𝑛 𝑜𝑡𝑟𝑜 𝑐𝑎𝑠𝑜 (45)
De tal manera que si 𝑇𝑊𝐶𝑖𝑗 es igual a 1, la heurística comprueba si la posición es factible y seguidamente
calcula el 𝑐1(𝑖, 𝑢, 𝑗). Si, de lo contrario, 𝑇𝑊𝐶𝑖𝑗 es igual a 0, la heurística ni se molesta en comprobar la
factibilidad y el coste en dicha posición. Para entender un caso en el que 𝑇𝑊𝐶𝑖𝑗 es igual a 1 (compatibilidad) y
otro en el que es igual a 0 (incompatibilidad) se muestra la siguiente figura:
4.3.3.2 Método de eficiencia en Insertion Heuristic
Otro gran problema que presentan las heurísticas de inserción es la dificultad para comprobar si es factible o no
introducir un cliente 𝑢 en una posición 𝑝. Para resolver este problema Campbell y Savelsbergh [28] presentan
un método de comprobación para distintas variantes del VRP que mejoran considerablemente la eficacia del
algoritmo.
Para el VRPTW, es necesario definir dos nuevas variables:
𝑡𝑒𝑖 se define como la hora más temprana a la que el cliente i puede ser atendido.
𝑡𝑙𝑖 se define como la hora más tardía a la que el cliente i puede ser atendido.
Estas dos variables se han de mantener para cada cliente 𝑖 introducido ya en una ruta. Por conveniencia 𝑡𝑒0 = 0
y 𝑡𝑙𝑛+1 = 𝑇, donde 𝑇 es el final del horizonte temporal del problema y los clientes 0 y 𝑛 + 1 representan al
depósito. Inicialmente 𝑡𝑒𝑖 = 𝑒𝑖 y 𝑡𝑙𝑖 = 𝑙𝑖, pero a lo largo del tiempo de ejecución del algoritmo 𝑡𝑒𝑖 y 𝑡𝑙𝑖 irán
cambiando según la ruta en la que se encuentre el cliente 𝑖.
Para comprobar la factibilidad de la inserción del cliente 𝑗 entre el cliente 𝑖 − 1 e 𝑖 se calcula 𝑡𝑒𝑖 y 𝑡𝑙𝑖 según:
𝑡𝑒𝑗 = max (𝑒𝑖, 𝑡𝑒𝑖−1 + 𝑑𝑖−1,𝑗) (46)
𝑡𝑙𝑗 = max (𝑡𝑙𝑖, 𝑙𝑖 + 𝑑𝑖,𝑗) (47)
Calculadas estas variables simplemente se han de comparar 𝑡𝑒𝑖 y 𝑡𝑙𝑖. Si 𝑡𝑒𝑗 < 𝑡𝑙𝑗 la inserción es factible, de lo
contrario, es inviable.
Por último, una vez se haya hecho la inserción en la posición, las variables 𝑡𝑒𝑘 y 𝑡𝑙𝑘 de cada cliente 𝑘
perteneciente a la ruta donde se ha hecho dicha inserción han de ser actualizadas del siguiente modo:
Desde 𝑘 = 𝑖 − 1 hasta 0, el nuevo cliente modifica la hora más tardía a la que el vehículo puede llegar
Figura 4.4: (a) Caso compatible en el que 𝑇𝑊𝐶𝑖𝑗 = 1, (b) Caso incompatible en el que 𝑇𝑊𝐶𝑖𝑗 = 0, Joubert y Claasen [26]
31
de todos los clientes 𝑘.
𝑡𝑙𝑘 = max (𝑡𝑙𝑘 , 𝑙𝑘+1 + 𝑑𝑖,𝑘+1) (48)
Desde 𝑘 = 𝑖 hasta 𝑛 + 1, el nuevo cliente modifica la hora más temprana a la que el vehículo puede
llegar de todos los clientes 𝑘.
𝑡𝑒𝑘 = max (𝑒𝑘, 𝑡𝑒𝑘−1 + 𝑑𝑘−1,𝑘) (49)
4.3.4 Criterios de finalización
Como se puede ver en los pseudocódigos del MACS-VRPTW, ACS-TIME, y ACS-VEI cada proceso termina
según un criterio de finalización. Para el ACS-TIME el criterio de finalización escogido es el número de
iteraciones, es decir, el número de veces que una colonia de hormigas de tamaño 𝑚 encuentra un máximo de 𝑚
soluciones factibles. Para el ACS-VEI, son dos los criterios escogidos. El primero es el número de iteraciones,
al igual que en el ACS-TIME y el segundo consiste en terminar con el proceso en caso de que no se mejore la
solución en un número 𝑥 de iteraciones, donde 𝑥 es el 20% del número de iteraciones. Para ambos procesos, la
finalización puede también venir como orden por parte del MACS-ecVRP
Por último para el MACS-ecVRP el criterio escogido es de tiempo fijo. El algoritmo MACS-ecVRP controla
dos procesos (colonias) al mismo tiempo (ACS-VEI y ACS-TIME), cada vez que una colonia encuentra una
solución factible con un menor número de vehículos o cada vez que ambos procesos terminan porque se ha
llegado a los respectivos criterios de finalización, este termina con ambos procesos, y los reinicia. Este
procedimiento se repite hasta que se alcance un tiempo específico, momento a partir del cual el algoritmo no
volverá a reiniciar ninguna de las dos colonias. El reinicio de las colonias tiene como ventaja el reinicio de la
feromona, lo que implica aumentar la exploración por las regiones del espacio aún sin explorar y huir, así, de
posibles estancamientos en óptimos locales.
33
5 RESULTADOS
n este capítulo se evaluará el algoritmo diseñado empleando una batería de problemas originaria para el
VRPTW. Para ello se calibrará el algoritmo según una serie de parámetros escogidos y con la
configuración resultante de la calibración se resolverá la batería de problemas. Finalmente, los resultados
serán comparados con los de otros trabajos.
5.1 Definición de la experimentación
Para evaluar el algoritmo diseñado en este Proyecto aplicado al ecVRP se ha empleado la batería de problemas
de Solomon. Esta batería fue desarrollada por M. M Solomon para evaluar un conjunto de heurísticas que había
presentado para resolver el VRPTW [26]. Una de estas heurísticas es la I1, presentada en el apartado 4.1.2.2 y
descrita en el apartado 4.3.3, que se ha utilizado como algoritmo auxiliar para este proyecto, también se empleaba
la heurística del Nearest Neighbour Algorithm, explicada en el apartado 4.1.2.3.
La batería está formada por seis conjuntos de problemas (R1, R2, C1, C2, RC1, RC2) que han sido diseñados
teniendo en cuenta varios factores: las coordenadas geográficas, el número de clientes por vehículo y las
características de las ventanas temporales. Aunque esta batería fuera pensada originalmente para el VRPTW, se
ha escogido para el ecVRP por su facilidad de adaptación a este último y por la calidad de la información sobre
la bondad del problema que la batería aporta al ser resuelta. Dicha calidad de la información no solo se debe a
cómo es la batería, sino también al hecho de que son muchos los algoritmos que la han utilizado para ser
evaluados, y gracias a esto se pueden comparar entre ellos, conociendo así con más exactitud la bondad del
algoritmo.
Las coordenadas geográficas de los problemas R1 y R2 han sido obtenidas aleatoriamente según una función de
distribución uniforme. Las coordenadas de C1 y C2 han sido diseñadas de manera que los clientes queden
agrupados. Por último, las coordenadas RC1 y RC2 son una mezcla entre los cuatro conjuntos de problemas
anteriores. En los conjuntos de problemas R1, C1, y RC1 la capacidad de los vehículos es más reducida, por lo
que con un mismo vehículo será difícil servir a muchos clientes al mismo tiempo. Al contrario para los conjuntos
de problemas R2, C2 y RC2, la capacidad de los vehículos es mayor, por lo que se hace más fácil servir a varios
clientes con un mismo vehículo.
Para los problemas R1, R2, RC1 y RC2 los centros de las ventanas temporales han sido obtenidos aleatoriamente
según una función de distribución uniforme mientras que el ancho temporal, para la mitad de los clientes, ha
sido obtenido según una función de distribución normal y para la otra mitad, según una función de distribución
uniforme. Por otro lado para los conjuntos de problemas C1 y C2, primero se generó una ruta y luego según los
tiempos de llegada a cada cliente se crearon los centros de las ventanas temporales. Finalmente se le añadieron
los anchos temporales. Gracias a esto para los problemas tipo C es fácil generar una ruta que se acerque bastante
al óptimo.
Para adaptar esta batería de problemas al ecVRP, donde cada cliente tiene un número 𝐺 de lugares en los que
ser atendido, cada grupo de 𝐺 clientes consecutivos de la batería de problemas del VRPTW corresponden a un
cliente del ecVRP. De manera que el número de nodos N en el ecVRP viene dado por: 𝑁 = 𝐺 ∗ 𝑍, donde 𝑍
indica el número de clientes.
En la batería de problemas se pueden observar siete columnas. La primera corresponde al número identificativo
del cliente, donde el primer cliente corresponde al depósito. La segunda y tercera columnas se refieren a las
coordenadas de cada nodo, 𝑥 e 𝑦, respectivamente. La cuarta a la demanda de cada cliente. La quinta y la sexta
definen la ventana temporal, siendo la quinta el tiempo de inicio de la ventana y la sexta el de finalización. Por
último, la séptima columna se refiere al tiempo de servicio de cada cliente, es decir cuánto tiempo ha de estar el
vehículo parado en un nodo cuando llegar a él. A continuación se muestra un ejemplo de cómo se define uno de
los problemas mencionados:
E
En cada problema también se incluye el número máximos de vehículos y la capacidad de estos.
En este proyecto, se ha optado por resolver el ecVRP sin tener en cuenta el tiempo de servicio ni la capacidad.
Es decir para todos los clientes, el tiempo de servicio, 𝑠𝑧, y la demanda, 𝑞𝑧, es igual a 0. Queda entonces como
principal restricción las ventanas temporales. La Figura 5.2 muestra una solución gráfica para un problema de
25 clientes:
Figura 5.2: Solución gráfica representativa de un problema ecVRP.
5.2 Calibrado del método
Puesto que el algoritmo MACS-VRPTW nunca antes ha sido implementado para el ecVRP, es necesario
Figura 5.1: Ejemplo del tipo de problemas de Solomon (problema r101, conjunto de
problemas R1)
35
calibrarlo, es decir, probar empíricamente la respuesta del algoritmo frente a distintos valores de ciertos
parámetros para conocer con que configuración actúa mejor.
Son cinco los parámetros seleccionados para el calibrado: el número de hormigas 𝑚 para ambas colonias, el
número de iteraciones para ACS-VEI y ACS-TIME (el número de iteraciones es el mismo para ambos y definen
el criterio de finalización), los coeficientes 𝛼 y 𝛽, que representan en la ecuación de la probabilidad (26) los
exponentes de la feromona y de la visibilidad, respectivamente, y por último el coeficiente de evaporación 𝜌 del
que depende la feromona (ecuación (30)) y que es el mismo para la actualización local y global de la feromona.
Los parámetros 𝜌, 𝛼 y 𝛽 han sido escogidos por el poco consenso que hay sobre ellos en la literatura. Por otro
lado, el número de iteraciones se ha escogido por la escasa información que se puede encontrar en la literatura
y porque la información que se encuentra sobre dicho número varía en grados de magnitud. Por último, el
número de hormigas 𝑚 se ha escogido por ser el más mencionado y puede dar una idea de cuán diferente es el
algoritmo en comparación con otros ACO según el número resultante de la calibración.
En primer lugar se han calibrado los parámetros referentes al número de hormigas 𝑚 y al número de iteraciones.
Para ello, se han tomado los valores 10, 15 y 20 para el número de hormigas y 100, 175 y 250 para el número
de iteraciones. Al ser dos parámetros y tres posibilidades por cada parámetro el número de combinaciones
posibles es nueve, por lo que se han calculado nueve tipos de problemas diez veces cada uno. Se ha de aclarar
que el ACS-VEI y ACS-TIME son dos algoritmo subordinados al MACS-ecVRP, por lo que si se aumenta el
número de iteraciones no necesariamente se mejora el resultado, puede incluso empeorarse.
Las distintas combinaciones son:
𝑚 = 10,𝑛º𝑖𝑡 = 100
𝑚 = 10,𝑛º𝑖𝑡 = 175
𝑚 = 10,𝑛º𝑖𝑡 = 200
𝑚 = 15,𝑛º𝑖𝑡 = 100
𝑚 = 15,𝑛º𝑖𝑡 = 175
𝑚 = 15,𝑛º𝑖𝑡 = 200
𝑚 = 20,𝑛º𝑖𝑡 = 100
𝑚 = 20,𝑛º𝑖𝑡 = 175
𝑚 = 20,𝑛º𝑖𝑡 = 200
Tabla 2: Combinaciones de los parámetros escogidos (m y nºit) para la calibración del MACS-ecVRP
Para dichas combinaciones los resultados han sido los siguientes:
Figura 5.3: Resultados en distancias de la calibración del MACS-ecVRP para los parámetros m y nºit.
m:10Nºit: 100
m:10Nºit: 175
m:10Nºit: 250
m:15Nºit: 100
m:15Nºit: 175
m:15Nºit: 250
m:20Nºit: 100
m:20Nºit: 175
m:20Nºit: 250
Promedios 399.61 394.98 397.26 416.09 407.19 401.01 411.55 401.55 400.39
380.00
385.00
390.00
395.00
400.00
405.00
410.00
415.00
420.00
DIS
TA
NC
IA R
EC
OR
RID
A
COMBINACIONES
Calibración m - nºit
El ecVRP es un tipo de problema con objetivos jerarquizados, es decir, tiene varios objetivos pero unos son más
importantes que otros: mejorar el número de vehículos empleados es mejor que mejorar la distancia total
recorrida. Entonces, viendo las gráficas Figura 5.3 y Figura 5.4 se puede concluir que de las combinaciones con
menos vehículos, es decir, tres vehículos, la que menor distancia tiene es aquella para la que el número de
hormigas es igual a 10 y el número de iteraciones 100. Esto se explica gracias a los criterios de finalización
explicados en el apartado 4.3.4. El criterio principal es el que rige al algoritmo principal MACS-VEI, es decir el
tiempo fijo. Los otros criterios son el número de iteraciones. Si aumenta el número de iteraciones o el número
de hormigas, el tiempo de ejecución para cada proceso aumenta, lo que implica un menor número de veces de
reinicio de los procesos. De lo contrario, disminuyendo el número de iteraciones y el número de hormigas se
aumenta el número de reinicios para un mismo tiempo fijo. Un mayor aumento del número de reinicios se
traduce en un aumento de la exploración por las regiones del espacio de búsqueda aún sin explorar.
Tras la primera calibración, se procede a la segunda. En ella las combinaciones de parámetros se dan entre la
pareja de parámetros 𝛼 y 𝛽, y 𝜌. El conjunto de combinaciones resultantes es el siguiente:
(𝛼 = 1, 𝛽 = 1),𝜌 = 0.1
(𝛼 = 1, 𝛽 = 1),𝜌 = 0.25
(𝛼 = 1, 𝛽 = 1),𝜌 = 0.175
(𝛼 = 0.5, 𝛽 = 1.2),𝜌 = 0.1
(𝛼 = 0.5, 𝛽 = 1.2),𝜌 = 0.25
(𝛼 = 0.5, 𝛽 = 1.2),𝜌 = 0.175
(𝛼 = 1, 𝛽 = 4),𝜌 = 0.1
(𝛼 = 1, 𝛽 = 4),𝜌 = 0.25
(𝛼 = 1, 𝛽 = 4),𝜌 = 0.175
Tabla 3: Combinaciones de los parámetros escogidos (𝛼 y 𝛽, y 𝜌) para la calibración del MACS-ecVRP
m:10Nºit: 100
m:10Nºit: 175
m:10Nºit: 250
m:15Nºit: 100
m:15Nºit: 175
m:15Nºit: 250
m:20Nºit: 100
m:20Nºit: 175
m:20Nºit: 250
Nº Veh 3.00 3.10 3.10 3.10 3.00 3.10 3.20 3.00 3.00
2.90
3.00
3.10
3.20
3.30
Nº
DE
VE
HÍC
UL
OS
COMBINACIONES
Número de vehículos para m - nºit
Figura 5.4: Resultados en nº de vehículos de la calibración del MACS-ecVRP para los parámetros m y nºit.
37
Para dichas combinaciones se ha usado la configuración de número de iteraciones y de número de hormigas
obtenidas en la primera calibración. Los resultados para la segunda son los siguientes:
Figura 5.5: Resultados en distancias de la calibración del MACS-ecVRP para los parámetros 𝛼 y 𝛽, y 𝜌.
Figura 5.6: Resultados en nº de vehículos de la calibración del MACS-ecVRP para los parámetros 𝛼 y 𝛽, y 𝜌.
Como se puede comprobar la mejor combinación de todas es 𝛼 = 1, 𝛽 = 1 y 𝜌 = 0.1, para los que tanto el
número de vehículos, que es el objetivo principal, como la distancia promedio recorrida son mínimos. Por lo
tanto para la resolución de la batería de problemas R1 se tomará como parámetros los siguientes valores:
𝛼 = 1 𝛽 = 1 𝜌 = 0.1 𝑚 = 10 𝑛º𝑖𝑡 = 100
Tabla 4: Valores resultantes de la calibración del MACS-ecVRP para los parámetros 𝛼, 𝛽, 𝜌, m y nºit.
5.3 Resultados del MACS-ecVRP
Para resolver la batería de problemas se ha de aclarar las condiciones de los problemas. En el problema original
cada arco 𝑎𝑖𝑗 se definía por una longitud 𝑑𝑖𝑗 y por un tiempo de recorrido 𝑡𝑖𝑗. En esta batería de problemas, se
considera que el vehículo viaja a una velocidad de 60 𝑘𝑚/ℎ por lo que recorre un kilómetro por minuto, esto
se traduce en que 𝑑𝑖𝑗 = 𝑡𝑖𝑗. Por lo tanto, el coste de una solución viene dado por la distancia total recorrida o,
β:1 α:1 ρ: 0.1
β:1.2 α:0.5 ρ:
0.1
β:4 α:1 ρ: 0.1
β:1 α:1 ρ: 0.25
β:1.2 α:0.5 ρ:
0.25
β:4 α:1 ρ: 0.25
β:1 α:1 ρ: 0.175
β:1.2 α:0.5 ρ:
0.175
β:4 α:1 ρ: 0.175
Promedios 391.64079 405.36304 439.04856 417.8 409.95062 444.81405 406.18453 423.24153 445.31628
360
370
380
390
400
410
420
430
440
450
DIS
TA
NC
IA R
EC
OR
RID
A
COMBINACIONES
Calibración β, α - ρ
β:1 α:1 ρ: 0.1
β:1.2 α:0.5 ρ: 0.1
β:4 α:1 ρ: 0.1
β:1 α:1 ρ: 0.25
β:1.2 α:0.5 ρ: 0.25
β:4 α:1 ρ: 0.25
β:1 α:1 ρ: 0.175
β:1.2 α:0.5 ρ: 0.175
β:4 α:1 ρ: 0.175
Nº Veh 3 3.0909091 3.2727273 3.0909091 3 3.1818182 3 3 3
2.8
2.9
3
3.1
3.2
3.3
DIS
TA
NC
IA R
EC
OR
RID
A
COMBINACIONES
Número de vehículos
por lo que es lo mismo, el tiempo total de viaje. Gracias a esta suposición se evitan cálculos innecesarios a la
hora de evaluar las soluciones.
La batería a resolver entre las seis de Solomon corresponde a los doce problemas de la batería R1. Para ello, se
tendrán en cuenta 25 clientes del ecVRP, lo que significa trabajar con un total de 75 nodos más el depósito. Por
otro lado, también se resolverá para cincuenta clientes, es decir, 150 nodos más el depósito.
Se presentan a continuación los resultados:
25 clientes
Promedios Valores mínimos Desviación
Problemas Nº Vehículos Distancia Tiempos (s) Nº Vehículos Distancia Nº Vehículos Distancia
R101 3 397.5172464 129.61 3 375.306491 0 18,6108866
R102 2,1 321.4723097 135.34 2 310.113764 0.31622777 9,03405501
R103 2 292.1862948 136.57 2 269.942057 0 18,5014073
R104 2 282.393436 131.39 2 266.985671 0 8,78079573
R105 2,6 352.3616345 133.30 2 324.643763 0.51639778 19,6421374
R106 2 296.7800444 130.02 2 278.922405 0 13,7435314
R107 2 292.442668 140.94 2 273.322685 0 12,1433084
R108 2 283.1729435 138.58 2 252.017584 0 13,8621461
R109 2 301.2607913 138.92 2 289.42733 0 8,81797455
R110 2 268.9760313 133.80 2 255.429799 0 13,2739597
R111 2 291.2521652 134.12 2 254.514185 0 18,3073005
R112 2 278.4154121 136.66 2 263.9987 0 11,8562353
Tabla 5: Resultados de la batería de problemas R1 para 25 clientes
39
Figura 5.7: Distancia promedios para los problemas de 25 clientes
Figura 5.8: Distancias mínimas para los problemas de 25 clientes
50 clientes
Promedios Valores mínimos Desviación
Problemas Nº Vehículos Distancia Tiempos (s) Nº Vehículos Distancia Nº Vehículos Distancia
R_1_2_1 3,9 1185,032667 276.62 3 1116,747397 0,3 41,10041776
R_1_2_2 3 1051,755508 318.35 3 1002,368551 0 25,77268201
R_1_2_3 2 871,3640591 323.17 2 829,3315742 0 29,58702273
230
250
270
290
310
330
350
370
390
410
r101 r102 r103 r104 r105 r106 r107 r108 r109 r110 r111 r112
DIS
TA
NC
IA R
EC
OR
RID
A
PROBLEMAS R1
Soluciones promedio 25 clientes
220
240
260
280
300
320
340
360
380
400
r101 r102 r103 r104 r105 r106 r107 r108 r109 r110 r111 r112
DIS
TA
NC
IA R
EC
OR
RID
A
PROBLEMAS R1
Mínimas distancias 25 clientes
R_1_2_4 1,9 750,3637271 287.14 1 608,7562805 0,3 60,34393556
R_1_2_5 3 1120,739828 278.87 3 1056,442241 0 46,75991405
R_1_2_6 2,8 1022,449773 309.77 2 918,0685745 0,4 56,49155882
R_1_2_7 2 886,8941429 334.89 2 846,2123781 0 30,38676974
R_1_2_8 2 803,39008 300.68 2 744,9887582 0 36,27664493
R_1_2_9 2,6 1030,281516 295.91 2 891,3075017 0,489897949 82,41079564
R_1_2_10 2 912,0007859 295.87 2 819,2311368 0 47,76975845
Tabla 6: Resultados para 50 clientes
Figura 5.9: Distancia promedios para los problemas de 50 clientes
Figura 5.10: Distancias mínimas para los problemas de 50 clientes
R_1_2_1 R_1_2_2 R_1_2_3 R_1_2_4 R_1_2_5 R_1_2_6 R_1_2_7 R_1_2_8 R_1_2_9 R_1_2_10
Promedio 1185.033 1051.756 871.3641 750.3637 1120.74 1022.45 886.8941 803.3901 1030.282 912.0008
400
500
600
700
800
900
1000
1100
1200
1300
DIS
TA
NC
IA R
EC
OR
RID
A
PROBLEMAS R1
Soluciones promedio 50 clientes
R_1_2_1 R_1_2_2 R_1_2_3 R_1_2_4 R_1_2_5 R_1_2_6 R_1_2_7 R_1_2_8 R_1_2_9 R_1_2_10
Dis. Mín 1116.747 1002.369 829.3316 608.7563 1056.442 918.0686 846.2124 744.9888 891.3075 819.2311
400
500
600
700
800
900
1000
1100
1200
DIS
TA
NC
IA R
EC
OR
RID
A
PROBLEMAS R1
Mínimos alcanzados 50 clientes
41
5.4 Comparación de resultados con trabajos previos
Para entender mejor la magnitud de los resultados obtenidos en el apartado anterior (5.3) se comparan estos con
los de otros trabajos que emplean distintas metaheurísticas para resolver el mismo problema. Dichas
metahurísticas son: Búsqueda tabú (Tabu Search), presentada en el apartado 4.1.3.3, Recocido simulado
(Simulated Aleaning, SA), presentado en el apartado 4.1.3.2, Algoritmo genético (Evolutionary Procedure),
presentado en el apartado 4.1.3.1 y Búsqueda cuco, presentado en el apartado 4.1.3.5. Puesto que los resultados
disponibles de estos algoritmos no abarcan el número de vehículos, este no se tendrá en cuenta en la
comparación. No obstante, se ha de entender que el principal objetivo del MACS-ecVRP es, primero, la
disminución del número de vehículos empleados y después, la distancia. Por lo que para poder tener una mejor
exactitud en la magnitud de los resultados sería necesario disponer de los datos sobre el número de vehículos.
Figura 5.11: Comparación de distancia promedio para 25 clientes
r101 r102 r103 r104 r105 r106 r107 r108 r109 r110 r111 r112
Ant Colony 397.52 321.47 292.19 282.39 352.36 296.78 292.44 283.17 301.26 268.98 291.25 278.42
SA 430.42 370.88 331.61 274.89 381.09 344.08 319.36 272.38 341.33 300.2 305.31 248.15
Tabu Search 452.1 396.71 357.17 284.37 395.15 375 343.67 263.91 352.53 325.7 326.09 279.84
Evolutionary 365.24 301.42 280.13 254.11 318.74 286.24 272.19 250.67 285.86 266.81 255.35 242.88
CucKoo Search 354.57 314.72 295.71 254.99 328.61 296.97 282.58 253.89 287.38 274.89 283.39 267.88
230.00
280.00
330.00
380.00
430.00
DIS
TA
NC
IA R
EC
OR
RID
A
Comparación promedio 25 clientes
Figura 5.12: Comparación de distancia mínima para 25 clientes
Figura 5.13: Comparación de tiempos en segundos para 25 clientes
r101 r102 r103 r104 r105 r106 r107 r108 r109 r110 r111 r112
Ant Colony 375.31 310.11 269.94 266.99 324.64 278.92 273.32 252.02 289.43 255.43 254.51 264.00
SA 395.89 342.97 308.38 255.09 326.46 319.54 305.26 251.57 310.18 276.74 280.77 229.34
Tabu Search 401.59 336.32 296.95 253.32 317.5 306.73 290.91 233.86 303.11 268.57 285.02 227.98
Evolutionary 349.26 294.4 267.77 232.36 310.91 271.09 260.37 231.49 272.37 243.74 241.77 230.82
Cuckoo Search 347.27 298.62 281.06 232.51 311.96 265.34 272.68 228.47 270.11 240.53 243.79 228.90
220.00
240.00
260.00
280.00
300.00
320.00
340.00
360.00
380.00
400.00
DIS
TA
NC
IA R
EC
OR
RID
AComparación mínimo 25 clientes
r101 r102 r103 r104 r105 r106 r107 r108 r109 r110 r111 r112
Ant Colony 129.61 135.34 136.57 131.39 133.30 130.02 140.94 138.58 138.92 133.80 134.12 136.66
SA 66.48 83.08 95.56 121.42 67.04 86.4 103.86 134.6 79.62 94.56 101.04 130.84
Tabu Search 47.98 60.58 73.22 112.34 49.1 57.72 77.94 124.92 56.82 74.58 80.66 100.98
Evolutionary 27.49 29.95 30.86 31.5 30.52 30.61 32.43 32.49 30.54 30.65 31.49 32.59
CucKoo Search 497.88 476.66 450.99 450.57 471.45 464.25 457.35 442.40 459.05 472.80 449.80 439.98
0.00
100.00
200.00
300.00
400.00
500.00
TIE
MP
O D
E E
JEC
UC
IÓN
(s)
Comparación tiempos 25 clientes
43
Figura 5.14: Comparación de distancia promedio para 50 clientes
Figura 5.15: Comparación de distancia mínima para 50 clientes
r1_2_1 r1_2_2 r1_2_3 r1_2_4 r1_2_5 r1_2_6 r1_2_7 r1_2_8 r1_2_9 r1_2_10
Ant Colony 1185.03 1051.76 871.36 750.36 1120.74 1022.45 886.89 803.39 1030.28 912.00
SA 1234.2 1082.78 916.23 804.39 1144.72 1030.9 899.99 788.34 1056.64 998.06
Tabu Search 1238.11 1257.79 1158.92 1067.64 1251.8 1204.22 1134.73 1085.62 1245.75 1156.13
Evolutionary 1043.9 928.96 846.11 822.05 988.17 920.01 870.59 841.8 898.47 917.38
Cuckoo Search 1095.14 945.82 773.84 682.70 1001.32 906.25 762.87 681.56 889.31 829.19
650.00
750.00
850.00
950.00
1050.00
1150.00
1250.00
1350.00D
IST
AN
CIA
RE
CO
RR
IDA
Comparación promedio 50 clientes
r1_2_1 r1_2_2 r1_2_3 r1_2_4 r1_2_5 r1_2_6 r1_2_7 r1_2_8 r1_2_9r1_2_1
0
Ant Colony 1116.75 1002.37 829.33 608.76 1056.44 918.07 846.21 744.99 891.31 819.23
SA 1141.15 965.66 861.56 722.52 1039.29 922.67 832.91 711.16 974.39 905.58
Tabu Search 1118.22 1093.75 936.67 870.22 1137.34 1022.85 878.92 814.85 1036.22 949.9
Evolutionary 987.7 890.44 803.45 749.97 944.77 868.44 833.6 781.93 838.68 837.46
Cuckoo Search 1010.58 852.26 685.45 595.55 921.92 832.85 678.57 612.88 813.12 783.45
580.00
680.00
780.00
880.00
980.00
1080.00
1180.00
DIS
TA
NC
IA R
EC
OR
RID
A
Comparación mínimo 50 clientes
Figura 5.16: Comparación de tiempos en segundos para 50 clientes
Para problemas de 25 clientes en la mayor parte de los casos el MACS-ecVRP supera a las metaheurísticas de
Recocido simulado y Búsqueda tabú. No obstante, este no es el caso para el Algoritmo genético y la Búsqueda
cuco donde pocas veces se les llega a igualar o a superar. En la comparación de mínimos para 25 clientes vuelve
a encontrarse la misma situación, donde esta vez el MACS-ecVRP se sitúa entre la Búsqueda tabú y la Búqueda
cuco, a la que en ocasiones se le llega a superar. Como mejor resultado en comparación con el resto de algoritmos
cabe destacar que en el problema r103 de 25 clientes el algoritmo se acerca al 0.8% de la mejor solución
encontrada y por lo general se acerca a menos del 10%. Los tiempos para esta fase son entorno a los 120
segundos, que es el tiempo que se ha establecido para el criterio de finalización del MACS-ecVRP.
Por otro lado para los problemas de 50 clientes los resultados obtenidos por el MACS-ecVRP son mejores que
los obtenidos para 25 clientes. A la Búsqueda tabú y al Recocido simulado el algoritmo de hormigas los supera
en la mayor parte de los problemas mientras que al Algortimo genético solo en tres de ellos. En la comparación
de promedios el algoritmo se sitúa en general en torno al 10% de los mejores resultados. Para mínimos
encontrados por las distintas metaheurísticas el MACS-ecVRP sigue dando buenos resultados, para el r1_2_4
se acerca al 2.16% de la mejor solución encontrada, diferenciándose notablemente del resto de metaheurísticas.
En cuanto a los tiempos de ejecución, el criterio de finalización se ha establecido en 240 segundos por lo que el
promedio de tiempos suele estar entre los 290 segundos.
Se ha de tener en consideración, como se mencionó anteriormente, que el MACS-ecVRP ha sido diseñado para
reducir principalmente el número de vehículos, lo que no siempre conlleva una disminución de la distancia. Aun
así, los resultados son bastante competitivos y con posibilidad de mejora, como se verá en el siguiente capítulo
(Capítulo 6: Conclusiones).
r1_2_1 r1_2_2 r1_2_3 r1_2_4 r1_2_5 r1_2_6 r1_2_7 r1_2_8 r1_2_9 r1_2_10
Ant Colony 276.62 318.35 323.17 287.14 278.87 309.77 334.89 300.68 295.91 295.87
SA 171.02 240.32 310.52 480.58 168.32 232.74 331.82 512.06 181 212.82
Tabu Search 284.66 305.68 446.3 584.86 200.58 297.08 436.32 544 200.68 267.6
Evolutionary 122.55 119.01 118.38 115.3 116.37 111.2 113.61 117.75 110.75 112.82
Cuckoo Search 948.61 946.89 927.05 902.25 989.95 903.22 916.82 939.57 970.22 904.90
50.00
150.00
250.00
350.00
450.00
550.00
650.00
750.00
850.00
950.00
1050.00T
IEM
PO
DE
EJE
CU
CIÓ
N (
s)Comparación tiempos 50 clientes
45
6 CONCLUSIONES
ras la obtención de los resultados y la comparación de estos con los de otras metaheurísticas en este
capítulo se procede a evaluar cómo el algoritmo diseñado cumple los objetivos planteados y cómo se ha
llegado a alcanzar tales objetivos. Se propone al final del capítulo posibles mejoras del algoritmo que
podrían dar lugar a mejoras en los resultados o a la implantación del algoritmo en otros problemas de
distribución.
A continuación se exponen brevemente los principales puntos que se han considerado en este trabajo y que han
permitido llegar a los resultados finales.
Se han explicado los principales objetivos del presente proyecto, donde se ha mostrado la importancia
del mercado del comercio electrónico, y cómo tales objetivos suponen una clara mejoría para dicho
mercado.
Se han mostrado los principales servicios que existen en el mercado del comercio electrónico.
Posteriormente, se ha hecho una búsqueda exhaustiva de datos que respaldan los objetivos propuestos
en los diferentes informes de empresas públicas y privadas, así como en organismos del Gobierno. Tales
objetivos son válidos en el presente y, según las tendencias estudiadas hacia las que el mercado del
eCommerce evoluciona, también son válidos para el futuro.
Se ha explicado cómo el ecVRP responde a dichos objetivos. También se han presentado las variantes
de las que proviene el problema para después definirlo y exponer su formulación matemática. A
continuación, se han presentado las principales variantes en los problemas de distribución que
pertenecen a la misma familia que el ecVRP.
Tras la explicación del problema a resolver se ha mostrado cómo la literatura ha respondido a los
problemas de distribución, gracias a algoritmos exactos, heurísticas y metaheurísticas. Posteriormente
se ha profundizado en el tipo de algoritmo que concierne al presente proyecto, los algoritmos basados
en colonias de hormigas, donde se han explicado las variantes más importantes: Ant System
Optimization, Ant Colony System y Multimple Ant Colony System. Finalmente, se ha adaptado este
último al ecVRP mejorándolo además con heurísticas de inserción, que a su vez también han sido
mejorada y adaptadas. Como resultado se ha obtenido un nuevo algoritmo llamado MACS-ecVRP
Por último se ha resuelto una batería de problemas para comprobar la eficacia y eficiencia del algoritmo,
así como, la posterior comparación de los resultados con otras metaheurísticas.
En cuanto a la estructura del algoritmo cabe remarcar la versatilidad de este. Muchos problemas clásicos de
distribución pueden definirse como una particularización del ecVRP, como se dijo en el apartado 3.1. Es decir,
simplemente definiendo los datos del ecVRP, sin modificar ninguna ecuación, se pueden obtener distintos
problemas. Tales son, el TSP, CVRP, VRPTW y CVRPTW. Por tanto, este algoritmo al ser diseñado para el
ec-VRP no solo es capaz de resolver este, sino también las particularizaciones mencionadas.
De cara al futuro el MACS-ecVRP, con pequeñas modificaciones podría ser adaptado a otros problemas de
distribución, mencionados en el apartado 3.3, como son el OVRP o el HVRP. Además, también podría ser
mejorado mediante búsqueda local como el Operador 𝜆-intercambio que, a diferencia de otros algoritmos
basados en colonias de hormigas, la búsqueda se aplicaría cada vez que se mejorara la solución y no cada vez
que se encontrara una solución, como se indica en el ASO, ACS y MACS-VRPTW [22] [23] [24].
Finalmente, tras la obtención y comparación de resultados se puede concluir que el MACS-ecVRP cumple
notablemente los objetivos planteados superando en muchos casos a algoritmos tradicionales como la Búsqueda
tabú o el Recocido simulado. Además para ciertos problemas se acerca considerablemente a la mejor solución
T
hasta la fecha o se aproxima mucho a ella en tiempos de ejecución aceptables y competitivos. Por otro lado, el
algoritmo es capaz de reducir eficazmente el número de vehículos, llegando incluso a emplear un solo vehículo
para servir a 50 clientes.
Dichos resultados muestran una clara reducción de costes para futuras implementaciones del algoritmo que
permiten no solo ahorrar gastos a las empresas logísticas sino también reducir considerablemente los gastos de
envíos que tantos problemas causan a los consumidores. Además, resolviendo el ecVRP se hace factible la
posibilidad de ofrecerle al cliente distintos puntos donde recibir su mercancía, lo que supone para este un ahorro
de tiempos y una mejora de la calidad y de la flexibilidad de la entrega.
47
7 REFERENCIAS
[1] Everis; Cel; UNO, «Estudio de caracterización del sector del transporte y la logística en España,» 2016.
[2] Adigital, «Informe sobre logística para comercio electrónico en España,» 2016.
[3] A. Urueña, E. Prieto, M. P. Ballestero, R. Castro, S. Cadenas y J. A. Seco, «Estudio sobre Comercio
Electrónico B2C,» ONTSI, 2016.
[4] H. Torres Barroeta, J. Muñoz Casero, F. Rivas Díaz, M. López Masclans, J. J. Sanz Montiel, C. Pérez, Á.
Forriol Sanz, M. Ballesteros, C. Tello y J. L. Zimmermann, «Libro Blanco de Logística para Comercio
Electrónico,» Adigital, 2016.
[5] UPS , «Pulse of the Online Shopper,» 2014.
[6] IAB Spain, «Estudio Anual de eCommerce,» 2016.
[7] KPMG, «La realidad de los consumidores online,» 2017.
[8] K. Lobaugh, B. McConnell, C. Cheng y L. Bailey, «Fifth annual eCommerce assessment,» Deloitte, 2014.
[9] G. B. Ramser y J. H. Dantzig, «The Truck Dispatching Problem,» Management Science, vol. 6, nº 1, pp.
80-91, 1959.
[10] R. V. Kulkarni y P. R. Bhave, «Integer programming formulations of vehicle,» European Journal of
Operational Research, vol. 20, nº 1, pp. 58-67, 1985.
[11] M. Salari, P. Toth y A. Tramontani, «An ILP improvement procedure for the Open Vehicle Routing
Problem,» Computers & Operations Research, vol. 37, pp. 2106-2120, 2010.
[12] N. Christofides y E. Beasley J., «The period routing problem,» Networks, vol. 14, pp. 237-256, 1984.
[13] J. R. M. -Torres, J. L. Franc, S. N. Isaza, H. F. Jiménez y NilsonHerazo-Padilla, «A literature review on
the vehicle routing problem with multiple depots,» Computers & Industrial Engineering, vol. 79, pp. 115-
129, 2015.
[14] J. M. Framinan, R. Leisten y R. Ruiz García, «Exact Algorithms,» de Manufacturing Scheduling Systems:
An Integrated View on Models, Methods and Tools, London, Springer London, 2014, pp. 191-216.
[15] N. Christofides, A. Mingozzi y P. Toth, «Exact algorithms for the vehicle routing problem, based on
spanning tree and shortest path relaxations,» Mathematical Programming, vol. 20, pp. 255-282, 01 12
1981.
[16] G. Clarke y J. W. Wright, «Scheduling of Vehicles from a Central Depot to a Number of Delivery Points,»
Operations Research, vol. 12, nº 4, pp. 568 - 581, 1964.
[17] L. Fisher Marshall y J. Ramchandran, «A generalized assignment heuristic for vehicle routing,» Networks,
vol. 11, pp. 109-124.
[18] F. Herrera, «Introducción a los algoritmos metaheurı́sticos,» Ciencias de la Computación e IA, 2006.
[19] J. H. Holland, Adaptation in natural and artificial systems: an introductory analysis with applications to
biology, control, and artificial intelligence, University of Michigan Press, 1975.
[20] C. Uribe Astolfi y A. Escudero Santana, Resolución de un VRP con ventanas móviles mediante el uso del
algoritmo Cuckoo Search Trabajo Fin de Máster, ed., : , pp. 1 CD-ROM ; .
[21] M. Dorigo, «Optimization, Learning and Natural Algorithms (in Italian),» Milan, 1992.
[22] M. Dorigo, V. Maniezzo y A. Colorni, «Ant system: optimization by a colony of cooperating agents,»
IEEE Transactions on Systems, Man, and Cybernetics, Part B (Cybernetics), vol. 26, nº 1, pp. 29 - 41,
1996.
[23] M. Dorigo y L. Gambardella, «Ant colony system: a cooperative learning approach to the traveling
salesman problem,» IEEE Transactions on Evolutionary Computation , vol. 1, nº 1, pp. 53 - 66, 1997.
[24] L. M. Gambardella, É. Taillard y G. Agazzi, «MACS-VRPTW: A multiple ant colony system for vehicle
routing problems with time windows,» de New Ideas in Optimization, Lugano, Switzerland, 1999.
[25] I. Ellabib, O. A. Basir y P. Calamai, «An Experimental Study of a Simple Ant Colony System for the
Vehicle Routing Problem with Time Windows,» de Ant Algorithms, Berlin, 2002.
[26] M. M. Solomon, «Algorithms for the Vehicle Routing and Scheduling Problems with Time Window
Constraints,» Oper. Res., vol. 35, pp. 254-265, 4 1987.
[27] J. W. Joubert y S. J. Claasen, «A sequential insertion heuristic for the initial solution to a constrained
vehicle routing problem,» ORiON, vol. 22, 2006.
[28] A. M. Campbell y M. Savelsbergh, «Efficient Insertion Heuristics for Vehicle Routing and Scheduling
Problems,» Transportation Science, vol. 38, pp. 369-378, 2004.
49
8 ANEXO: CÓDIGO DE PROGRAMACIÓN
Se muestra a continuación el código diseñado, elaborado y empleado para la realización de este proyecto. El
lenguaje de programación escogido es Python 3.
8.1 Código principal (MACS-ecVRP, ACS-VEI y ACS-TIME)
import numpy as np
import matplotlib.pyplot as plt
import Insertion_Heuristic2 as IH2
import time
import multiprocessing as mp
starting_point = time.time()
class City:
def __init__(self, x, y, index, demand, ready_time, due_date,
service_time):
self.index = index
self.x = x
self.y = y
self.demand = demand
self.r_time = ready_time
self.d_date = due_date
self.service_time = service_time
self.time_e = ready_time
self.time_l = due_date
self.ruta = 0
class Ant:
def __init__(self, i, cities, capacity, n_depositos):
self.index = i
self.tam_camino = 0
self.current_city = cities[np.random.randint(0, n_depositos)]
self.camino = []
self.camino.append(self.current_city)
self.camino_int = []
self.camino_int.append(0)
self.unvisited = [] # Ciudades sin visitar
self.unvisited.extend(cities[n_depositos:])
self.unvisited_int = []
self.unvisited_int.append(cities[n_depositos:].index)
self.unvisited_wh = [] # Depósitos sin visitar
self.unvisited_wh.extend(cities[1:n_depositos])
self.cur_capacity = 0
self.capacity = capacity
self.capacity2 = capacity
self.n_depot = n_depositos
self.n_veh = 1
self.current_time = 0
def resetear(self, cities):
self.tam_camino = 0
self.current_city = cities[np.random.randint(0, self.n_depot)]
self.camino = []
self.camino.append(self.current_city)
self.camino_int = []
self.camino_int.append(cities[0].index)
self.unvisited = []
self.unvisited.extend(cities[self.n_depot:])
self.unvisited_int = []
for i in self.unvisited:
self.unvisited_int.append(i.index - self.n_depot + 1)
self.unvisited_wh = []
self.unvisited_wh.extend(cities[1:self.n_depot])
self.cur_capacity = 0
self.capacity = self.capacity2
self.n_veh = 1
self.current_time = 0
numero_clientes = 25
#Criterio de finalización MACS-ecVRP en segundos
tiempo_max_seg = 120
#Criterio de finalización ACS-VEI y ACS TIME
n_it = 100
G = 3
# PARÁMETROS
q_0 = 0.1
alpha = 1
beta = 1
rho_evap = 0.1
numero_hormigas = 10
metodo_visibilidad = 1 # 1 es con polares, otro es solo la distancia
Q = 10000 # Capacidad de los vehículos
numero_ciudades = numero_clientes * G
# Crea una lista con todas las ciudades como clase City más el número de
depósitos inicial.
def constructora(d_file, numero_de_depositos, n_modif):
cities = list(range(0, n_modif))
for i in range(0, numero_de_depositos):
cities[i] = City(d_file[0][1], d_file[0][2], i, d_file[0][3],
d_file[0][4], d_file[0][5], 0)
n_c = 0
clientes = []
for i in range(numero_de_depositos, n_modif):
# Añade las ciudades a la lista de ciudades
cities[i] = City(d_file[i - numero_de_depositos + 1][1], d_file[i -
numero_de_depositos + 1][2], i, d_file[i - numero_de_depositos + 1][3],
d_file[i - numero_de_depositos + 1][4], d_file[i - numero_de_depositos +
1][5], 0)
# Crea una lista que identifica cada ciudad con su cliente
correspondiente
if (i - numero_de_depositos) % 3 == 0:
clientes.append([cities[i].index])
if i != numero_de_depositos:
n_c += 1
51
else:
clientes[n_c].append(cities[i].index)
return cities, clientes
# Crea una lista con todas las hormigas como clase Ant
def hormiguero(tamano, cities, Q, n_depo, n_modif):
ants = list(range(0, tamano))
for i in range(0, tamano):
ants[i] = Ant(i, cities, Q, n_depo)
for i in range(0, tamano):
for j in range(n_depo, n_modif):
ants[i].unvisited_int.append(cities[j].index)
return ants
# Crea una matriz con todas las distancias entre nodos y otra matriz (TWCM)
que indica si es imposible ir de una ciudad a otra sea cual sea la
circustancia
def calc_distancia_TWCM(n_modif, cities):
TWCM = np.full((n_modif, n_modif), 0) # Si vale 0, se aplican
restricciones de tiempo, si no, es un CVRP
distancia = np.full((n_modif, n_modif), 0.00)
for i in cities:
for j in cities:
Ax = i.x - j.x
Ay = i.y - j.y
distancia[i.index][j.index] = np.sqrt(Ax ** 2 + Ay ** 2)
ae = distancia[i.index][j.index] + i.r_time + i.service_time
if (j.d_date - ae) >= 0:
TWCM[i.index][j.index] = 1
return distancia, TWCM
# Crea todos los datos anteriores al mismo tiempo, sirve para cuando se
encuentre una solución con menos vehículos eliminar todos los datos y crear
datos nuevos con uno o varios depósitos menos
def crea_datos(numero_depositos,matriz_ciudades):
global numero_clientes
global Q
global numero_hormigas
numero_de_ciudades = numero_clientes * 3
n_modif = numero_depositos + numero_de_ciudades
cities, clientes = constructora(matriz_ciudades, numero_depositos,
n_modif)
ants = hormiguero(numero_hormigas, cities, Q, numero_depositos, n_modif)
distancia, TWCM = calc_distancia_TWCM(n_modif, cities)
return cities, clientes, ants, distancia, TWCM, n_modif
# Elimina todos los datos que dependan del número de vehículos
def elimina_datos():
global cities
global clientes
global ants
global distancia
global TWCM
global n_modif
del (cities, clientes, ants, distancia, TWCM, n_modif)
# Calcula el tamaño de un camino realizado por una hormiga.
def calc_tam_camino(camino):
dist = 0.00
for i in range(1, len(camino)):
Ax = camino[i].x - camino[i - 1].x
Ay = camino[i].y - camino[i - 1].y
dist += np.sqrt(Ax ** 2 + Ay ** 2)
return dist
# Los mismo que "calc_tam_camino" función pero además actualiza la variable
IN, que se usa en la colonia ACS-VEI
def calc_tam_camino_v3(camino, numero_de_depositos, IN, clientes, cities):
dist = 0.00
IN_aux = np.full(len(IN), 0)
for i in range(1, len(camino)):
Ax = camino[i].x - camino[i - 1].x
Ay = camino[i].y - camino[i - 1].y
dist += np.sqrt(Ax ** 2 + Ay ** 2)
if camino[i].index >= numero_de_depositos:
indice = camino[i].index - numero_de_depositos + 1
indice_cliente = int(np.ceil(indice / 3)) - 1
for j in range(0, 3):
IN_aux[cities[clientes[indice_cliente][j]].index] = 1
for i in range(1, len(IN)):
if IN_aux[i] == 0:
IN[i] += 1
return dist, IN
# Transforma una ruta representada por una lista de enteros en una lista de
objetos City
def covert_camino(camino_int, n_depot, cities):
cc = 0
camino = []
for value in camino_int:
if value == 0:
camino.append(cities[cc])
if cc < n_depot - 1:
cc += 1
elif cc == n_depot - 1:
cc = 0
else:
camino.append(cities[value + n_depot - 1])
return camino
# Calcula las ciudades disponibles para una hormiga en una posicion y tiempo
determinados
def ciudad_disponible(ant, distancia, n_depot):
feasibles_cities = []
feasibles_cities_int = []
if ant.current_city.index >= n_depot:
feasibles_cities.extend(ant.unvisited_wh)
for j in ant.unvisited_wh:
feasibles_cities_int.append(j.index - n_depot + 1)
for j in ant.unvisited:
if (ant.capacity >= ant.cur_capacity + j.demand) & (
ant.current_time + distancia[ant.current_city.index][j.index]
<= j.d_date):
feasibles_cities.append(j)
feasibles_cities_int.append(j.index - n_depot + 1)
return feasibles_cities, feasibles_cities_int
53
# Calcula el numero de vehiculos usados.
def active_vehicles(camino, n_depot):
n_veh = -1
for i in camino:
if i.index < n_depot:
n_veh += 1
return n_veh
# Calcula el numero de clientes visitados.
def visited_costumers(camino, n_depo):
veh = active_vehicles(camino, n_depo)
return (len(camino) - veh - 1)
# Calcula las coincidencias entre dos caminos
def calc_coincidencias(camino1, camino2):
coincidencia1 = np.full((len(cities), len(cities)), 0)
coincidencia2 = np.full((len(cities), len(cities)), 0)
n_coincidencias = 0
for i in range(0, len(camino1) - 1):
coincidencia1[camino1[i].index][camino1[i + 1].index] = 1
for i in range(0, len(camino2) - 1):
coincidencia2[camino2[i].index][camino2[i + 1].index] = 1
for i in range(0, len(cities)):
for j in range(0, len(cities)):
if coincidencia1[i][j] == 1 & coincidencia2[i][j] == 1:
n_coincidencias += 1
return n_coincidencias
# Actualiza la pheromone global y localmente
def update_pheromone(camino, tam_camino, evaporation, pheromone):
pheromone = (1 - evaporation) * np.array(pheromone)
for i in range(0, len(camino)):
if i < (len(camino) - 1):
curr_pher = pheromone[camino[i].index][camino[i + 1].index]
pheromone[camino[i].index][camino[i + 1].index] = (curr_pher +
evaporation / tam_camino)
else:
curr_pher = pheromone[camino[i].index][camino[1].index]
pheromone[camino[i].index][camino[1].index] = (curr_pher +
evaporation / tam_camino)
return pheromone
def update_local(i, j, evaporation, tau_0, pheromone):
curr_pher = pheromone[i][j] * (1 - evaporation)
pheromone[i][j] = curr_pher + evaporation * tau_0
return pheromone
# Muestra por pantalla un camino. C es ciudad y D es depósito
def print_camino(camino, numero_depositos):
for ciudad in camino:
if ciudad.index < numero_depositos:
print(' %d(D),' % ciudad.index, end='')
else:
print(' %d(C),' % ciudad.index, end='')
# Hago la eleccion para todas las hormigas
# El corazón del código
def new_active_ant(ant, pheromone, IN, i_pheromone, numero_depositos, cities,
distancia, TWCM, clientes, AcsVei):
ant.resetear(cities)
if AcsVei: # ACS-VEI tiene que usar un vehiculo menos que la mejor
solución factible encontrada
ant.unvisited_wh = ant.unvisited_wh[:-1]
while ant.unvisited:
transition_probabilities = []
# Teniendo en cuenta las restricciones, obtiene una lista de las
ciudades factibles
feasibles_cities, feasibles_cities_int = ciudad_disponible(ant,
distancia, numero_depositos)
# Si no hay ciudades factibles, la hormiga termina y vuelve al
depósito inicial.
if not feasibles_cities:
ant.camino.append(ant.camino[0])
ant.camino_int.append(0)
ant.current_city = ant.camino[0]
break
# Calcula de la probabilidad
for j in feasibles_cities:
if metodo_visibilidad == 1: # Método dinámico de la visibilidad,
se tienen en cuenta los ángulos polares entre dos nodos.
T_ij = max(distancia[ant.current_city.index][j.index],
j.r_time - ant.current_time)
V_ij = j.d_date - ant.current_time
P_ij = abs(np.arctan((ant.current_city.y /
ant.current_city.x)) - np.arctan((j.y / j.x)))
C_ij = 0.95 * T_ij * V_ij + 0.05 * P_ij
distance_ij = max(1, (C_ij - IN[j.index]))
numerator = pow(pheromone[ant.current_city.index][j.index],
alpha) * pow(1 / distance_ij, beta)
else: # Método original y estático de la visibilidad, da peores
resultados y actualmente esta parte de código no se usa
numerator = pow(pheromone[ant.current_city.index][j.index],
alpha) * pow(visibilty[ant.current_city.index][j.index], beta)
transition_probabilities.append(numerator)
# Selecciona la siguiente ciudad, puede centrarse en la exploración
(más aleatorio) o en la explotación (más búsqueda local)
p = np.random.uniform(0, 1)
if p <= q_0:
# Explotaition
next_city_i =
transition_probabilities.index(max(transition_probabilities))
next_city = feasibles_cities[next_city_i]
else:
# Exploration
denominator = sum(transition_probabilities)
transition_probabilities1 = [x / float(denominator) for x in
transition_probabilities]
lista = list(range(0, len(feasibles_cities)))
next_city_i = np.random.choice(lista, 1,
p=transition_probabilities1)
next_city = feasibles_cities[next_city_i[0]]
# Actualiza el tiempo
ant.current_time = max(ant.current_time +
distancia[ant.current_city.index][next_city.index], next_city.r_time) +
next_city.service_time
55
# Actualiza la feromona desde "Current City" hasta "Next City"
pheromone = update_local(ant.current_city.index, next_city.index,
rho_evap, i_pheromone, pheromone)
# Cambia la ciudad actual, el camino recorrido de la hormiga y la
lista de ciudades por visitar
ant.camino.append(next_city)
if TWCM[ant.current_city.index][next_city.index] == 0:
print('Error de', ant.current_city.index - numero_depositos + 1,
'a', next_city.index - numero_depositos + 1)
ant.current_city = next_city
if next_city.index < numero_depositos:
ant.cur_capacity = 0
ant.current_time = 0
ant.n_veh += 1
ant.camino_int.append(0)
ant.unvisited_wh.pop(ant.unvisited_wh.index(next_city))
else:
ant.camino_int.append(next_city.index - numero_depositos + 1)
ant.cur_capacity = ant.cur_capacity + ant.current_city.demand
# Detecta el cliente al que pertenece la ciudad actual y elimina
todas las ciudades de dicho cliente de la lista de ciudades por visitar
indice = next_city.index - numero_depositos + 1
indice_cliente = int(np.ceil(indice / 3)) - 1
for i in range(0, 3):
ant.unvisited.remove(cities[clientes[indice_cliente][i]])
ant.unvisited_int.remove(cities[clientes[indice_cliente][i]].index -
numero_depositos + 1)
# Ordena a la hormiga volver al depósito cuando haya visitado todas
las ciudades
if (not ant.unvisited):
ant.camino.append(ant.camino[0])
ant.camino_int.append(0)
ant.current_city = ant.camino[0]
break
# Añade a la ruta, mediante inserción, el mayor número posible de
ciudades
if ant.unvisited:
ant.camino, ant.camino_int, rutas =
IH2.complete_feasible_v3(ant.unvisited, ant.camino, ant.camino_int,
numero_depositos, distancia, Q, TWCM, cities, clientes, ant.unvisited_int,
AcsVei)
ant.n_veh = len(rutas)
ciudades_visitadas = len(ant.camino_int) - ant.n_veh - 1
return ant.camino, ant.n_veh, ant.camino_int, ciudades_visitadas,
pheromone
# ACS-VEI
def ACS_VEI(n_it, numero_depositos, cities, clientes, ants, distancia, Q,
TWCM, cola, cola_ACS,semaforo_1,lock):
#Espera a que el ASC-TIME se active
while True:
if semaforo_1.full():
semaforo_1.get()
break
time.sleep(0.1)
# Si el número de depósitos es igual a 1 ACS-VEI ya no necesita ser
ejecutado
if numero_depositos == 1:
print('Fin de la Colonia VEI')
return
#Recoge la mejor solución factible encontrada hasta el momento
mejor_camino2 = []
if not cola_ACS.empty():
try:
mejor_camino2 = cola_ACS.get(False)
mejor_camino_int2 = cola_ACS.get(False)
except Exception as e:
print(type(e))
try:
mejor_camino2 = cola_ACS.get(True,2)
mejor_camino_int2 = cola_ACS.get(True,2)
except Exception as e:
print(type(e))
tam_mejor_camino2 = calc_tam_camino(mejor_camino2)
if not cola.empty():
cola.get(True, 2)
if not cola.empty():
cola.get(True, 2)
#Inicializa el vector IN y la variable it
IN = np.full(len(cities), 0)
it = 0
# Genera una ruta inicial con un numero menos de vehículos disponibles
mejor_camino, mejor_camino_int, rutas_demanda =
IH2.Insertion_VEI(numero_depositos, distancia, Q, TWCM, cities,
clientes)
mejor_v = active_vehicles(mejor_camino, numero_depositos)
mejor_c = visited_costumers(mejor_camino, numero_depositos)
tam_mejor_camino = calc_tam_camino(mejor_camino)
# Inicializa la feromona
i_pheromone = 1.00 / (tam_mejor_camino * len(cities))
pheromone = np.full((len(cities), len(cities)), i_pheromone)
paro = 0 #Permite parar ACS-VEI en un 20% de iteraciones sin mejoría
for vuelta in range(0, n_it):
print('ACS_VEI ', vuelta * 100 / n_it, '%', ' || Mejor_c =
%d/%d' % (mejor_c, len(clientes)),
' Try_v = ', mejor_v, 'Distancia = ', tam_mejor_camino)
for hor in ants:
# Ordena al hormiguero realizar rutas y luego las compara con la
mejor solución no factible hasta el momento
camino_actual, n_veh_actual, camino_actual_int,
ciudades_visitadas, pheromone = new_active_ant(hor, pheromone, IN,
i_pheromone, numero_depositos, cities, distancia, TWCM, clientes, True)
c_actual = visited_costumers(camino_actual, numero_depositos)
tam_camino_actual, IN = calc_tam_camino_v3(camino_actual,
numero_depositos, IN, clientes, cities)
it += 1
#Compara la solución obtenida
if mejor_c < c_actual:
mejor_c = c_actual
tam_mejor_camino = tam_camino_actual
57
mejor_camino = camino_actual
mejor_camino_int = camino_actual_int
IN = 0 * np.array(IN)
paro = 0
elif (mejor_c == c_actual) & (tam_mejor_camino >
tam_camino_actual):
tam_mejor_camino = tam_camino_actual
mejor_camino = camino_actual
mejor_camino_int = camino_actual_int
IN = 0 * np.array(IN)
# Dos actualizaciones de feromonas una con la mejor solucion no
factible y otra con la mejor factible.
pheromone = update_pheromone(mejor_camino, tam_mejor_camino,
rho_evap, pheromone)
if cola_ACS.full(): # Recibe informacion de ACS-TIME. Si ACS-TIME
mejora su solucion se la envía a ACS-VEI.
try:
mejor_camino2 = cola_ACS.get(timeout=0)
tam_mejor_camino2 = calc_tam_camino(mejor_camino2)
except Exception:
break
if mejor_camino2:
try:
pheromone = update_pheromone(mejor_camino2,
tam_mejor_camino2, rho_evap, pheromone)
except IndexError:
pass
mejor_v = active_vehicles(mejor_camino, numero_depositos)
if mejor_c == len(
clientes): # Si se encuentra una solución factible el
algoritmo de para y se le envía la solución al programa principal.
lock.acquire()
cola.put(mejor_camino,True,2)
cola.put(mejor_camino_int, True, 2)
lock.release()
return mejor_camino, mejor_camino_int, mejor_c
if (paro * 100 / n_it) > 20: # Para el algoritmo si no se mejora la
solucion.
break
paro += 1
return mejor_camino, mejor_camino_int, mejor_c
# ACS-TIME
def ACS_TIME(n_it, mejor_v, cities, clientes, ants, distancia, mejor_camino,
mejor_camino_int, TWCM, cola, cola_ACS,semaforo_1,lock):
#Manda señal a ACS-VEI para que pueda continuar
while True:
if semaforo_1.empty():
semaforo_1.put(True)
break
IN = np.full(len(cities), 0) # En esta parte del algoritmo no se tiene
en cuenta la variable IN
tam_mejor_camino = calc_tam_camino(mejor_camino)
#Inicializa parámetros
i_pheromone = 1.00 / (tam_mejor_camino * len(cities))
pheromone = np.full((len(cities), len(cities)), i_pheromone)
it = 0
tiempo = 1
sum_v = 0
for vuelta in range(0, n_it):
#Calcula el tiempo aproximado restante.
diferencia = max(0.00000001, time.time() - tiempo)
tiempo = time.time()
velocidad = 1 / diferencia
sum_v += velocidad
v_media = sum_v / (vuelta + 1)
print('ACS_TIME', (vuelta + 1) * 100 / n_it, '% ||
Mejor_v =', mejor_v, 'Distancia = ', tam_mejor_camino, ' Tiempo restante = %d
min %d s' % (int((n_it - vuelta - 1) / (v_media * 60)), int(((n_it - vuelta -
1) / v_media) % 60)))
suma_unfe = 0
for hor in ants:
camino_actual, n_veh_actual, camino_actual_int,
ciudades_visitadas, pheromone = new_active_ant(hor, pheromone, IN,
i_pheromone, mejor_v, cities, distancia, TWCM, clientes, False)
if ciudades_visitadas == len(clientes):
tam_camino_actual = calc_tam_camino(camino_actual)
it += 1
if mejor_v > n_veh_actual: # Si se encuentra un camino con
menos vehículos se le envía la información al programa principal y se para el
algoritmo.
mejor_v = n_veh_actual
mejor_camino = camino_actual
mejor_camino_int = camino_actual_int
lock.acquire()
cola.put(mejor_camino, True, 2)
cola.put(mejor_camino_int, True, 2)
lock.release()
return mejor_camino, mejor_camino_int, mejor_v
elif (mejor_v == n_veh_actual) & (tam_mejor_camino >
tam_camino_actual):
tam_mejor_camino = tam_camino_actual
mejor_camino = camino_actual
mejor_camino_int = camino_actual_int
if not cola_ACS.full(): # Si se mejora la distancia se
le envia la informacion a la colonia ACS-VEI
cola_ACS.put(mejor_camino,True, 2)
cola_ACS.put(mejor_camino_int,True, 2)
else:
suma_unfe += 1
pheromone = update_pheromone(mejor_camino, tam_mejor_camino,
rho_evap, pheromone)
lock.acquire()
cola.put(mejor_camino) # Esta es la solución final de algoritmo
cola.put(mejor_camino_int)
lock.release()
time.sleep(3)
return mejor_camino, mejor_camino_int, mejor_v
#Muestra por pantalla la solución gráfica de un camino
def grafica_camino(camino,n_depo,cities):
for i in range(n_depo-1,len(cities)):
indice=(cities[i].index-n_depo)%3
id_ciudad = cities[i].index-n_depo+1
texto = '('+ str(int((id_ciudad+3-indice+1)/3))+','+str(indice+1)+')'
if cities[i].index<n_depo:
plt.plot(cities[i].x,cities[i].y,'kp')
59
elif indice == 0:
plt.plot(cities[i].x, cities[i].y, 'b.')
elif indice == 1:
plt.plot(cities[i].x, cities[i].y, 'r.')
elif indice == 2:
plt.plot(cities[i].x, cities[i].y, 'g.-')
if cities[i].index < n_depo:
plt.annotate('(almacén)', xy=(cities[i].x, cities[i].y),
xytext=(cities[i].x + 1, cities[i].y))
else:
plt.annotate(texto, xy=(cities[i].x, cities[i].y),
xytext=(cities[i].x + 1, cities[i].y + 1))
plt.axis([0, 75, 0, 85])
for i in range(len(camino)-1):
dx=camino[i+1].x-camino[i].x
dy=camino[i+1].y-camino[i].y
plt.arrow(camino[i].x,camino[i].y,dx,dy,length_includes_head=True,head_width=
0.95,width=0.0005)
plt.show()
plt.clf()
if __name__ == '__main__':
archivo = 'r101.txt'
matriz_ciudades = np.loadtxt(archivo)
tiempo_iteracion = time.time()
n_depot = 30
# Creo los datos iniciales
cities, clientes, ants, distancia, TWCM, n_modif =
crea_datos(n_depot,matriz_ciudades)
# Solución inicial
mejor_camino, mejor_camino_int, h =
IH2.Insertion_Heuristic_I1_v3(n_depot, distancia, Q, TWCM, cities,
clientes)
tam_mejor_camino = calc_tam_camino(mejor_camino)
# Actualizo el nuevo número de depósitos, que siempre será igual al
número de vehículos
n_depot = active_vehicles(mejor_camino, n_depot)
mejor_v = n_depot
# Destruyo los datos anteriores
elimina_datos()
del mejor_camino
# Creo datos nuevos a partir del nuevo número de depósitos
cities, clientes, ants, distancia, TWCM, n_modif =
crea_datos(n_depot,matriz_ciudades)
# Los caminos (listas de objetos City) dependen del número de depósitos,
pues los objetos City tienen un .index quedepende de este número. Por eso es
necesario transmitir la informacion mediante lista de enteros para que
nodependan del número de depósitos porque cuando se destruyen y construyen
los datos los .index de las ciudades cambian
mejor_camino = covert_camino(mejor_camino_int, n_depot, cities)
tiempo = time.time()
# Creo las colas y semáforos que me servirán para transmitir la
información y coordinarla
cola = mp.JoinableQueue(2)
cola_ACS = mp.JoinableQueue(2)
semaforo_1= mp.JoinableQueue(1)
cola_ACS.put(mejor_camino)
cola_ACS.put(mejor_camino_int)
lock = mp.Lock()
# MACS-ecVRP
while True:
# Define los procesos
A_TIME = mp.Process(target=ACS_TIME, args=(
n_it, n_depot, cities, clientes, ants, distancia, mejor_camino,
mejor_camino_int, TWCM, cola, cola_ACS,semaforo_1,lock))
A_VEI = mp.Process(target=ACS_VEI,
args=(n_it, n_depot, cities, clientes, ants,
distancia, Q, TWCM, cola, cola_ACS,semaforo_1,lock))
# Activa los proceso
A_VEI.start()
A_TIME.start()
while (A_VEI.is_alive() or A_TIME.is_alive()):
#Recoge la solución enviada por ACS-TIME o ACS-VEI
if cola.full():
mejor_camino = cola.get()
mejor_camino_int = cola.get()
time.sleep(1)
try:
A_VEI.terminate()
except AttributeError:
pass
try:
A_TIME.terminate()
except AttributeError:
pass
break
time.sleep(2)
if not cola.empty():
cola.get(True,2)
if not cola.empty():
cola.get(True,2)
n_depot_new = active_vehicles(mejor_camino, n_depot)
if n_depot != n_depot_new:
# Destruyo
elimina_datos()
del mejor_camino
del A_VEI
del A_TIME
n_depot=n_depot_new
# Construyo
cities, clientes, ants, distancia, TWCM, n_modif =
crea_datos(n_depot,matriz_ciudades)
mejor_camino = covert_camino(mejor_camino_int, n_depot, cities)
if n_depot <= 1:
break
if (time.time() - tiempo) > tiempo_max_seg:
break
tiempo_final = time.time() - tiempo_iteracion
#Muestra los resultados
np.set_printoptions(precision=1)
tam_mejor_camino = calc_tam_camino(mejor_camino)
print('\nDistancia recorrida: ', tam_mejor_camino)
print('Numero de vehiculos usados: %d' % n_depot)
print('Camino:', mejor_camino_int)
61
elapsed_time_int = int(time.time() - starting_point)
print('Tiempo total transcurrido:', int((time.time() - starting_point) /
60), 'min y',
(time.time() - starting_point) % 60, 'seg')
grafica_camino(mejor_camino,n_depot,cities)
elimina_datos()
del mejor_camino
del cola
del lock
8.2 Código auxiliar (Insertion Heuristics)
import numpy as np
alpha1 = 1
alpha2 = 0
mu = 1
# Devuelve True y otros datos si es posible ubicar una ciudad 'u' en la
posción de la ciudad 'p'
def cambio_factible(u, p, Q, distancia, visitadas, pos, mu, alpha1, alpha2,
ruta_demanda, TWCM):
e_j = 0
l_j = 0
coste1 = 0
resultado = False
if (TWCM[visitadas[pos - 1].index][u.index] == 0) or
(TWCM[u.index][p.index] == 0):
return resultado, coste1, e_j, l_j
# e_j y l_j equivalen a te_j y tl_j explicados anteriormente
e_j = max(u.r_time, visitadas[pos - 1].time_e +
distancia[u.index][visitadas[pos - 1].index] + visitadas[
pos - 1].service_time)
l_j = min(u.d_date, visitadas[pos].time_l -
distancia[u.index][visitadas[pos].index] - u.service_time)
if (e_j < l_j) & (ruta_demanda < Q - u.demand):
resultado = True
coste11 = distancia[u.index][visitadas[pos].index] +
distancia[u.index][
visitadas[pos - 1].index] - mu * distancia[visitadas[pos -
1].index][
visitadas[pos].index]
coste12 = max(visitadas[pos].time_l, e_j +
distancia[u.index][visitadas[pos - 1].index]) - visitadas[
pos].time_l # b_ju-b_j
coste1 = alpha1 * coste11 + alpha2 * coste12
return resultado, coste1, e_j, l_j
else:
return resultado, coste1, e_j, l_j
#Devuelve una lista de ciudades disponibles
def ciudad_disponible(current_city, current_time, cur_capacity, capacity,
unvisited, distancia, deposito):
feasibles_cities = []
feasibles_cities_int = []
for j in unvisited:
if (capacity >= cur_capacity + j.demand) & (
current_time + distancia[current_city.index][j.index] <=
j.d_date):
feasibles_cities.append(j)
feasibles_cities_int.append(j.index)
if (not feasibles_cities) & (current_city.index != 0):
feasibles_cities.append(deposito)
feasibles_cities_int.append(deposito.index)
return feasibles_cities, feasibles_cities_int
#Insertion Heuristic que añade ciudades a una solución obtenida por una
hormiga
def complete_feasible_v3(unvisited, visited, visited_int, n_depo, distancia,
Q, TWCM, cities, clientes, unvisited_int,
AcsVei):
if AcsVei:
max_depot = n_depo - 1
else:
max_depot = n_depo
# Calculo todos los e_j y l_j
rutas_demanda = []
v = 0
ruta = 0
rutas_demanda.append(0)
visited[0].time_e = visited[0].r_time
visited[len(visited) - 1].time_l = visited[len(visited) - 1].d_date
for k in range(len(visited) - 2, 0, -1):
if visited[k].index < n_depo:
visited[k].time_l = visited[k].d_date
ruta += 1
else:
visited[k].time_l = min(visited[k].d_date,
visited[k + 1].time_l -
distancia[visited[k].index][visited[k + 1].index] - visited[
k].service_time)
visited[k].ruta = ruta
for k in range(1, len(visited)):
if visited[k].index < n_depo:
visited[k].time_e = visited[k].r_time
rutas_demanda.append(0)
v += 1
else:
visited[k].time_e = max(visited[k].r_time,
visited[k - 1].time_e +
distancia[visited[k - 1].index][visited[k].index] + visited[
k - 1].service_time)
rutas_demanda[v] += visited[k].demand
del rutas_demanda[-1]
while unvisited:
costes1 = []
for ciudad in unvisited:
b = 0
ruta_index = 0
for posicion, c in enumerate(visited):
if (posicion != 0):
Resultado, coste1, e_j, l_j = cambio_factible(ciudad, c,
Q, distancia, visited, posicion, mu,
alpha1,
alpha2,
rutas_demanda[ruta_index], TWCM)
if Resultado == True:
b += 1
63
if b == 1:
coste_min = coste1
pos_min = posicion
ruta_min = ruta_index
e_umin = e_j
d_umin = l_j
if coste1 < coste_min:
coste_min = coste1
pos_min = posicion
ruta_min = ruta_index
e_umin = e_j
d_umin = l_j
if visited[posicion].index < n_depo:
ruta_index += 1
if b != 0:
costes1.append([ciudad, coste_min, pos_min, ruta_min, e_umin,
d_umin])
if (not costes1) & (len(rutas_demanda) < max_depot):
visited.append(cities[0])
visited_int.append(0)
rutas_demanda.append(0)
elif not costes1:
return visited, visited_int, rutas_demanda
else:
b = 0
for i in range(len(costes1)):
coste2 = 2 * distancia[0][costes1[i][0].index] -
costes1[i][1]
b += 1
if b == 1: # Inicializo ciertas variables
ciudad_opt = costes1[i][0]
coste2_opt = costes1[i][1]
i2 = i
if coste2 > coste2_opt:
ciudad_opt = costes1[i][0]
coste2_opt = costes1[i][1]
i2 = i
visited_int.insert(costes1[i2][2], ciudad_opt.index - n_depo + 1)
visited.insert(costes1[i2][2], ciudad_opt)
rutas_demanda[costes1[i2][3]] += ciudad_opt.demand
indice = ciudad_opt.index - n_depo + 1
indice_cliente = int(np.ceil(indice / 3)) - 1
for i in range(0, 3):
unvisited.remove(cities[clientes[indice_cliente][i]])
unvisited_int.remove(cities[clientes[indice_cliente][i]].index - n_depo + 1)
ciudad_opt.time_e = costes1[i2][4]
ciudad_opt.time_l = costes1[i2][5]
for k in range(visited.index(ciudad_opt) - 1, 0, -1):
if visited[k].index < n_depo:
break
visited[k].time_l = min(visited[k].time_l,
visited[k + 1].time_l -
distancia[visited[k].index][visited[k + 1].index] -
visited[k].service_time)
for k in range(visited.index(ciudad_opt) + 1, len(visited)):
if visited[k].index < n_depo:
break
visited[k].time_e = max(visited[k].time_e,
visited[k - 1].time_e +
distancia[visited[k - 1].index][visited[k].index] +
visited[k - 1].service_time)
return visited, visited_int, rutas_demanda
#Insertion Heuristic que se usa para generar una solución inicial en ACS-VEI
def Insertion_VEI(n_depo, distancia, Q, TWCM, cities, clientes):
rutas_demanda = []
visited = []
visited.append(cities[0])
visited_int = []
visited_int.append(0)
unvisited = cities[n_depo:]
unvisited_int = []
for ciudad in unvisited:
unvisited_int.append(ciudad.index - n_depo + 1)
while unvisited:
costes1 = []
for ciudad in unvisited:
b = 0
ruta_index = 0
for posicion, c in enumerate(visited):
if (posicion != 0):
Resultado, coste1, e_j, l_j = cambio_factible(ciudad, c,
Q, distancia, visited, posicion, mu,
alpha1,
alpha2,
rutas_demanda[ruta_index], TWCM)
if Resultado == True:
b += 1
if b == 1:
coste_min = coste1
pos_min = posicion
ruta_min = ruta_index
e_umin = e_j
d_umin = l_j
if coste1 < coste_min:
coste_min = coste1
pos_min = posicion
ruta_min = ruta_index
e_umin = e_j
d_umin = l_j
if visited[posicion].index < n_depo:
ruta_index += 1
if b != 0:
costes1.append([ciudad, coste_min, pos_min, ruta_min, e_umin,
d_umin])
if (not costes1) & (len(rutas_demanda) < (n_depo - 1)):
visited.append(cities[0])
visited_int.append(0)
rutas_demanda.append(0)
elif not costes1:
return visited, visited_int, rutas_demanda
else:
b = 0
for i in range(len(costes1)):
coste2 = 2 * distancia[0][costes1[i][0].index] -
65
costes1[i][1]
b += 1
if b == 1: # Inicializo ciertas variables
ciudad_opt = costes1[i][0]
coste2_opt = costes1[i][1]
i2 = i
if coste2 > coste2_opt:
ciudad_opt = costes1[i][0]
coste2_opt = costes1[i][1]
i2 = i
visited_int.insert(costes1[i2][2], ciudad_opt.index - n_depo + 1)
visited.insert(costes1[i2][2], ciudad_opt)
rutas_demanda[costes1[i2][3]] += ciudad_opt.demand
indice = ciudad_opt.index - n_depo + 1
indice_cliente = int(np.ceil(indice / 3)) - 1
for i in range(0, 3):
unvisited.remove(cities[clientes[indice_cliente][i]])
unvisited_int.remove(cities[clientes[indice_cliente][i]].index - n_depo + 1)
ciudad_opt.time_e = costes1[i2][4]
ciudad_opt.time_l = costes1[i2][5]
for k in range(visited.index(ciudad_opt) - 1, 0, -1):
if visited[k].index < n_depo:
break
visited[k].time_l = min(visited[k].time_l,
visited[k + 1].time_l -
distancia[visited[k].index][visited[k + 1].index] -
visited[k].service_time)
for k in range(visited.index(ciudad_opt) + 1, len(visited)):
if visited[k].index < n_depo:
break
visited[k].time_e = max(visited[k].time_e,
visited[k - 1].time_e +
distancia[visited[k - 1].index][visited[k].index] +
visited[k - 1].service_time)
return visited, visited_int, rutas_demanda
#Insertion-Heuristic que genera la solución inicial en el MACS-ecVRP
def Insertion_Heuristic_I1_v3(n_depo, distancia, Q, TWCM, cities, clientes):
cur_capacity = 0
current_time = 0
unvisited = cities[n_depo:]
i = cities[0]
unvisited_int = []
corr = -n_depo+1
for ciudad in unvisited:
unvisited_int.append(ciudad.index - n_depo + 1)
# Initialization
visited = []
visited_int = []
rutas_demanda = []
v = 1
visited.append(i)
visited_int.append(i.index)
rutas_demanda.append(0)
#Se generan las primeras rutas
while True:
c_posibles, c_posibles_int = ciudad_disponible(i, current_time,
cur_capacity, Q, unvisited,
distancia, cities[0])
if not c_posibles:
break
j = c_posibles[0]
cij = 0
for point in c_posibles:
if distancia[i.index][point.index] > cij:
cij = distancia[i.index][point.index]
j = point
visited.append(j)
j.time_e = max(j.r_time, visited[visited.index(j) - 1].time_e +
distancia[j.index][visited[visited.index(j) - 1].index] +
visited[visited.index(j) - 1].service_time)
j.time_l = min(j.d_date, visited[visited.index(j)].time_l -
distancia[j.index][visited[visited.index(j)].index] - j.service_time)
for k in range(visited.index(j) - 1, 0, -1):
if visited[k].index < n_depo:
break
visited[k].time_l = min(visited[k].time_l,
visited[k + 1].time_l -
distancia[visited[k].index][visited[k + 1].index] - visited[
k + 1].service_time)
for k in range(visited.index(j) + 1, len(visited)):
if visited[k].index < n_depo:
break
visited[k].time_e = max(visited[k].time_e,
visited[k - 1].time_e +
distancia[visited[k - 1].index][visited[k].index] + visited[
k - 1].service_time)
if j.index < n_depo:
visited_int.append(0)
rutas_demanda[v - 1] = cur_capacity
if v == int(2):
break
rutas_demanda.append(0)
cur_capacity = 0
current_time = 0
v += 1
else:
visited_int.append(j.index + corr)
cur_capacity += j.demand
current_time += max(current_time + distancia[i.index][j.index],
j.r_time) + j.service_time
indice = j.index - n_depo + 1
indice_cliente = int(np.ceil(indice / 3)) - 1
for i in range(0, 3):
unvisited.remove(cities[clientes[indice_cliente][i]])
unvisited_int.remove(cities[clientes[indice_cliente][i]].index - n_depo + 1)
i = j
#Se completan las rutas generadas anteriormente y si es necesario se
añaden otras nuevas
while unvisited:
# Se obtiene la primera lista de costes 1
costes1 = []
for numero, ciudad in enumerate(unvisited):
b = 0
ruta_index = 0
for posicion, c in enumerate(visited):
67
if (posicion != 0):
Resultado, coste1, e_j, l_j = cambio_factible(ciudad, c,
Q, distancia, visited, posicion, mu,
alpha1,
alpha2,
rutas_demanda[ruta_index], TWCM)
if Resultado == True:
b += 1
if b == 1:
coste_min = coste1
pos_min = posicion
ruta_min = ruta_index
e_umin = e_j
d_umin = l_j
if coste1 < coste_min:
coste_min = coste1
pos_min = posicion
ruta_min = ruta_index
e_umin = e_j
d_umin = l_j
if visited[posicion].index == 0:
ruta_index += 1
if b != 0:
costes1.append([ciudad, coste_min, pos_min, ruta_min, e_umin,
d_umin])
if not costes1:
visited.append(cities[0])
visited_int.append(0)
rutas_demanda.append(0)
else:
b = 0
# Se compara la lista de costes 1 según el coste 2
for i in range(len(costes1)):
coste2 = 2 * distancia[0][costes1[i][0].index] -
costes1[i][1]
b += 1
if b == 1:
ciudad_opt = costes1[i][0]
coste2_opt = costes1[i][1]
i2 = i
if coste2 > coste2_opt:
ciudad_opt = costes1[i][0]
coste2_opt = costes1[i][1]
i2 = i
visited_int.insert(costes1[i2][2], ciudad_opt.index + corr)
visited.insert(costes1[i2][2], ciudad_opt)
rutas_demanda[costes1[i2][3]] += ciudad_opt.demand
indice = ciudad_opt.index - n_depo + 1
indice_cliente = int(np.ceil(indice / 3)) - 1
for i in range(0, 3):
unvisited.remove(cities[clientes[indice_cliente][i]])
unvisited_int.remove(cities[clientes[indice_cliente][i]].index - n_depo + 1)
ciudad_opt.time_e = costes1[i2][4]
ciudad_opt.time_l = costes1[i2][5]
for k in range(visited.index(ciudad_opt) - 1, 0, -1):
if visited[k].index < n_depo:
break
visited[k].time_l = min(visited[k].time_l,
visited[k + 1].time_l -
distancia[visited[k].index][visited[k + 1].index] -
visited[
k].service_time)
for k in range(visited.index(ciudad_opt) + 1, len(visited)):
if visited[k].index < n_depo:
break
visited[k].time_e = max(visited[k].time_e,
visited[k - 1].time_e +
distancia[visited[k - 1].index][visited[k].index] +
visited[
k - 1].service_time)
return visited, visited_int, rutas_demanda