1
Equation Chapter 1 Section 1
Trabajo Fin de Grado
En Ingeniería de Tecnologías Industriales,
Intensificación de Organización y Producción
Ciculación Óptima de Vehículos y Localización de
Depósitos en Redes Ferroviarios de Tránsito Rápido
Autor: Olivia Julianna Peña French
Tutor: Jose David Canca Ortiz
Dep. Organización y Gestión de Empresas I
Escuela Técnica Superior de Ingeniería
Universidad de Sevilla
Sevilla, 2017
3
Trabajo Fin de Grado
En Ingeniería de Tecnologías Industriales
Intensificación Organización y Producción
Ciculación Óptima de Vehículos y Localización de
Depósitos en Redes Ferroviarios de Tránsito
Rápido
Autor:
Olivia Julianna Peña French
Tutor:
Jose David Canca Ortiz
Profesor titular
Dep. Organización y Gestión de Empresas I
Escuela Técnica Superior de Ingeniería
Universidad de Sevilla
Sevilla, 2017
7
Resumen
Hoy en día los avances tecnológicos ocurren cada vez más rápido y a la vez, los recursos disponibles para
llevarlos a cabo están más limitados. Por esto, en el ámbito que nos compete, el de la ingeniería, es necesario
desarrollar herramientas potentes de búsqueda que encuentren buenas soluciones a los problemas que se
presentan, enfocados a la reducción en el consumo de recursos.
El problema que presenta la planificación y organización de los recursos del sector de transporte público
ferroviario es de alta complejidad. Para encontrar una solución eficiente, se requieren técnicas potentes y
robustas. En este documento se trata de seguir con el trabajo ya comenzado por A. Tellez [1] y encontrar
una herramienta que de solución a la última parte del problema de planificación del material rodante en una
red ferroviaria de transporte metropolitano: optimizar la circulación del material rodante y localizar donde
construir depósitos para minimizar los costes de funcionamiento y de inversión.
Esto se realiza desarrollando tanto un modelo matemático resuelto con el programa Gurobi Optimizer, como
un algortimo metaheurístico programado en Python 3.5, y comparando su eficiencia y eficacia resolviendo
sistemas de distinta complejidad y dimensión.
9
Abstract
In our current world technologicl advances are being developed at a constantly faster rate while the resources
necessary for them are becoming more and more limited. Because of this, powerful tools need to be
developed to find good solutions to different problemas in the engineering field, reducing the consumption
of resources within any type of system.
The problem presented by the planning and organization of the resources used by the public rail transport
sector is highly complex. To find an efficient solution, a powerful tool is needed. This document has intended
to continue the work begun by A. Tellez [1], and find a proper tool that solves the last part of the rolling
stock planning problem: optimizing the circulation of trains and the depot location policy that minimize the
costs of the railway system.
This is achieved by developing both a mathematical model, solved with the solver Gurobi Optimizer,
metaheuristic algorithm, programmed in Python 3.5, to later compare the effectiveness and efficiency of said
methods in resolving systems of different complexity and dimension.
Índice
Resumen .................................................................................................................................................. 7
Abstract ................................................................................................................................................... 9
Índice ..................................................................................................................................................... 10
Índice de Tablas ..................................................................................................................................... 13
Índice de Figuras .................................................................................................................................... 15
1 Objetivos y alcance ......................................................................................................................... 17
2 Introducción a la planificación Ferroviaria ..................................................................................... 18 2.1 Elementos de un Sistema ferroviario: ................................................................................................ 18
2.1.1 Infraestructura ............................................................................................................................. 18 2.1.2 Material Rodante ........................................................................................................................ 18 2.1.3 Depósitos ..................................................................................................................................... 19
2.2 Planificación de un sistema ferroviario .............................................................................................. 19
3 Descripción del problema concreto que se aborda ......................................................................... 21 3.1 Información inicial del problema ........................................................................................................ 21 3.2 Defnición de solución .......................................................................................................................... 23
4 Modelado ....................................................................................................................................... 24 4.1 Notación del Modelo ........................................................................................................................... 24
4.1.1 Conjunto de Datos de Problema ................................................................................................ 24 4.1.2 Variables del modelo .................................................................................................................. 25
4.2 Modelo Matemático ........................................................................................................................... 27 4.2.1 Restricciones del modelo ............................................................................................................ 27 4.2.2 Función Objetivo ......................................................................................................................... 31
5 Heurística propuesta: Algoritmo Genético ..................................................................................... 32 5.1 Algoritmo genético ajustado a problema .......................................................................................... 33
5.1.1 Datos de entrada de Solución Genética .................................................................................... 34 5.2 Codificación de Solución ..................................................................................................................... 37 5.3 Algoritmo Genético ajustado ............................................................................................................. 42
6 Ejemplos ......................................................................................................................................... 52 6.1 Ejemplo 1 ............................................................................................................................................. 52
6.1.1 Aplicación de Modelo Matemático: .......................................................................................... 53 6.1.2 Aplicación de Algoritmo Genético: ............................................................................................ 55
6.2 Ejemplo 2 ............................................................................................................................................. 57 6.2.1 Aplicación de Modelo Matemático: .......................................................................................... 59 6.2.2 Aplicación de Algoritmo Genético: ............................................................................................ 61
6.3 Red de Cercanías de Sevilla ................................................................................................................. 64 6.3.1 Aplicación del Modelo Matemático ........................................................................................... 66 6.3.2 Aplicación de Algoritmo Genético ............................................................................................. 66
11
7 Experimentos con parámetros del sistema .................................................................................... 70 7.1 Coste de construcción de Depósito .................................................................................................... 70 7.2 Tamaño de Población ......................................................................................................................... 71
8 Conclusión ...................................................................................................................................... 73
9 Anexos ........................................................................................................................................... 75 9.1 Anexo I .................................................................................................................................................. 75 9.2 Anexo II ................................................................................................................................................. 96 9.3 Anexo III.............................................................................................................................................. 136 9.4 Anexo IV ............................................................................................................................................. 138 9.5 Anexo V .............................................................................................................................................. 140
10 Bibliografía ...................................................................................................................................... 141
13
ÍNDICE DE TABLAS
Tabla 1. Horarios establecidos para la línea Santa Justa-Cartuja de la Red de Cercanías de Sevilla. 19
Tabla 2. Distancias entre estaciones de dos líneas de un mismo sistema 34
Tabla 3. Combinaciones de Individuos Reproductoes 45
Tabla 4. Combinación de Individuos Reproductores. 46
Tabla 5. Distancias entre Estaciones del Sistema del Ejemplo 1. 52
Tabla 6. Información de Rutas del Ejemplo 2. 52
Tabla 7. Resultados de Modelo Matemático Ejemplo 1. 54
Tabla 8. Resultados de Algoritmo del Ejemplo 1. 56
Tabla 9. Distancias entre Estaciones del Sistema del Ejemplo 2. 57
Tabla 10. Información de Rutas del Ejemplo 2. 58
Tabla 11. Representación Gráfica de Rutas del Sistema del Ejemplo 2. 58
Tabla 12. Resultados del Modelo Matemático del Ejemplo 2. 60
Tabla 13. Resultados del Algoritmo del Ejemplo 2. 63
Tabla 14. Distancias entre Estaciones de la Red de Cercanías de Sevilla. 66
Tabla 15. Resultados de Costes de Red de Cercanías de Sevilla 67
Tabla 16. Kilómetros recorridos en una semana por los trenes de la Red de Cercanías de Sevilla. 68
Tabla 17. Asignación de Rutas de la Red de Cercanías de Sevilla. 69
15
ÍNDICE DE FIGURAS
Figura 1. Representación gráfica de un ejemplo de ruta 22
Figura 2. Grafo de solución de un sistema genérico de una línea. 26
Figura 3. Gráfica de valor de función objetivo de un problema ejemplo para 33
Figura 4. Representación Gráfica de un Ejemplo de Ruta 35
Figura 5. Grafo de Rutas de Sistema Ejemplo. 38
Figura 6. Asignación de Rutas del Sistema Ejemplo 39
Figura 7. Ejemplo de solución mostrando el uso de depósitos. 40
Figura 8. Representación Gráfica Combinaión 1. 47
Figura 9. Representación Gráfica Combinación 2. 47
Figura 10. Representación Gráfica Combinación 3. 48
Figura 11. . Representación Gráfica Combinación 4. 48
Figura 12.. Representación Gráfica Combinación 5. 48
Figura 13. . Representación Gráfica Combinación 6. 49
Figura 14. Diagrama de Flujo del Algoritmo Diseñado 51
Figura 15. Representación Gráfica de la Red Ferroviaria del Ejemplo 1. 52
Figura 16. Representación gráfica de rutas de la red ferroviaria del Ejemplo 1. 53
Figura 17. Gráfica de Valores Función Objetivo en cada nodo encontrado por el Modelo Matemático 53
Figura 18. Asignación de Rutas de la Solución del Modelo Matemático del Ejemplo 1. 54
Figura 19. Gráfica de Valores de función obetivo de cada solución ideal de cada generación creada por el algoritmo
genético. 55
Figura 20. Asignación de Rutas de la Solución del Algoritmo del Ejemplo 1. 56
Figura 21. Representación Gréfia de la Red Ferroviaria del Ejemplo 2. 57
Figura 22. Gráfica de Valores Función Objetivo en cada nodo encontrado por el Modelo Matemático 59
Figura 23. Asignación de Rutas del Sistema del Ejemplo 2. 61
Figura 24. Gráfica de Valores de función obetivo de cada solución ideal de cada generación creada por el algoritmo
genético 61
Figura 25. Asignación de Rutas del Algorimo del Ejemplo 2. 63
Figura 26. Representación Gráfica de la Red de Cercanías de Sevilla 64
Figura 27. Red de Cercanías de Sevilla Simplificada 65
Figura 28. Gráfica de Valores de función obetivo de cada solución ideal de cada generación creada por el algoritmo
genético para la Red de Cercanías de Sevilla. 67
Figura 29. Nº de Depósitos según Coste de construcción 70
Figura 30. Evolución de Función Objetivo con el Tamaño de Población (Ejemplo 1 & 2) 71
Figura 31. Evolución de Función Objetivo con el Tamaño de Población (Red de Cercanías de Sevilla) 71
17
1 OBJETIVOS Y ALCANCE
Debido a la continua disminución de recursos materiales y las restricciones cada vez más estrictas sobre el
consumo convencional de fuentes de energía, la demanda de sistemas más eficientes de bajo coste y consumo
y el diseño de nuevas infraestructuras se ha vuelto un objetivo crucial del trabajo de los ingenieros de hoy
en día [3]. Encontrar estas soluciones, por tanto, requiere técnicas robustas de búsqueda de soluciones
óptimas para problemas, usualemente no lineales, de naturaleza compleja y de dimensiones muy elevadas.
Estos sistemas presentan problemas de difícil solución, por tanto, se debe de estudiar métodos alternativos
de búsqueda de soluciones, tanto matemáticamente exáctos como aproximados.
El problema objeto de este proyecto surge dentro del proceso de diseño de una red ferroviaria genérica. La
planificación ferroviaria suele plantearse como una secuenciación de problemas que abarca el diseño de la
red, la planificación de las líneas, el diseño de horarios en función de la demanda, la planificación de material
rodante y el diseño de turnos y asignación de personal. Este proyecto se centra en parte del problema de
planificación de material rodante (conocido como Rolling Stock Planning). De forma específica, se aborda
un sub-problema de diseño de circuitos (sucesión temporal de servicios. Se trata de un problema previamente
estudiado en Téllez [1], en el que se diseña un modelo matemático con el fin de encontrar solución al
problema de gestión de material rodante y localización de depósitos en redes de ferrocarril de tránsito rápido.
En el último trabajo se plantearon varios procesos de resolución. Específicamente, una de las técnicas
utilizadas consistía en la resolución secuencial de varios sub-problemas, lo que entonces se denominó
“resolución por partes”. Este proceso se ve definido por tres fases; la primera consiste en obtener el número
mínimo de trenes necesarios para la prestación de todos los servicios a lo largo del horizonte temporal. En
segundo lugar se obtenían soluciones locales (agrupación de servicios en secuencias) para cada día y línea a
fin de satisfacer el horario impuesto previamente. La última fase consiste en asignar trenes específicos a las
rutas previamente definidas, encadenar rutas entre días sucesivos y determinar la mejor ubicación de
depósitos con la finalidad de reducir al máximo los viajes en vacío (consecuencia de los desplazamientos
necesarios para la pernoctación de los trenes) minimizando el coste total de operación del sistema ferroviario.
Los modelos propuestos por Téllez [1] fueron programados en GAMS y resueltos usando IBM ILOG
CPLEX v12.5 (2014).
El objeto de este proyecto consiste en proponer una metodología de resolución eficiente de la tercera fase
del problema previamente comentado, esto es, el diseño de circuitos para cada uno de los trenes a lo largo
del horizonte de planificación y la determinación óptima de la localización y el número de depósitos que
consigue minimizar el coste total de operación. La resolución por partes, de forma exacta, del problema de
Rolling Stock y la localización de depósitos consigue reducir sustancialmente el tiempo de computación
necesario para completar la resolución del problema. No obstante, el 95% del tiempo empleado para la
resolución exacta del problema corresponde a la tercera fase, debido al carácter NP-duro de este problema.
Como consecuencia, se hace necesario abordar esta fase mediante algún procedimiento meta-heurístico que
facilite un método eficiente de resolución.
Por un lado se creará un modelo matemático exacto, programado en Python 3.5 y resuelto mediante el solver
GUROBI. Por otro, se construirá un algoritmo meta-heurístico específico, basado en los Algoritmos
Genéticos (GA), que permita resolver instancias de gran tamaño de forma eficiente. Finalmente, se
compararán estas dos metodologías en cuanto a su calidad de solución, tiempo de computación y uso de
recursos.
2 INTRODUCCIÓN A LA PLANIFICACIÓN
FERROVIARIA
Antes de comenzar con la definición del problema a resolver, y las metodologías propuestas para su
resolución, se hace necesaria una pequeña introducción sobre las fases del diseño y planificación de material
rodante de una red ferroviaria genérica.
Para la aplicación de las metodologías de resolución de este trabajo se han considerado los sistemas
ferroviarios existentes dentro del país europeo de España. Por tanto, los sistemas considerados serán aquellas
que siguen la legislación consolidada recogida en la Ley 38/2015, de 29 de septiembre, del sector ferroviario
[2].
2.1 Elementos de un Sistema ferroviario:
Los elementos de un sistema ferroviario se pueden dividir en infraestructura, material rodante y depósitos.
2.1.1 Infraestructura
Se entenderá por infraestructura ferroviaria la totalidad de los elementos que formen parte de las vías
principales y de los de servicios y los ramales de desviación para particulares, con excepción de las vías
situadas dentro de los talleres de reparación de material rodante y de los depósitos o garajes de máquinas de
tracción.
Entre dichos elementos se encuentran los terrenos, las estaciones de transporte de viajeros, las terminales de
transporte de mercancías, las obras civiles, los pasos a nivel, los caminos de servicio, las instalaciones
vinculadas a la seguridad, a las telecomunicaciones, a la electrificación, a la señalización de las líneas, al
alumbrado, al almacenamiento de combustible necesario para la tracción y a la transformación y el transporte
de la energía eléctrica, sus edificios anexos, los centros de control de tráfico y cualesquiera otros que
reglamentariamente se determinen [2].
En el contexto de este proyecto, la infraestructura será entendida como las líneas que incluye el sistema
ferroviario que se estudie, y las estaciones límite de cada línea. Las estaciones límite de una línea son las
estaciones que están en los límites físicos o extremos de las líneas que actúan como estaciones de término.
Las estaciones intermedias, aunque existentes, sólo se considerarán si representan puntos operativos de
intersección de diferentes líneas del sistema.
2.1.2 Material Rodante
Dentro de todo sistema ferroviario, existe un conjunto de equipos y vehículos que se mueve a lo largo de las
vías de la infraestructura de dicho sistema. Este conjunto se entiende como material rodante.
Este material rodante está formado por trenes o unidades de trenes. Estas unidades pueden estar formadas
por:
- Locomotoras. Se refiere a equipos del material rodante que constituyen el elemento motor de un tren, o
unidad de tren.
- Vagones. Se refiere a los elementos de carga del material rodante. Estos elementos pueden tener distintas
estructuras, según la naturaleza de la carga (pasajeros, mercancías, etc.).
- Unidades de trenes. Se entienden con conjuntos de locomotoras y vagones.
19
2.1.3 Depósitos
Un depósito, en el contexto de sistemas ferroviarios, es un lugar donde se almacena material rodante que no
está en uso y para realizar trabajos de reparación y mantenimiento sobre dicho material.
El coste de construcción de un depósito tiende a ser considerablemente elevado, por lo que, como norma
general, se trata de minimizar el número de depósitos construidos en un mismo sistema ferroviario.
2.2 Planificación de un sistema ferroviario
Tras haber definido todo los elementos físicos que forman un sistema ferroviario, se pasará a considerar la
parte de planificación logística del sistema.
Esta planificación se realiza en varias fases. La primera fase es la selección de los horarios. Consiste en
definir las horas a las que se desea que llegue y salga cada servicio. En este punto, no se sabe cuántos trenes
se requieren, ni se conocen las rutas que se deben se realizar. Simplemente se decidirá las horas a las que se
desea que uno o varios trenes, aún no definidos, lleguen a y salgan de cada una de las estaciones del sistema
ferroviario. Este proceso se realiza estudiando la demanda de transporte de la zona donde se desea instalar o
alterar el sistema ferroviario. Este estudio se debe de realizar con herramientas de forecasting, capturando
datos de las demandas existentes de la zona, y observando las tendencias de la zona. Por ejemplo, si se sabe
que históricamente, habrá días con más demanda de pasajeros que en otros, se puede suponer que la demanda
va a tener una naturaleza estacional, y se tendrá que elegir la herramienta adecuada para proyectarlo
Un ejemplo de estos horarios son los siguientes, obtenidos del sistema de cercanías de Sevilla:
Tabla 1. Horarios establecidos para la línea Santa Justa-Cartuja de la Red de Cercanías de Sevilla.
En el contexto de este proyecto, se considera que este estudio ya se ha realizado, y que los horarios ya han
sido definidos previamente.
Una vez definidos los horarios, se puede pasar a la siguiente fase de la planificación. Esta fase se puede
denominar “cálculo de rutas”.
Una ruta se entiende como un conjunto de desplazamientos (servicios) de un único tren a lo largo de un
mismo día. En el contexto de redes de cercanías, una ruta está limitada a una misma línea, siendo imposible
que una ruta incluya más de una línea. Esto quiere decir, que si un tren realizase la ruta ‘A’, que existe en la
línea ‘X’, este tren no dejará la línea X hasta que realice todos los desplazamientos que incluye la ruta ‘A’.
Cada ruta está definida y diferenciada por los siguientes factores:
- Depósito de inicio: Es el depósito donde comienza el primer desplazamiento del día, que en el
contexto de este proyecto, será uno de las dos estaciones límites de la línea en la que existe la ruta.
- Depósito de fin: Es el depósito donde termina el último desplazamiento del día, que será, de nuevo,
uno de las dos estaciones límite de la línea en la que existe la ruta.
- Recorrido: sucsión de servicios en el interior de la línea.
El problema de cálculo de rutas de modeló y resolvió en Téllez [1], utilizando un modelo matemático de
programación enterea que minimiza para realizar todos los servicios de una línea y por tanto determinando
el número necesario de rutas.
Tras esta fase, se llega a la última, que se puede entender como la asignación de trenes a rutas, y localización
de depósitos. Este es el problema que se desea abordar en este trabajo, y que a continuación se expondrá.
21
3 DESCRIPCIÓN DEL PROBLEMA CONCRETO
QUE SE ABORDA
El problema que se plantea consiste en la asignación de trenes específicos a rutas (sucesión de servicios en
las diferentes líneas) a lo largo de cierto horizonte de planificación, usualmente una semana, así como en la
determinación del número y ubicación de los depósitos con el fin de conseguir, por un lado, la minimización
de costes operativos y por otro, el equilibrio del número de kilómetros semanales recorridos por los trenes
de manera que se consiga un desgaste similar en todas las unidades. Este último objetivo permitirá con
posterioridad diseñar un plan rotatorio de mantenimiento de los vehículos, si así se deseara.
En este problema se busca una solución óptima que minimice los costes de operación el sistema ferroviario.
Estos costes se pueden resumir en:
- El coste de construir depósitos
- El coste de que haya trenes viajando sin carga, es decir, en vacío. Estos viajes en vacío son aquellos
movimientos entre los depósitos donde los trenes pernoctan y las estaciones de inicio y fin de la ruta que
realiza cada tren en cada día.
- El coste del desgaste del material rodante. Es decir, el coste del uso de los trenes.
Para minimizar el coste de degaste del material rodante, se buscará un equilibrio entre los kilómetros totales
recorridos por cada tren del sistema. En otras palabras, se buscará que todos los trenes recorran los mismos
kilómetros. Esto permitirá que el material rodante se desgaste a, relativamente, la misma velocidad, y por
tanto, minimizará el desgaste general de todos los equipos, facilitando al mismo tiempo el desarrollo de
políticas de mantenimiento.
Los costes de viajar en vacío y de construcción de depósitos se minimizan determinando el número y la
localización de depósitos.
Este problema se puede definir, en resumen, como la búsqueda de la configuración de la asignación de
rutas a trenes o unidades de trenes y de la disposición y número de depósitos que minimice los costes
incurridos en el sistema ferroviario estudiado.
3.1 Información inicial del problema
Se dispone de los siguientes datos iniciales:
El número de líneas de tren
Las distancias entre estaciones inicial y final de todas las líneas.
Las rutas por día y por línea que se realizan. Estas rutas están definidas por:
Día de realización de la ruta
Línea donde se realiza la ruta
Estación de inicio de la ruta
Estación de finalización de la ruta
Distancia total recorrida por un tren que realizase la ruta
Los elementos básicos del problema son:
o Un conjunto de líneas. Este conjunto representa todas las líneas existentes en el sistema
ferroviario que se esté tratando de planificar, por donde el material rodante podrá moverse.
Para el contexto del problema, se obviarán todas las estaciones intermedias que pueda tener
una línea, y sólo se considerará las estaciones de los extremos. Estas estaciones las
nombraremos Estación 1 y Estación 2, en orden arbitrario. El material rodante podrá
moverse por la línea en dos sentidos, desde la estación 1 hacia la estación 2, o viceversa.
o Un conjunto de días. Este conjunto representa todos los días individuales que se deseen
considerar.
Se asume que el conjunto de días se repetirá de forma consecutiva a lo largo del horizonte
temporal que se quiera estudiar. Por ejemplo, si se define un conjunto de siete días y un
horizonte de 30 días, estos siete días se repetirían de forma consecutiva a lo largo de los 30
días del horizonte temporal.
o Un conjunto de trenes. Este conjunto representa el material rodante que se encuentra en
movimiento en el sistema.
Se obviará la longitud y tipo de tren, y se considerará todo el material rodante como
homogéneo.
o Un conjunto de rutas por día y por línea. Una ruta representa un conjunto de servicios,
que satisface un horario, ya establecido.
Se puede ver una representación gráfica de una ruta ejemplo a continuación:
Figura 1. Representación gráfica de un ejemplo de ruta
En este ejemplo, la ruta mostrada comienza en la estación 2 y termina en la estación 1 dentro
de la línea en la que existe. Además, se puede ver que la ruta incluye dos movimientos de
ida y vuelta antes de concluir la ruta en la estación 1. Estos movimientos se definen en la
primera fase de la planificación de material rodante.
En el problema que se aborda en este documento tomará como ya definidas estas rutas.
Cada ruta se caracteriza por su estación de inicio, su estación de finalización y los
kilómetros que recorrería el material rodante que estuviese asignada a ella.
Estos conjuntos de rutas se organizan por día y por línea, es decir, habrá un conjunto de
rutas para cada día y cada línea.
23
3.2 Defnición de solución
La solución del problema consistirá de varios resultados que definirán la planificación final del material
rodante, y la disposición de los depósitos.
1. Se obtendrá el número de depósitos que se deben de construir, además del lugar dentro
de la infraestructura ferroviaria en que se debe construir.
2. Se obtendrá la asignación exacta de cada ruta en cada día del conjunto que se considera
a cada tren. Es decir, para cada tren, se tendrá la ruta que realiza cada día. Además, se
sabrá qué día no realiza ninguna ruta.
3. Se obtendrá la lista de depósitos usados por cada tren cada día. En otras palabras, se
sabrá, para cada tren, desde qué depósito sale al inicio de cada día y a que depósito
entra al final de cada día.
4. Se tendrá el número de kilómetros que recorre cada tren sin carga, que corresponde a
los movimientos desde y hacia depósitos para pernoctar durante el horizonte de
planificación.
5. Se obtendrá el número de kilómetros recorridos por los trenes que constituyen el
material rodante del sistema ferroviario durante los días que se consideran en el
conjunto D.
4 MODELADO
El problema de asignación de trenes a rutas, y de localización de depósitos se presenta como un problema
complejo. Esto se debe a varios factores, como el tamaño del problema, que aumenta de forma exponencial
con las dimensiones del sistema ferroviario que se desea estudiar, o como el hecho que casi todas las
variables del problema son enteras.
Para resolver este problema, primero se ha tratado de modelar usando una serie de restricciones que definan
correctamente qué soluciones son válidas, y una función objetivo que minimice los gastos, costes y desgaste
al sistema ferroviario que se desea estudiar.
La meta de este modelo es que encuentre la solución que minimice:
- Los costes de infraestructura, que serán aquellas relacionadas con la construcción y mantenimiento de
depósitos en el sistema.
- Los gastos semanales del sistema, que estarán relacionadas con los kilómetros recorridos en vacío, es
decir, sin pasajeros, de los trenes a lo largo del horizonte temporal que se define.
- El desgaste del material rodante e infraestructuras, que estará relacionada con el total kilómetros
recorridos por los trenes, y el equilibrio de distancias totales recorridas entre trenes.
El modelo se ha formulado para ser resuelto por el programa Gurobi, que usa Python 3.5 como idioma de
programación.
4.1 Notación del Modelo
Antes de definir las restricciones y la función objetivo, es necesario posentar la notación que se usa en el
entorno del modelo. Esta notación expondrá, tanto los conjuntos de datos que determinan el problema, como
las variables que se emplean para resolverlo.
4.1.1 Conjunto de Datos de Problema
Los datos del sistema son aquellos que definen el problema que se va a abordar. El volumen de datos
dependerá de las dimensiones del problema, i.e., sistema ferroviario, que se quiere abordar. Por tanto, el
número de datos está en función de las dimensiones del problema. En el modelo se definen los siguientes
conjuntos:
- Conjunto L: representa el conjunto de Líneas del problema. Dentro del modelo, se refiere elementos
de este conjunto utilizando los índices ‘i’, ’l’.
- Conjunto D: representa el conjunto de días que forman el horizonte de planificación del problema,
es decir, el número de días que se consideran diferenciables estre sí. La semana se define como el
conjunto de días que se repite a lo largo del horizonte temporal. Se refiere a los elementos de este
conjunto con su índice ‘d’.
- Conjunto T: representa el conjunto de trenes que forman el material rodante del sistema. Se
considera que todos los trenes son idénticos, y por tanto, pueden realizar cualquier ruta de cualquier
línea del conjunto L, en cualquier día del conjunto D. Su índice será ‘t’.
- Conjunto Rdl: representa el conjunto de rutas del día ‘d’ de la línea ‘l’ del problema. Habrá un
conjunto para cada día del conjunto D y para cada línea del conjunto L. O sea, cada línea tiene un
conjunto de rutas que se deben de realizar cada día. Estas pueden variar para cada día y línea. En un
25
día, una línea puede tener 5 rutas, y en otro día la misma línea puede no tener rutas. Los conjuntos
de rutas para cada día y línea del sistema son independientes entre sí. Se hace uso del índice ‘rdl’
para referirse a estos conjuntos.
Además de estos conjuntos de datos, se cuenta con una serie de datos adicionales que terminan de de definir
el sistema ferroviario:
- DEle-ic: representa la distancia entre la estación ‘e’ de la línea ‘l’ y la estación ‘c’ de la línea ‘i’. Los
índices ‘e’ y ‘c’ se referirán a las estaciones de la líneas, y podrán tomar valor [1, 2].
- KMd.l.r: representa los kilómetros asociados a la ruta ‘r’, de la línea ‘l’ y del día ‘d’. Este dato
representa la suma de distancias recorridas en la ruta ‘r’, es decir, los kilómetros transitados para
cubrir los servicios horarios que se han calculado satisfacer por la ruta ‘r’.
- INd.l.r: representa la estación de inicio de la ruta ‘r’, de la línea ‘l’ y del día ‘d’. Esta estación es de la
que parte la ruta, es decir, la primera estación donde el tren que realiza la ruta ‘r’ recoge pasajeros
en el día. Si este tren realiza traslados antes de llegar a esta estación en el día ’d’, serán kilómetros
realizados en vacío, sin pasajeros. INd.l.r puede ser tomar valor 1 o 2, dependiendo de la estación en
la que empieza la ruta.
- FNd.l.r: representa la estación de finaliza de la ruta ‘r’, de la línea ‘l’ y del día ‘d’. Esta estación es la
última estacón donde el tren que realiza la ruta ‘r’ deja a pasajeros en el día. Tras esta estación, si el
tren realiza más traslados en el día ‘d’, será en vacío. Al igual que la de inicio, puede tomar valor 1
o 2, dependiendo de la estación en la que termina la ruta.
- YRS: duración, en años, del horizonte temporal. Este tiempo representa el horizonte que se desea
observar para el estudio de costes, gastos y desgaste de material e infraestructuras del sistema que
se está resolviendo.
- N_T: número mínimo de trenes necesarios para poder satisfacer todas las rutas. Este dato se obtiene
a partir de las rutas realizadas cada día en todas las líneas. El mayor número de rutas realizadas en
un día determina el número necesario de trenes para poder realizar todas las rutas del sistema.
4.1.2 Variables del modelo
El modelo hace uso de diversas variables, cuyos valores en la solución dan respuesta a la información
desconocida que se desea encontrar. Se hace uso de variables binarias, enteras y continuas. Estas variables
se definen a continuación:
- XRt.d.l.r: variable binaria. Se activará si el tren ‘t’ es asignado a la ruta ‘r’ de la línea ‘l’ del día ‘d’.
Esta variable es aquella que define la asignación de los trenes a las rutas. Si su valor es 1, entonces
el tren ‘t’ realiza la ruta ‘r’ de la línea ‘l’ del día ‘d’; si su valor fuese 0, es decir, no se activase, el
tren no realiza esa ruta en esa línea ese día.
- XVt.d.le-ic: variable binaria. Esta variable se ha definido para aquellos trenes que no realizan ninguna
ruta. En otros términos, representa un tránsito en vacío de un tren que no realiza ruta. Esta variable
sirve para conectar el final del día ‘d-1’ donde el tren ‘t’ sí realizó una ruta, con el fin del día ‘d’,
donde no realizó ninguna ruta. Por tanto, se activará, es decir, valdrá 1, si el tren ‘t’ no realiza una
ruta el día ‘d’, y se mueve desde la estación ‘e’ de la línea ‘l’ hasta la estación ‘c’ de la línea ‘i’. Se
define de forma resumida como una ruta vacía.
- Xdit.d.le-ic: variable binaria. Estas variables representan los traslados desde un depósito hasta la
estación de inicio de la ruta que realiza el tren ‘t’ en el día ‘d’. Conectan los depósitos en los que
pernoctaron los trenes en el día anterior, hasta el comienzo de las rutas del día ‘d’. Se activará si el
tren ‘t’ sale de un depósito en la estación ‘e’ de la línea ‘l’ hacia el inicio de su ruta en la estación
‘c’ de la línea ‘i’ al comienzo del día ‘d’.
- Xdft.d.le-ic: variable binaria. Estas variables representan los traslados desde la estación de fin de la
ruta que realiza el tren ‘t’ en el día ‘d’ hasta un depósito. Sirven de conexión entre las rutas y los
depósitos en que pernoctarán los trenes al final del día ‘d’. Se activará si el tren ‘t’ entra al depósito
en la estación ‘c’ de la línea ‘i’ desde el final de su ruta en la estación ‘e’ de la línea ‘l’ al final del
día ‘d’.
Si se definiese el problema como un grafo con arcos y nodos, las estaciones y depósitos representarían los
nodos del sistema, mientras que las variables binarias anteriores serían los arcos que las unen. Cada variable
representa un desplazamiento que hipotéticamente podría realizar un de tren. Cuando se active una de estas
variables binarias, entonces en la solución, ese traslado hipotético se realiza en la realidad.
Para clarificar el significado de cada una de las variables binarias anteriores, a continuación se hace uso de
una representación de grafo, que muestra, a modo de ejemplo, una solución:
Figura 2. Grafo de solución de un sistema genérico de una línea.
En el ejemplo se ha propuesto un problema de dos días y una sola línea. En el día 1 existen dos
rutas, una que comienza en la estación 1 y termina en la estación 2, y otra que comienza y termina
en la estación 2. En el día 2 sólo existe una ruta, una que comienza en la estación 1 y termina en la
estación 2.
Las variables XR indican que el tren ‘1’ realiza la ruta ‘1’ de la línea ‘1’ del día ‘1’ y la ruta ‘1’ de
la línea ‘1’ del día ‘2’ y que el tren ‘2’ realiza la ruta ‘2’ de la línea ‘1’ del día ‘1’.
𝑋𝑅1111 & 𝑋𝑅1211
La variable XV indica que el tren ‘2’ en el día ‘2’ realiza una ruta vacía desde la estación ‘2’ de la
línea ‘1’ hasta la estación ‘2’ de la línea ‘1’
𝑋𝑉22.12−12
Las variables Xdi indican que el tren ‘1’ en comienzo el día ‘1’ parte del depósito localizado en la
estación ‘2’ de la línea ‘1’ hacia el inicio de la ruta que realiza tal día.
𝑋𝑑𝑖11.12−11
Esto es análogo para los demás días y trenes.
Las variables Xdf indican que el tren ‘1’ en el final el día ‘1’ entra al depósito localizado en la
estación ‘2’ de la línea ‘1’ desde el final de la ruta que realiza tal día (Xdf1.1.12-12). Esto es análogo
para los demás días y trenes.
27
𝑋𝑑𝑓11.12−12
Además de estas variables binarias, se hace uso de variables adicionales, que terminande definir la solución
del problema que plantea el modelo:
- Ale: variable binaria. Esta variable define si una estación de una línea es también un depósito a usar
por todos los trenes. Si se activa, es decir, su valor es 1, la estación ‘e’ de la línea ‘l’ es también un
depósito del sistema ferroviario.
- RVt: variable continua. Representa los kilómetros recorridos en vacío que realiza en total el tren ‘t’
durante los días del conjunto D. Estos kilómetros son aquellos que los trenes recorren desde
depósitos hasta sus estaciones de inicio de cada día, desde sus estaciones de fin hasta los depósitos
al final de cada día, y en las rutas vacías que hacen los días que no realizan rutas con pasajeros.
- Rect: variable continua. Representa los kilómetros totales recorridos por el tren ‘t’ durante los días
del conjunto D. Es la suma de toda la distancia recorrida en todas las rutas realizadas por un tren ‘t’
y la distancia recorrida en vacío a lo largo de los días del conjunto D.
- C_Total: variable continua. Representa el coste total del sistema, teniendo en cuenta tanto los
kilómetros recorridos en vacío a lo largo de todo el horizonte temporal, como el coste de inversión
para construir los depósitos. Esta variable se calcula con los valores de otras variables, y sólo es
necesario para simplificar la expresión de la función objetivo.
- C_Equ: variable continua. Representa el coeficiente de equilibrio entre las distancias recorridas por
el material rodante. Cuanto menor sea el coeficiente de equilibrio, más equilibradas estarán las
distancias entre sí. Al igual que la variable C_Total, esta variable se calcula a partir de los valores
de otras variables, y sólo sirve para simplificar la expresión de la función objetivo.
4.2 Modelo Matemático
El modelo está formado por una función objetivo y un conjunto de restricciones asociadas al conjunto de
días que se repetirá a lo largo del horizonte temporal que se considere.
El código Python 3.5 usado para la descripción y resolución del problema en el ANEXO I.
4.2.1 Restricciones del modelo
1. En apartados anteriores, se han descrito las rutas como la solución del problema de satisfacer los
servicios horarios definidos previamente. Esto implica que, para satisfacer estos servicios, será
necesario que todas las rutas definidas para el sistema que se desea resolver se realicen. Además,
también se debe de asegurar que a cada ruta esté asignado un sólo tren, ya que no tendría sentido
que dos trenes realizasen la misma ruta al mismo tiempo. Las siguientes restricciones aseguran que
todas las rutas son asignadas a un tren, y que cada ruta esté asignada a un solo tren:
∑ 𝑋𝑅𝑡.𝑑.𝑙.𝑟 = 1 ∀
𝑡∈𝑇
𝑟 ∈ 𝑅𝑑𝑙 ∀𝑙 ∈ 𝐿 ∀𝑑 ∈ 𝐷
2. Todos los trenes deben salir de un depósito al inicio de un día y deben ir a un depósito al final de
ese día. Por lo cual, es necesario que se realice una conexión correcta entre el depósito de salida del
tren al principio del día con la estación de inicio de la ruta que le sea asignada. Igualmente ocurre
con la estación de fin y el depósito donde pernocta el tren. Las siguientes restricciones aseguran que,
si un tren es asignado a una ruta r, las correspondientes variables de depósitos son también
asignadas/activadas:
a. Estas restricciones garantizan la correcta conexión entre depósito y estación de inicio.
Aseguran que si un tren ‘t’ realiza la ruta ‘r’ de la línea ‘l’ que comienza en la estación
‘INd.l.r’ en el día ‘d’, se activa la variable de depósito de inicio de día adecuado y que no se
active si ese tren ‘t’ no realiza tal ruta ‘r’:
∑ ∑ 𝑋𝑑𝑖𝑡.𝑑.𝑙𝑒−𝑖𝑐
2
𝑐=1
≥ 𝑋𝑅𝑡.𝑑.𝑙.𝑟 ∀
𝑖∈𝐿
𝑟 ∈ 𝑅𝑑𝑙 ∀𝑙 ∈ 𝐿 ∀𝑑 ∈ 𝐷 ∶ 𝑒 = 𝐼𝑁𝑑𝑙𝑟
b. Analógicamente, estas restricciones garantizan la correcta conexión entre la estación de
final del día con el depósito, restringiendo ahora las variables de depósito de fin de día:
∑ ∑ 𝑋𝑑𝑖𝑡.𝑑.𝑖𝑐−𝑙𝑒
2
𝑐=1
≥ 𝑋𝑅𝑡.𝑑.𝑙.𝑟 ∀
𝑖∈𝐿
𝑟 ∈ 𝑅𝑑𝑙 ∀𝑙 ∈ 𝐿 ∀𝑑 ∈ 𝐷 ∶ 𝑒 = 𝐹𝑁𝑑𝑙𝑟
3. Se definieron anteriormente las variables binarias del problema como los hipotéticos traslados que
podría realizar un tren. En el caso de los traslados desde depósito hasta una estación, y vice-versa,
aunque existen múltiples posibilidades para un tren, en un mismo día, sólo podrá realizar un traslado
desde depósito hasta su estación de inicio y sólo un traslado desde la estación de finalización a un
depósito. Por esta razón, se debe asegurar que se active una sola variable de traslado de depósito a
estación por día y por tren; eso también se cumple con los traslados de estación de fin de ruta hasta
depósito. A continuación se muestran las restricciones que garantizan que se active una y sólo una
variable de depósito de inicio de día y una variable de depósito de fin de día para un tren ‘t’ en un
día ‘d’:
a. Se fuerza que la suma de todas las posibles variables de depósito de inicio de día para un
tren ‘t’ en un día ‘d’ sea uno:
∑ ∑ ∑ ∑ 𝑋𝑑𝑖𝑡.𝑑.𝑙𝑒−𝑖𝑐 = 1 ∀𝑡 ∈ 𝑇 ∀𝑑 ∈ 𝐷
2
𝑐=1𝑖∈𝐿
2
𝑒=1𝑙∈𝐿
b. Las restricciones son análogas para las variables de depósito de fin de día:
∑ ∑ ∑ ∑ 𝑋𝑑𝑓𝑡.𝑑.𝑙𝑒−𝑖𝑐 = 1 ∀𝑡 ∈ 𝑇 ∀𝑑 ∈ 𝐷
2
𝑐=1𝑖∈𝐿
2
𝑒=1𝑙∈𝐿
4. Todos los trenes deben pernoctar en un depósito. Es lógico que el depósito donde un tren acaba el
día ‘d’, será el mismo depósito en el que ese tren comenzará el día siguiente, el día ‘d+1’. Es
necesario que, para mantener esta continuidad entre días consecutivos, se certifique que el depósito
del inicio del día ‘d’ del tren ‘t’ coincida con el depósito de fin de día ‘d-1’ del tren ‘t’. Esta
continuidad se consigue forzando que, si una variable de depósito de fin de día del día ‘d’ y tren ‘t’,
para un depósito que se encuentra en la línea ‘i’ en la estación ‘c’ se activa, una de las variables de
depósito de inicio de día del día ‘d+1’ del tren ‘t’ que conecta la estación ‘c’ de la línea ‘l’ con las
29
estaciones de inicio de ruta, también se debe de activar. Estas restricciones de formulan de la
siguiente forma:
∑ ∑ 𝑋𝑑𝑓𝑡.𝑑.𝑙𝑒−𝑖𝑐 = ∑ ∑ 𝑋𝑑𝑖𝑡.𝑑+1.𝑖𝑐−𝑙𝑒
2
𝑒=1𝑙∈𝐿
2
𝑒=1𝑙∈𝐿
∀𝑙 ∈ 𝐿 ∀𝑒 ∈ [1,2] ∀𝑡 ∈ 𝑇 ∀𝑑 ∈ [0, 𝐷 − 1]
Además, ya que se está considerando que el conjunto D se repite a lo largo del horizonte temporal,
habrá que garantizar la continuidad entre el último y primer día del conjunto D, pues cuando se
repite el conjunto, estos días serán consecutivos. Se fuerza entonces que el depósito del fin de día
del tren ‘t’ del último día del conjunto D sea el mismo que el depósito de inicio del tren ‘t’ de día
del primer día del conjunto D:
∑ ∑ 𝑋𝑑𝑓𝑡.𝐷.𝑙𝑒−𝑖𝑐 = ∑ ∑ 𝑋𝑑𝑖𝑡.1.𝑖𝑐−𝑙𝑒
2
𝑒=1𝑙∈𝐿
2
𝑒=1𝑙∈𝐿
∀𝑙 ∈ 𝐿 ∀𝑒 ∈ [1,2] ∀𝑡 ∈ 𝑇
5. Un tren tiene la posibilidad de no realizar una ruta en un día ‘d’ del conjunto D. Esto puede pasar si
el día ‘d’ tiene menos rutas que otro día en el conjunto D. En este caso, el tren que no realiza una
ruta definida, tendrá que realizar una ruta en vacío. Por tanto, habrá que garantizar que, si un tren
no realiza ninguna ruta, se asigna a una ruta vacía. Esto se consigue forzando que en un mismo día,
se active una variable de ruta, XR o una variable de ruta vacía, XV, pero nunca las dos a la vez,
para el tren ‘t’. Además, se obliga a que se active una variable de ruta o una variable de ruta vacía
del tren ‘t’, del día ‘d’:
∑ ∑ ∑ ∑ 𝑋𝑉𝑡.𝑑.𝑙𝑒−𝑖𝑐 + ∑ ∑ 𝑋𝑅𝑡.𝑑.𝑙.𝑟
𝑟∈𝑅𝑑𝑙𝑙∈𝐿
= 1 ∀𝑡 ∈ 𝑇 ∀𝑑 ∈ 𝐷
2
𝑐=1𝑖∈𝐿
2
𝑒=1𝑙∈𝐿
6. Al igual que con las rutas definidas por el sistema, la conexión entre los depósitos y las rutas en
vacío también se deben garantizar. Para ello, se crean restricciones análogas a las del punto 2. Las
siguientes restricciones aseguran que, si un tren es asignado a una ruta vacía, las correspondientes
variables de depósitos son también asignadas/activadas:
a. Las siguientes restricciones fuerzan que si un tren ‘t’ realiza una ruta vacía que va de la
estación ‘e’ de la línea ‘l’ hasta la estación ‘c’ de la línea ‘i’ en el día ‘d’, se activa la variable
de depósito de inicio de día adecuado:
∑ ∑ 𝑋𝑑𝑖𝑡.𝑑.𝑖𝑐−𝑙𝑒
2
𝑐=1
≤ ∑ ∑ 𝑋𝑉𝑡.𝑑.𝑙𝑒−𝑖𝑐
2
𝑐=1𝑖∈𝐿
∀
𝑖∈𝐿
𝑒 ∈ [1,2] ∀𝑙 ∈ 𝐿 ∀𝑡 ∈ 𝑇 ∀𝑑 ∈ 𝐷
b. Análogo a lo anterior, restringiendo ahora las variables de depósito de fin de día:
∑ ∑ 𝑋𝑑𝑖𝑡.𝑑.𝑖𝑐−𝑙𝑒
2
𝑐=1
≤ ∑ ∑ 𝑋𝑉𝑡.𝑑.𝑙𝑒−𝑖𝑐
2
𝑐=1𝑖∈𝐿
∀
𝑖∈𝐿
𝑒 ∈ [1,2] ∀𝑙 ∈ 𝐿 ∀𝑡 ∈ 𝑇 ∀𝑑 ∈ 𝐷
7. Es necesario definir las estaciones que se usan como depósito. Estas estaciones vendrñan definidas
por las variables de inicio y fin de día; si una variable de inicio de día del tren ‘t’ que conecta la
estación ‘e’ de a línea ‘l’ con su estación de inicio de ruta ‘c’ en la línea ‘i’, entonces la estación ‘e’
de la línea ‘l’ es un depósito, y la variable de activación de depósito asociado a esta estación se debe
de activar:
𝑋𝑑𝑖𝑡.𝑑.𝑙𝑒−𝑖𝑐 ≤ 𝐴𝑙𝑒 ∀𝑙, 𝑖 ∈ 𝐿 ∀𝑒, 𝑐 ∈ [1,2] ∀𝑑 ∈ 𝐷 ∀𝑡 ∈ 𝑇
Esto se cumple de forma análogo con las variables de fin de día:
𝑋𝑑𝑓𝑡.𝑑.𝑙𝑒−𝑖𝑐 ≤ 𝐴𝑖𝑐 ∀𝑙, 𝑖 ∈ 𝐿 ∀𝑒, 𝑐 ∈ [1,2] ∀𝑑 ∈ 𝐷 ∀𝑡 ∈ 𝑇
8. Para la función objetivo, es necesario conocer las distancias recorridas en vacío por los trenes a lo
largo de los días del conjunto D. Se definen las variables de recorrido en vacío en las siguientes
restricciones. Para cada tren, este recorrido constará de la suma de las distancias entre depósitos e
inicios de ruta y entre fin de ruta depósitos durante los días del conjunto D, además de los kilómetros
recorridos en rutas vacías:
∑ ∑ ∑ ∑ ∑[𝑋𝑑𝑖𝑡.𝑑.𝑙𝑒−𝑖𝑐 + 𝑋𝑑𝑓𝑡.𝑑.𝑙𝑒−𝑖𝑐 + 𝑋𝑉𝑡.𝑑.𝑙𝑒−𝑖𝑐] ∗ 𝐷𝐸𝑙𝑒−𝑖𝑐 = 𝑅𝑉𝑡 ∀𝑡 ∈ 𝑇
2
𝑐=1𝑖∈𝐿
2
𝑒=1𝑙∈𝐿𝑑∈𝐷
9. Además de las distancias recorridas en vacío, también se precisa medir las distancias totales
recorridas por los trenes a lo largo de los días del conjunto D, para poder buscar una solución, no
sólo de bajo coste, sino con desgaste equilibrado del material rodante. Las siguientes restricciones
definen las variables de recorrido total. Para cada tren ‘t’, este recorrido será la suma de kilómetros
recorridos en vacío, RVt, y los kilómetros recorridos en cada ruta de cada día:
𝑅𝑉𝑡 + ∑ ∑ ∑ 𝑋𝑅𝑡.𝑑.𝑙.𝑟 ∗ 𝐾𝑀𝑑.𝑙.𝑟 = 𝑅𝑒𝑐𝑡 ∀𝑡 ∈ 𝑇
𝑟∈𝑅𝑑𝑙𝑙∈𝐿𝑑∈𝐷
10. El coste total queda definido por la suma del coste por kilómetros en vacío a lo largo de todo el
horizonte temporal y el coste de la construcción de depósitos:
∑ 𝑅𝑉𝑡 ∗ (𝑌𝑅𝑆 ∗ 365/𝐷) ∗ 𝐶𝑉 + ∑ ∑ 𝐴𝑙𝑒 ∗ 𝐶𝐷 = 𝐶_𝑇𝑜𝑡𝑎𝑙
2
𝑒=1𝑙∈𝐿𝑡∈𝑇
11. El coste de equilibrio se definirá como la diferencia entre los kilómetros recorridos por el tren que
recorre la máxima distancia y los del tren que recorre la mínima distancia. De esta forma, cuando
se minimice este coste de equilibrio, los recorridos de los trenes a lo largo de todos los días del
conjunto D se equilibrarán entre sí de forma orgánica.
Para encontrar el mínimo entre los recorridos de los trenes, se usa una variable auxiliar, llamado
Rmin, que guardará el valor mínimo. Este valor se define con las siguientes restricciones:
𝑅𝑒𝑐𝑡 ≥ 𝑅𝑚𝑖𝑛 ∀𝑡 ∈ 𝑇
Al igual que con el mínimo, para encontrar el recorrido máximo, también se introduce una variable
auxiliar llamado Rmax, que guarda el valor del recorrido máximo. El valor máximo se define con
las siguientes restricciones:
𝑅𝑒𝑐𝑡 ≤ 𝑅𝑚𝑎𝑥 ∀𝑡 ∈ 𝑇
31
Tras haber definido el máximo y mínimo de los recorridos, se puede definir el coste de equilibrio
con la siguiente restricción:
𝑅𝑚𝑎𝑥 − 𝑅𝑚𝑖𝑛 = 𝐶_𝐸𝑞𝑢
Con estas restricciones queda definida el entorno y las limitaciones del problema. A continuación, se define
la función objetivo, utilizada como criterio para determinar la solución óptima.
4.2.2 Función Objetivo
La función objetivo busca encontrar la programación que produzca los mínimos costes, tanto por
construcción de depósitos como por kilómetros recorridos en vacío. Además, también se busca el equilibrio
entre las distancias recorridas por cada tren que forma parte del material rodante del sistema ferroviario. Sin
embargo, la importancia del coste de inversión y de funcionamiento del sistema ferroviario puede ser mayor
que el equilibrado de recorridos de los trenes. Por esto, la variable de coste de equilibrio se multiplica por un
coeficiente α,que permite realizar diferentes experimentos valorando de diferente forma el criterio de
equilibrado.
Por lo cual, para encontrar esta solución óptima, se ha introducido la siguiente función objetivo:
𝐹. 𝑂𝑏𝑗. : 𝑀𝐼𝑁 [𝐶𝑇𝑜𝑡𝑎𝑙 + 𝛼𝐶_𝐸𝑞𝑢]
Este modelo se ha formulado en el lenguaje Python 3.5, y resuelto usando el solver Gurobi Optimizer. El
modelo de optimización se incluye en el Anexo I.
5 HEURÍSTICA PROPUESTA: ALGORITMO
GENÉTICO
La naturaleza del problema que se desea abordar permite considerar varias herramientas meta-heuristicas
que podrán ser útiles a la hora de buscar una solución a dicho problema.
Se ha estudiado una gran variedad de procesos meta-heurísticos como Ant Colony algorithms for discrete
optimization [4], búsqueda Tabú [6], Cuckoo [11], Harmónico [8] y Genético [12]. Se ha considerado el
algortimo Luciernaga [10], el algoritmo de recocido simulado [5], optimización por enjambre de partículas
[7] y el algoritmo Big Bang Crunch [9]. Tras estudiar las condiciones y factores de cada una de estas
metaheurísticas, analizadas las características del problema y la aplicación de estos algoritmos en el ámbito
de la optimización de procesos en redes de trasnporte público, se ha llegado a la conclusión que la
flexibilidad, versatilidad y aplicabilidad de los Algoritmos Genéticos es una buena opción para la resolución
del problema planteado.
Un algoritmo genético (AG) consta de un proceso de optimización que combina la información organizada
de un problema con múltiples soluciones posibles, con el principio Darwiniano de supervivencia del más
apto [12]. Este principio se puede resumir como:
<<Existen organismos que se reproducen y la progenie hereda características de sus progenitores,
existen variaciones de características si el medio ambiente no admite a todos los miembros de una
población en crecimiento. Entonces aquellos miembros de la población con características menos
adaptadas (según lo determine su medio ambiente) morirán con mayor probabilidad. Aquellos
miembros con características mejor adaptadas sobrevivirán más probablemente>> C. Darwin,
Origen de la Especie [13]
Aplicado a la búsqueda de la solución óptima de un problema de tipo NP-Hard, el algoritmo genético supone
que estos mecanismos realizará el mismo proceso de eliminación de individuos con cualidades no deseados,
dejando sólo los individuos más fuertes.
El proceso consta de varias fases, que buscan recrear el proceso de evolución natural que se puede observar
en la naturaleza. Se introduce tanto el mecanismo de selección natural, como el mecanismo de mutaciones.
Existen otros mecanismos que, aunque aplicables a la evolución natural, no tienen sentido en el ámbito de
la búsqueda de soluciones óptimas de problemas tipo NP-Hard.
El primer paso es crear un grupo de individuos iniciales, de forma aleatoria. Este grupo será la generación
inicial, a partir de la cual se crearán todos los individuos de las siguientes generaciones.
Posteriormente, se realiza la selección. Para continuar el paralelismo con la teoría evolutiva, esta fase se
podría considerar como el análogo del proceso de selección natural o de supervivencia del más apto. En este
caso, las soluciones o individuos que se consideran más aptos son aquellos que tengan el mejor valor de la
función objetivo.
Este grupo se divide en tres subdivisiones:
1. Padres y Madres. Estos serán los individuos más aptos de la generación. El porcentaje del grupo inicial
que son padres y madres puede variar según el problema. Este grupo de individuos se combinarán para
crear nuevos individuos, que, teóricamente, serán mejores que sus padres, y formarán la nueva
generación.
2. Mutaciones. Después de los padres y madres, se selecciona un grupo de individuos que tendrán
mutaciones aleatorias, que podrán llevar a buenas o malas soluciones, y formarán parte de la siguiente
generación de individuos.
3. Eliminados. Aquellos individuos de la generación inicial que no resultan aptos para ser padres serán
excluidos de la siguiente generación.
33
La siguiente generación pasará por este mismo proceso de selección. Este proceso se realiza repetitivamente
hasta que el algoritmo encuentre un individuo que proporciona un valor aceptable de la función objetivo, es
decir, encuentre una solución que se considera como óptima.
Sin embargo, es posible que el algoritmo no llegue a una solución óptima global. Puede pasar que, en la
búsqueda de esta solución global, el algoritmo se encuentre en una solución óptima local. Para evitar esto,
se recomienda que el algoritmo se repita varias veces, ya que la solución que se encuentra depende, en parte,
del grupo de individuos creados al inicio.
Figura 3. Gráfica de valor de función objetivo de un problema ejemplo para
En ésta gráfica se puede ver un rango de soluciones con un óptimo local y un óptimo global. El punto verde
es un óptimo local para un problema donde la función objetivo se maximiza. El algoritmo genético puede
encontrar este óptimo, y ya que no hay soluciones cercanas mejores, interpretará que la solución es la óptima.
Sin embargo, el algoritmo podrá encontrar el punto azul, el óptimo global, si parte desde otro punto inicial.
El punto de origen es la generación inicial, y, por tanto, ya que este punto se crea de forma aleatoria, habrá
que realizar el experimento varias veces, para evitar que el algoritmo se quede atrapado en un óptimo local.
Además de estas repeticiones de experimentos, habrá que poner límite en el número de generaciones que se
crean. En general, se puede suponer que, para problemas más grandes y complejas, se necesitarán más
generaciones para llegar al óptimo. Por tanto, será necesario limitar las generaciones creadas en función del
tamaño y dificultad del problema.
Basandose en esta descripción general se prono a continuación un algoritmo genético en términos generales,
se podrá crear un algoritmo genético desrrollado a medida para el problema específico de asignación de rutas
y localización de depósitos en el proceso de planificación de sistemas ferroviarios
5.1 Algoritmo genético ajustado a problema
El algoritmo genético ajustado al problema de asignación de rutas y localización de depósitos se ha creado
y codificado en Python 3.5. Se han creado estructuras de datos y funciones que aprovechen la naturaleza
del lenguaje, de forma que se desarrolle el algoritmo genético con la mayor economía de código.
El programa que realiza el algoritmo podrá dividirse en varias partes:
- Introducción de datos. Los datos del sistema se introducirán, en parte, cargándolos desde una hoja
de cálculo creada previamente. Los demás datos serán introducidos al ejecutar el programa.
- Creación de generación inicial, realización de selección y mutaciones. Se guarda el individuo con
el mejor valor de función objetivo en la memoria del programa, y se procede a crear la siguiente
generación.
- Se repite el proceso hasta llegar a una solución óptima.
- El experimento evolutivo aplicado al problema se repite varias veces para disminuir la
probabilidad de haber encontrado una solución óptima local, y permitir que el programa se
acerque al óptimo global.
El AG se expondrá de forma detallada a continuación.
Las instrucciones de uso de la introducción de datos y exposición de resultados del programa, a través de
hojas de cálculo, se puede encontrar en el ANEXO IV.
5.1.1 Datos de entrada de Solución Genética
Duración del horizonte es el tiempo en años que se considerado como horizonte temporal. Este
tiempo es la que se usa para estudiar la inversión, y por tanto, el coste total de todo el sistema
ferroviario. Estará representado en el código del algoritmo como la variable N_Years.
Número de Líneas en el sistema. Son las líneas ferroviarias por las que se mueve el material
rodante. Cada línea queda definida por las estaciones en sus extremos, llamadas estación límite, así
como por la la distancia entre ellas. Se representa por la variable Num_Lineas.
Número de Días totales que se consideran y que se repetirán consecutivamente a lo largo del
horizonte temporal. Representado por la variable Num_Dias.
Coste de viajar en vacío es el coste por kilómetro de un tren que realiza un recorrido sin pasajeros,
en vacío. Este dato se representa por la variable CV.
Coste de construcción de depósito es el coste de construir un depósito en el sistema ferroviario.
Este dato es representado por la variable CD.
Distancias en kilómetros entre estaciones y líneas:
Se define una matriz de dimensiones 2*Num_Lineas X 2*Num_Lineas. Como se comentó
anteriormente, las líneas se definen con sus dos estaciones límite y la distancia entre ellas. Además,
es necesario tener en cuenta la distancia entre estaciones de líneas diferentes. Por tanto, esta matriz
será simétrica. En la realidad, varias líneas de un mismo sistema pueden compartir infraestructuras,
es decir, estaciones y vías. Sin embargo, a la hora de codificar la información, cada línea tendrá sus
propias estaciones y vías, independientes de otras. Estaciones compartidas entre líneas tendrán una
distancia nula en la celda correspondiente a las línea implicadas. Estas distancias se guardan en el
programa dentro de una lista nombrada DIST. Se puede ver de forma gráfica a continuación:
L1E1 L1E2 L2E1 L2E2
L1E1 0 20 15 20
L1E2 20 0 15 20
L2E1 15 15 0 15
L2E2 15 20 15 0
Tabla 2. Distancias entre estaciones de dos líneas de un mismo sistema
35
Esta matriz se crea en la función Create_Distances(Num_Lineas) del código del ANEXO II y las
distancias se cargan desde la hoja de cálculo, cuyas instrucciones de uso se encuentran en el ANEXO
IV.
Rutas del sistema ferroviario. Se trata de la colección de rutas que se deben realizar en cada línea
y cada día, que cumplen los servicios horarios estipulados al principio del proceso de planificación
de sistemas ferroviarios. Como se describió con anterioridad, las rutas y por tanto sus longitudes se
habrán calculado previamente y se consideran datos para el problema de circulaciónu determinación
de depósitos.
Cada ruta individual es definida por los siguientes datos:
o El día que se realiza la ruta. En el ámbito del problema, se considera que cada ruta empieza
y acaba en un mismo día.
o La línea a la que pertenece la ruta. Una ruta sólo puede pertenecer a una línea.
o La estación de inicio, desde la que parte la ruta y la estación de fin, donde termina la ruta.
Estas estaciones deben ser una de las dos estaciones límite de la línea a la que pertenece la
ruta
o La longitud (nº de kilómetros) de la ruta. Esta distancia debe ser igual o mayor que la
distancia de la línea en la que existe la ruta. Esto se debe a que una ruta puede incluir varios
viajes desde una estación límite de la línea a otra, o puede incluir sólo un viaje entre
estaciones.
Se puede ver una representación gráfica de una ruta continuación:
Figura 4. Representación Gráfica de un Ejemplo de Ruta
Este ejemplo muestra una ruta que comienza el día en la estación 2 de una línea cualquiera, y termina
en la estación 1 de esa misma línea.
Las rutas se cargan al programa desde una hoja de cálculo, de acuerdo a las instrucciones de uso de
la hoja de cálculo para la introducción correcta de datos. Las rutas se guardan en el programa en una
lista con una estructura especializado para las funciones del código
Para mostrar la estructura de la lista RUTAS dentro del código, se emplea un ejemplo de un sistema
de dos líneas, donde el conjunto D incluye dos días. El ejemplo tiene dos rutas en cada línea y en
cada día. La lista tiene una estructura anidada, y a continuación se define cada nivel de la lista:
o El primer nivel de la lista RUTAS divide las rutas por días. La lista RUTAS tiene una lista
para cada día. En caso de Num_Dias=2, tendría el siguiente aspecto:
RUTAS = [ [], [] ]
o El siguiente nivel divide las rutas de cada día en líneas. Cada lista RUTAS[d] tendrá una
lista por línea. En el ejemplo que se considera corresponderías a las listas de nivel anterior
dentro de la estructura anidada:
RUTAS = [ [Dia 1 [L1], [L2] ], [Dia 2 [L1], [L2] ] ]
o En el tercer nivel se define una lista para cada ruta individual que se realiza en cada línea y
cada día. Cada lista RUTAS[d][l] contiene una lista por cada ruta que se realice en la línea
‘l’ en el día ‘d’. Se representan acentuadas en turquesa:
RUTAS = [ [Día 1 [L1[Ruta 1],[Ruta 2] ], [ [], [] ] ], [ [ [], [] ], [ [], [] ] ] ]
o El último nivel contiene la información que permite definir cada ruta individual de cada
línea y cada día. Esta información se guardarán en tres listas diferentes. Cada lista
RUTAS[d][l][r] tendrá tres listas:
La primera indica la estación de inicio:
[1,0] indica la estación 1; [0,1] indica la estación 2
La segunda indica la estación de fin:
[1,0] indica la estación 1; [0,1] indica la estación 2
La tercera indica los kilómetros recorridos dentro de la ruta ‘r’, de la línea ‘l’ y del
día ‘d’.
El ejemplo propuesto inicialmente, de un sistema de dos líneas, con un conjunto D de dos días,
donde se realizan 2 rutas en cada línea y en cada día, tiene, por tanto, la siguiente lista RUTAS:
RUTAS = [ [ [ [ [1, 0], [0, 1], [120] ], [ [0, 1], [1, 0], [90] ] ],
[ [ [1, 0], [1, 0], [125] ], [ [0, 1], [0, 1], [85] ] ] ],
[ [ [ [1, 0], [1, 0], [105] ], [ [1, 0], [0, 1], [90] ] ],
[ [ [0, 1], [1, 0], [75] ], [ [1, 0], [1, 0], [130] ] ] ] ]
Observando una ruta cualquiera, como, por ejemplo, la segunda ruta del primer día de la línea 1, es
decir, RUTAS[1][1][2], se interpreta la información de la siguiente forma:
[ [0, 1], [1, 0], [90] ] ]
La ruta ‘2’ de la línea ‘1’ del día ‘1’ comienza en la estación 2, termina en la estación 1 y recorre 90
kilómetros.
Esta matriz se crea en la función Create_TrainSchedule(Num_Dias, Num_Lineas) del código y se
rellena cargando información desde la hoja de cálculo donde se almacenan los datos del problema.
Número de trenes necesarios para realizar todas las rutas. Este dato no es introducido por el
usuario, sino que se calcula a partir de los datos anteriores:
En primer lugar se suma el número de rutas que se realizan en cada día del conjunto D. Estos datos
se recogen en la lista llamada TpD, de tamaño 1xD. Esta es calculada en la función
37
Trenes_por_dia(Num_Dias,Num_Lineas,RUTAS) del código del ANEXO II.
Posteriormente, se busca el mayor valor entre los objetos de la lista TpD. Este valor corresponderá
al número de rutas que se realizan en el día con mayor número de rutas. Este número, llamado
TOTAL_Trenes, será el número mínimo de trenes necesarios para cumplir las necesidades del
sistema estudiado.
5.2 Codificación de Solución
Tras la definición de los datos iniciales necesarios para la ejecución del algoritmo, y antes de exponer el
mismo, es necesario dejar estipulado cómo se configura una solución del problema dentro del programa.
Una solución válida del problema de asignación de rutas y localización de depósitos en sistemas ferroviarios
contendrá dos conjuntos fundamentales: Asignación de rutas a Trenes & Asignación de depósitos. Estos
conjuntos dejan completamente definida una solución del problema. El resto de elementos de la solución se
calculan a partir de ellos. Estos dos conjuntos se definen en el código del programa haciendo uso de listas
anidadas; la estructura de estas listas se muestra a continuación.
Asignación de rutas a Trenes. Este primer conjunto muestran las rutas que realiza cada tren del
sistema a lo largo de todo el horizonte de planificación (Num_Dias). Se puede decir que define la
planificación diaria de cada tren, ya que a partir de este conjunto se puede saber qué hace cada tren
en cada día, después de haber salido de un depósito al principio del día y antes de volver a un
depósito al final del día. Dentro de esta asignación queda definida la línea en la que se mueve ese
día así como la estación de inicio y la estación donde hace su última parada. Los movimientos desde
y hasta depósitos no están definidos en este conjunto.
En el código del programa, este conjunto de la solución se recoge en la lista denominada TRAINS.
Esta lista guarda:
o La línea ‘l’ donde se encuentra el tren ‘t’ en el día ‘d’.
o La ruta ‘r’ de la línea ‘l’ a la que es asignado el tren ‘t’ en el día ‘d’.
Para ilustrar la estructura de TRAINS con claridad, se propone el siguiente sistema ferroviario:
o El sistema está formado por 2 líneas, es decir, 2 líneas en el conjunto L.
o Se consideran 2 días en el conjunto D.
o El conjunto de rutas será la siguiente:
RUTAS=[ [ [ [ [1, 0], [1, 0], [120] ], [ [0, 1], [1, 0], [90] ] ], [ [ [1, 0], [1, 0], [125] ] ] ]
[ [ [ [1, 0], [0, 1], [90] ] ], [ [ [1, 0], [1, 0], [125] ] ] ] ]
Siendo su representación gráfica la siguiente:
Figura 5. Grafo de Rutas de Sistema Ejemplo.
o El nivel inicial de la lista se dividirá de acuerdo a los trenes que existen en el sistema, es
decir, la lista TRAINS tendrá una sub-lista para cada tren usado en el sistema:
(En este caso, se puede calcular fácilmente TOTAL_Trains=3)
TRAINS=[ [], [], [], [] ]
o El segundo nivel contiene la programación de los trenes por días, teniendo por tanto una
lista para cada día dentro de cada una de las sub-listas TRAINS[t]:
TRAINS=[ [Tren 1[Día 1], [Día 2] ], [ [], [] ], [ [], [] ] ]
o El tercer nivel de la lista guarda las rutas que realiza cada tren en cada día. Cada lista
TRAINS[t][d] guardará dos números: el primero es la ruta asignada al tren ‘t’ en el día ‘d’
y el segundo, la línea donde se realiza tal ruta:
TRAINS=[ Tren 1[ Día 1 [Ruta 1, Línea1], [0, 0]], [[2, 1], 1, 1]], [ [1, 2], [1, 2] ] ]
Si un tren no realiza una ruta en un día ‘d’, los valores guardados en esta sub-lista serán
nulos. Comose explicó anteriormente, un tren no podrá realizar más de una ruta al día, por
tanto, la sub-lista TRAINS[t][d] solo contiene dos valores.
La información contenida, a modo de ejemplo, en TRAINS=[[[1,1],[0,0]],[[2,1],[1,1]], [[1,2],[1,2]]]
se puederepresentar de forma gráfica a continuación:
39
Figura 6. Asignación de Rutas del Sistema Ejemplo
Se puede observar que el tren 1 realiza la ruta 1 de la línea 1 el día 1, pero no realiza ninguna ruta
en el día 2. Esto se puede ver representado en TRAINS[1][2]=[0, 0].
Si los valores de TRAINS[t][d] son nulos, el tren ‘t’ no realiza ninguna ruta en el día ‘d’, es decir,
realiza una ruta en vacío.
Esta lista se crea en la función Create_TRAINSsol(Num_Dias,Num_Lineas,TOTAL_Trenes) del
código del ANEXO II.
Asignación de depósitos. El segundo conjunto que define una solución del problema es aquel que
determina qué estaciones son depósitos en el sistema ferroviario. Además recoge cuales de estos
depósitos son usados por cada tren en cada día.
Al igual que en el modelo matemático, es importante mantener la continuidad de depositos entre
días consecutivos. En otros términos, es necesario asegurar que, para que una solución sea válida,
el depósito donde un tren acaba un día coincida con el depósito del que sale al inicio del día
siguiente. Esta continuidad se garantiza de forma muy simple, aprovechando las ventajas de listas
en el lenguaje de programación Python 3.5 a la hora de definir el conjunto Asignación de Depósitos:
Se usa una lista nombrada DEP, y, al igual que el conjunto Asignación de Rutas a Trenes, tiene una
estructura creada con listas anidadas:
o Primero, la lista se divide por tren, creando una lista que guarda los depósitos usados por
cada tren durante todos los días del conjunto D. Por tanto: la lista DEP tendrá una sub-lista
por cada tren (3 en el caso del ejemplo anterior):
DEP=[ [], [], [] ]
o A continuación, se divida la planificación de cada tren por días, definiendo una lista por
cada día del conjunto D para cada tren del sistema. Es decir, cada lista DEP[t] tendrá una
sub-lista por cada día:
DEP=[ [ [], [] ],
[ [], [] ],
[ [], [] ], ]
o El siguiente nivel se usa para definir posiciones de los depósitos, para ello se divide la
planificación de cada día, y cada tren, en el número de líneas del sistema ferroviario. Por lo
siguiente, cada lista DEP[t][d] tendrá una lista por cada línea:
DEP=[ [ [ [], [] ], [ [], [] ] ],
[ [ [], [] ], [ [], [] ] ],
[ [ [], [] ], [ [], [] ] ], ]
o Finalmente, se define el uso y localización de cada depósito. Esto se consigue guardando
en cada lista DEP[t][d][l] dos valores, que podrán ser 1 ó 0. Estos dos valores representan
las estaciones límite de la línea a la que pertenecen, el primer valor simbolizando la estación
1 y el segundo, la estación 2:
DEP=[ [ [ [0, 0], [1, 0] ], [ [1, 0], [0, 0] ] ],
[ [ [1, 0], [0, 0] ], [ [1, 0], [0, 0] ] ],
[ [ [0, 0], [1, 0] ], [ [0, 0], [1, 0] ] ], ]
Un valor igual a 1 en la lista DEP indica que en esa ubicación hay un depósito, y que es usada por
el tren en el día al que corresponde en la lista de acuerdo a su posición. Este concepto se puede
entender de forma más clara realizando un extracto del ejemplo anteriormente expuesto (ver figura
7).
Tomando de DEP, la información referente a los depósitos usados por el tren 1, a lo largo de los
días del conjunto D, (DEP[1]=[ [ [0, 0], [1, 0] ],[ [1, 0], [0, 0] ] ] ) se puede entender que:
o El tren 1, al comenzar el día 1, sale de un depósito localizado en la estación 1 de la línea 2.
o El tren 1, al final del día 1, entra a un depósito localizado en la estación 1 de la línea 1.
o El tren 1, al comenzar el día 2, sale de un depósito localizado en la estación 1 de la línea 2.
o El tren 1, al final del día 2, entra a un depósito localizado en la estación 1 de la línea 2.
Figura 7. Ejemplo de solución mostrando el uso de depósitos.
41
Volviendo al problema de continuidad de depósitos entre días consecutivos, se puede observar que,
a diferencia del modelo matemático, el conjunto Asignación de Depósitos no define depósitos de
inicio y fin de día, sino que simplemente define uno por día y por tren. Sin embargo, la continuidad
queda garantizada.
Esta garantía se consigue, a la hora de combinar los conjuntos que definen la solución, ie, Asignación
de rutas a trenes & Asignación de Depósitos, se considera que, el depósito asignado al tren ‘t’ en el
día ‘d’ representa el depósito de inicio de día ‘d’; es decir, será el depósito del que sale el tren ‘t’ al
principio del día ‘d’. Por tanto, para garantizar la conexión entre los días ‘d’ y ‘d-1’, este deósito,
que ha servido como depósito de inicio de día ‘d’, también será el depósito de fin del día ‘d-1’. En
palabras simples, el dato que identifica el depósito usado por el tren ‘t’ en un día ‘d’ es, a la vez, el
depósito donde pernocta el tren ‘t’ al final del día ‘d-1’ y el depósito del que sale ese mismo tren ‘t’
al inicio del día ‘d’.
De esta forma, quedan definidos los depósitos de inicio y fin de día para cada tren, sin la necesidad
de crear un sub-conjunto adicional.
Finalment, se puede entender que, a lo largo del horizonte temporal, los días del conjunto D se
repetirán consecutivamente. Es decir, el primer día de la semana X del horizonte temporal será
consecutiva al último día de la semana X-1. Ya que se considera que todas las semanas son idénticas
a lo largo del horizonte temporal, debe existir para mantener la continuidad de depósitos a lo largo
de todo el horizonte temporal, existe una conexión entre los depósitos del primer día y el último día
del conjunto D.
Esta conexión se crea a la hora de exponer y calcular los resultados, haciendo que el depósito del
que sale al comienzo del primer día cualquier tren ‘t’, coincida con el depósito al que entra al final
del último día.
Esta lista se crea en la función Create_Depositos(TOTAL_Trenes,Num_Dias, Num_Lineas) del
código del ANEXO II.
Además, se calcula el número de depósitos usados, recogido en la variable NDep, en la función
Calculo_Dep(DEP, TOTAL_Trenes ,Num_Lineas ,Num_Dias) del código del ANEXO II.
Distancias recorridas en vacío. El coste de operación de un sistema ferroviario se calcula en
función de los kilómetros que recorre el material rodante sin pasajeros, es decir, en vacío. Aquí se
suman las distancias recorridas desde, hacia y entre depósitos, de acuerdo a la solución obtenida.
Se calculan en la función Create_Recorrido(TOTAL_Trenes) del código en el ANEXO II.
Distancias recorridas. Las distancias totales recorridas se almacenan en la lista denominada
Rec_Tren. Esta lista se crea en la función Create_Recorrido(TOTAL_Trenes) del código en el
ANEXO II. Se realiza el cálculo de la distancia recorrida por cada tren, a partir de la información
recogida en las listas TRAINS y DEP. Este cálculo se realiza en la función
Calculo_distancia(DEP,TRAINS,RUTAS,DIST,TOTAL_Trenes,Num_Lineas,Num_Dias) del
código en el ANEXO II.
Coste Depóstios. Se calcula el coste de construir NDep Depósitos.
Coste Operacional Semanal. Este es el coste semanal de operar. En otras palabras, es el coste total
de los kilómetros en vacío recorridos por todos los trenes. Se calcula multiplicando el coste por
kilómietro en vacío por la suma de todos los kilómetros vacíos recorridos en los días del conjunto
D.
Coste Operacional TOTAL. Consiste en el coste de operar a lo largo de todo el horizonte temporal.
A la hora de exponer la solución, el programa crea una hoja de cálculo que recoge la solución óptima
encontrada a través de la aplicación del algoritmo. Se puede encontrar las instrucciones de lectura de
información de esta hoja de cálculo en el ANEXO V.
5.3 Algoritmo Genético ajustado
Una vez explicados los datos de entrada del problema y la estructura de las soluciones es posible abordar la
lógica del algoritmo genético ajustado al problema de asignación de rutas y localización depósitos de un
sistema ferroviario.
El algoritmo genético es una meta-heurística muy versátil, que se puede ajustar a numerorsos tipos de
problemas y casuísticas. En el presente documento, se ha desarrollado un algoritmo genético que se adecua
a las condiciones del problema y que garantiza que todas las soluciones encontradas son admisibles de
acuerdo a las limitaciones del problema.
Las fases del procedimiento y las condiciones específicas del algoritmo que se presenta como herramienta
de solución del problema propuesto son las siguientes:
1. Mínimo Inicial.
El algoritmo genético es un proceso iterativo, que, en este caso, busca la solución o individuo con
el valor mínimo de la función objetivo, es decir, el individuo que implique el menor coste de
inversión.
Se ha decidido usar como parámetro que determina el fin del algoritmo, un valor mínimo. Este
mínimo se define al final de cada iteración del algoritmo. Sin embargo, para la primera iteración,
será neceario definir un mínimo inicial para comenzar el algoritmo.
2. Creación de Generación inicial.
Esta fase representa el comienzo del proceso evolutivo. Aquí se crean los primeros individuos, a
partir de los cuales se crearan todas las demás soluciones del algoritmo. Serán, en términos
evolutivos, los ancestros comunes de todos los individuos creados en el futuro.
Estas soluciones o individuos son creadas por el programa de manera completamente aleatoria,
siendo absolutamente indiferente al valor de sus funciones objetivo. No obstante, sí se siguen
algunas reglas, ya que, aunque no tenga en cuenta ahora la calidad de solución, sí que se debe
considerar la validez de las soluciones creadas; todos los individuos de esta generación inicial, y por
lo consiguiente, de todas las generaciones posteriores, deben ser soluciones válidas para el
problema. Una solución es válida cuando cumple las siguientes especificaciones:
1. Todas las rutas que se definen para la red ferroviaria deben ser asignadas a un tren. O sea,
no puede quedar ninguna ruta sin realizarse, ya que esto implicaría que hay servicios
horarios que no se cumplen, lo que no está permitido en el ámbito del problema.
2. Un tren sólo puede ser asignado a una ruta al día. Es decir, un tren no puede realizar más
de una ruta en un mismo día.
3. Una ruta sólo poder ser asignada a un solo tren. Una vez asignada una ruta a un tren, otro
tren no podrá realizar esa misma ruta.
4. Un tren sólo puede tener asignado un depósito al día. Como se explicó anteriormente, el
depósito asignado a un tren en un día representa el depósito de inicio de ese día, y de fin
del día anterior. Esta especificación asegura que un tren no pueda tener dos depósitos de
43
fin de día, o de inicio de día. Es decir, una vez que un tren va a un depósito al final de un
día, el tren no se moverá de depósito hasta que comience el siguiente día.
El proceso de creación de esta generación inicial en el programa se expone a continuación:
- Un individuo aleatorio se crea a través de las siguientes funciones del código del ANEXO II:
o Random_Solution_Trains(RUTAS,TpD,Num_Dias,Num_Lineas,TOTAL_Trenes).
Esta función crea la parte de la solución en la que se asignan los trenes a las rutas del
sistema. Esta función genera una asignación de forma aleatoria, y asegura que es una
solución válida. Devolverá la lista TRAINS.
o Random_Solution_Dep(Num_Dias,Num_Lineas,TOTAL_Trenes). Esta función crea
la parte de la solución que asigna trenes a depósitos para cada día. Devolverá la lista
DEP.
o Calculo_distancia(DEP,TRAINS,RUTAS,DIST,TOTAL_Trenes,Num_Lineas,Num_
Di). Esta función calcula las distancias recorridas por los trenes de una solución, a
partir de la lista de asignación de rutas TRAINS y la lista de asignación de depósitos
DEP. Esta función calcula tanto las distancias totales, como las distancias en vacío.
Devolverá las listas donde se encontrarán los kilómetro recorridos en vacío (Lista RV)
y los kilómetros totales recorridos durante los días del conjunto D (Lista Rec_Tren).
o Calculo_Dep (DEP,TOTAL_Trenes,Num_Lineas,Num_Dias). Esta función calcula
el número de depósitos usado por la solución. Devuelve el valor NDep.
o Fobj_Coste(RV,NDep,TOTAL_Trenes,CV,CD). Esta función calcula la función
objetivo.
(∑ 𝑅𝑉[𝑡] ) ∗ 𝐶𝑉 + 𝑁𝐷𝑒𝑝 ∗ 𝐶𝐷
𝑡∈𝑇
o FObj_Equibilibrio(Rec_Tren1,TOTAL_Trenes). Esta función calcula la parte de la
función objetivo que trata de equilibrar la diferencia entre las distancias totales
recorridos por cada tren. Para ello se calcula la diferencia entre l mayor y el menor de
los recorridos.
Esta función se formula de la siguiente manera:
𝑀𝑖𝑛 (max(𝑅𝑒𝑐𝑇𝑟𝑒𝑛[𝑡]: 𝑡 ∈ [0, 𝑇]) − min(𝑅𝑒𝑐𝑇𝑟𝑒𝑛[𝑡]: 𝑡 ∈ [0, 𝑇]))
o Crear_Sol_Random(RUTAS,TpD,Num_Dias,Num_Lineas,TOTAL_Trenes,
DIST,CV,CD). Suma los valores de las partes de la función objetivo en un solo valor
FOBJ.
Esta función devolverá una lista cuyos valores son:
SOL= [FOBJ, TRAINS ,DEP ,Rec_Tren1, RV, NDep]
- Todos los individuos de la primera generación del algoritmo genético se crean en la función
Create_Random_popX(RUTAS,TpD,
Num_Dias,Num_Lineas,TOTAL_Trenes,DIST,X,CV,CD) del código del ANEXO II, donde X
es el número de individuos que se desea crear.
El número de individuos creados en cada generación es un parámetro del algoritmo, y se referirá
a este número como Pob a partir de ahora.
3. Selección Genética.
Esta fase trata de replicar el mecanismo evolutivo de selección natural de acuerdo a los siguientes
apartados:
1. Se ordenan las soluciones según el valor de su función objetivo de menor a mayor, ya que
se busca minimizar las funciones objetivo, es decir, se busca el menor coste y el mayor
equilibrio de distancias recorridas.
2. Se selecciona los SEL mejores para que sean el grupo reproductor, siendo SEL un parámetro
que define el usuario del algoritmo. Estos individuos son los más aptos, y para llevar el
paralelismo con la evolución, serán aquellos individuos que ‘sobreviven’ y por tanto podrán
pasar sus cualidades a la siguiente generación. Serán conocidos, así pues como los
progenitores de la siguiente generación.
3. Los siguientes MUT mejores individuos, tras aquellos seleccionados para ser
reproductores, serán los individuos que sufren mutaciones, siendo MUT un parámetro
definido por el usuario del algoritmo. Mutaciones, en la naturaleza, en algunos individuos
de la población de una especie puede dar lugar a la propagación de cualidades buenas, que
no habrían surgido de otra forma en la población. Por tanto, se puede llegar a la misma
conclusión a la hora de introducir mutaciones en las soluciones de la población que se crea
en el algoritmo genético.
En la naturaleza, aunque mutaciones pueden ocurrir por razones específicas, se puede decir
que ocurren de forma relativamente aleatoria. Por lo tanto, las mutaciones que sufren los
individuos elegidos para este grupo en el algoritmo, serán también aleatorias.
4. Los individuos sobrantes serán eliminados de la lista, y por tanto del algoritmo. Estos
individuos se consideran no aptos para el sistema y no ‘sobreviven’ el ambiente,
manteniendo el paralelismo con el mecanismo de selección natural.
El tamaño de la población dependerá, por tanto, del valor de los parámetros SEL y MUT. La
ecuación que define el tamaño de población se mostrará más adelante.
Esta selección se realiza en la función Genetic_selection(GEN) del código del ANEXO II.
45
4. Creación de ‘familias reproductoras’.
En esta fase en donde se definen las parejas que se reproducirán para crear la nueva generación. El
conjunto de individuos ‘reproductores’, se dividen en dos grupos, llamados ‘Familias’. Estas dos
familias están formadas por los mismos individuos, y se diferencian en la forma en la que se
combinan estos individuos entre ellos.
Dentro de estas familias, hay un grupo que se define como ‘Padres’ y otro como ‘Madres’. Cada
uno de ellos está formado por la mitad de los individuos reproductores. Posteriormente, se combinan
los individuos Padres con las Madres. Sin embargo, en esta fase solamente se definen las familias,
y los grupos a combinar.
Las familias, y sub grupos, se forman siguiendo la siguiente norma:
1. En el primer conjunto, o Familia, se cruza el individuo con el menor valor de suma de
funciones objetivo, con el segundo mejor; el tercero con el cuarto, y así consecutivamente
hasta llegar a combinar todos los individuos.
A modo de ejemplo se ha elegido una población de 100 individuos, habrá 30 individuos
reproductores. Asignando el nombre 1 al individuo con el mínimo valor de función
objetivo, 2 al segundo mejor, etc., se definen las parejas reproductoras de la familia 1 a
continuación:
Este grupo se guardará como FAM1 en el código, que consta de dos listas de individuos:
[Padres1, Madres1]
2. La segunda familia está formada por los mimos individuos que forman la familia 1. Sin
embargo, se definen las parejas de forma que se definen como Padres la mitad de los
individuos reproductores con el mejor valro de F.O., y por lo tanto, las Madres son la otra
mitad de individuos. En esta familia, se cruza el mejor de los padres, con la mejor de las
madres, el segundo mejor de los padres con la segunda mejor de las madres… y así
sucesivamente hasta combinar todos los individuos.
En el mismo ejemplo anterior, numerando de igual manera los individuos de la familia de
30 individuos, se pueden ver a continuación las parejas reproductoras de la familia:
Padres1 Madres1
1 2
3 4
… …
29 30
Tabla 3. Combinaciones de Individuos Reproductoes
Este grupo se guardará como FAM2 en el código, que consta de dos listas de individuos: [Padres2,
Madres2].
Esta labor de combinación y creación de ‘Familias’, se realiza dentro de la función
Genetic_selection(GEN) del código del ANEXO II.
5. Mutaciones.
La introducción de mutaciones en la población de soluciones al problema puede resultar en la
aparición de cualidades que no habrían surgido de otra manera en el proceso de selección natural.
Para crear estas mutaciones, se toman los individuos seleccionados en la fase 2 para ser mutados y
se introducen ligeros cambios en ellos.
El proceso de introducción de una mutación en un individuo, de forma simplificada, se ejecuta
mediante el intercambio entre trenes, de las rutas que realizan en un mismo día. Es decir, dentro de
un mismo día, se escoge la ruta realizada por un tren cualquiera y se intercambiará la asignación de
tal ruta con otro tren, tomando la ruta que realiza este segundo tren.
El procedimiento de mutación diseñado para un individuo, o sea, solución del problema, se realiza
en dos pasos:
1. En primer lugar se determina de forma aleatoria el número de días que se van a considerar
en la mutación. Para evitar el total cambio del individuo, se podrán realizar cambios en,
cómo máximo, la mitad de los días que se consideran en el sistema. Posteriormente se
seleccionan de forma aleatoria qué días serán los que foran parte del proceso.
2. Se define aleatoriamente cuantos intercambios se van a realizar dentro de cada día. Para
evitar de nuevo el cambio total del individuo, se podrán realizar como máximo,
combinaciones con la mitad de los trenes del sistema. Posteriormente se eligen entre qué
trenes habrá intercambio de rutas, en cada día.
Estas mutaciones se crean en la función Mutacion(MUTS, Num_Dias, Num_Lineas,
TOTAL_Trenes, CV, CD) del código del ANEXO II.
6. Creación de nuevos individuos.
Padres2 Madres2
1 16
2 17
… …
15 30 Tabla 4. Combinación de Individuos Reproductores.
47
En esta fase se cruzan los individuos reproductores de la generación actual, y se crean los individuos
nuevos de la generación posterior. Aquí cada Familia reproductora se combina de varias formas,
creando soluciones nuevas.
Se ha diseñado seis tipos de combinaciones para la creación de individuos nuevos. Estas
combinaciones se exponen a continuación:
1. La planificación del nuevo individuo será igual al ‘Padre’ en la primera mitad de los días
considerados, y será igual a la ‘Madre’ en la segunda mitad de los días considerados. Se
puede entender de forma más simple con un ejemplo gráfico:
Figura 8. Representación Gráfica Combinaión 1.
Estos individuos se crearán en la función Combinar1(Padres, Madres, TOTAL_Trenes,
RUTAS, DIST, Num_Lineas, Num_Dias, CV, CD) del código del ANEXO II.
2. La planificación del nuevo individuo será igual a la ‘Madre’ en la primera mitad de los días
considerados, y será igual al ‘Padre’ en la segunda mitad de los días considerados.
Figura 9. Representación Gráfica Combinación 2.
Estos individuos se crearán en la función Combinar2(Padres, Madres, TOTAL_Trenes,
RUTAS, DIST, Num_Lineas, Num_Dias, CV, CD) del código del ANEXO II.
Individuo
‖
‖
Padre
Madre
Individuo
‖
‖
Padre
Madre
3. La planificación del nuevo individuo será igual al ‘Padre’ en el primer y último tercio de
los días considerados, y será igual a la ‘Madre’ en el segundo tercio de los días
considerados.
Figura 10. Representación Gráfica Combinación 3.
Estos individuos se crearán en la función Combinar3(Padres, Madres, TOTAL_Trenes,
RUTAS, DIST, Num_Lineas, Num_Dias, CV, CD) del código del ANEXO II.
4. La planificación del nuevo individuo será igual a la ‘Madre’ en el primer y último tercio de
los días considerados, y será igual al ‘Padre’ en el segundo tercio de los días considerados.
Figura 11. . Representación Gráfica Combinación 4.
Estos individuos se crearán en la función Combinar4(Padres, Madres, TOTAL_Trenes,
RUTAS, DIST, Num_Lineas, Num_Dias, CV, CD) del código del ANEXO II.
5. La planificación del nuevo individuo será igual al ‘Padre’ en el primer y tercer cuarto de
los días considerados, y será igual a la ‘Madre’ en el segundo y último cuarto de los días
considerados.
Figura 12.. Representación Gráfica Combinación 5.
Estos individuos se crearán en la función Combinar5(Padres, Madres, TOTAL_Trenes,
RUTAS, DIST, Num_Lineas, Num_Dias, CV, CD) del código del ANEXO II.
Individuo
‖
‖
Madre
Padre
Individuo
‖
‖
Padre
Madre
Individuo
‖
‖
Padre
Madre
49
6. La planificación del nuevo individuo será igual al ‘Madre’ en el primer y tercer cuarto de
los días considerados, y será igual a la ‘Padre’ en el segundo y último cuarto de los días
considerados.
Figura 13. . Representación Gráfica Combinación 6.
Estos individuos se crearán en la función Combinar6(Padres, Madres, TOTAL_Trenes,
RUTAS, DIST, Num_Lineas, Num_Dias, CV, CD) del código del ANEXO II.
Cada tipo de combinación resulta en un solo individuo. En el algoritmo, todas las parejas que forman
las dos familias se combinan de las seis formas anteriormente expuestas. De modo que, cada una de
las parejas de individuos reproductores tendrán seis ‘hijos’ o individuos que han sido creados a partir
de ellos.
Por tanto, el tamaño de población se define con la siguiente ecuación:
𝑃𝑜𝑏 = 3 ∗ 𝑆𝐸𝐿 + 𝑀𝑈𝑇
7. Unificación de nueva generación.
Finalmente, tras la creación de los nuevos individuos, y la mutación de los individuos seleccionados
de la generación anterior, se puede crear la nueva generación. Se une los individuos nuevos
formados a partir de las Familias de individuos reproductores de la generación anterior, que
representan 3*SEL individuos de la nueva generación, a los que se unirán los individuos mutados,
conformando de nuevo una población con Pob individuos,
Se termina por tanto con la generación cde una nueva población con el mismo tamaño que la inicial
(o que la anterior).
8. Análisis de los individuos de la generación.
La última fase del algoritmo es dónde se analizan las soluciones encontradas tras el proceso de
selección natural y mutación, y se estudia si se ha encontrado una solución óptima del problema. Se
trata de la fase que se podría llamar Decisiva, pues es donde se decide si se continua o se para el
algoritmo.
Este análisis se ejecuta buscando el individuo cuya función objetivo sea el menor. Cuando se
encuentra, se guarda y renombra esta solución como la solución IDEAL.
El mejor individuo se guarda en una lista llamada MeM en el código del ANEXO II. Esta lista de
memoria guarda el mejor individuo de cada generación. Esto se hace, pues cabe la posibilidad que,
en una iteración el algoritmo, el ideal de la generación nueva sea peor que el del anterior.
El valor de la F.O. de la solución IDEAL se compara con el valor guardado en la variable MIN.
Si el valor de la función objetivo de la solución IDEAL es mayor que MIN, entonces se repiten las
fases 3 al 8 del algoritmo, usando como generación inicial, aquella creada en la iteración que se
acaba de terminar.
En el caso en que la función objetivo IDEAL se menor que MIN, se pasa a la fase 9.
Individuo
‖
‖
Madre
Padre
Es posible que las diferentes soluciones en la lista IDEAL san peores que la mejor (MIN). Si esta
situación se repite, se aplicará un segundo critreio de parada. Si se han creado NGen generaciones
sin llegar a una solución con valor de F.O. menor que MIN, entonces se pasa a la fase 9. NGen será
decidido por el usuario del programa.
9. Comparación final de resultados.
El algoritmo genético, tras la fase 9, ha terminado. Sin embargo, es posible que el algoritmo genético
se quede atrapado en una solución óptima local, y que una solución mejor puede ser alcanzado. Para
evitar esto, se ha introducido un bucle para lanzar varias veces el algortimo genético.
Al llegar al final de la fase 8, se termina de generar una nueva generación, donde IDEAL es la mejor
solución. El valor de la función objetivo de esta solución se compara con el parámetro de parada,
que es un valor MIN (o minimo inicial si es la primera iteración):
1. Si todavía no se han creado NGEN generaciones en la iteración actual del AG:
a. Si MIN es mayor que el valor de la función objetivo de IDEAL: el nuevo mínimo es este
valor de F.O., el algoritmo termina y se realiza otra iteración del AG.
b. En caso contrario, si MIN es mayor que el valor de la F.O. de IDEAL, MIN se mantiene y
se crea otra generación.
2. Si se han creado NGEN generacioens en la iteración acutal del AG, se termina el algortimo, y
se realiza otra iteración del AG. Esto puede indicar dos situaciones posibles.
I. La solución cuyo valor de función objetivo se ha estipulado como el límite mínimo del
algoritmo genético es, efectivamente la solución óptima global, y por tanto, no se puede
mejorar el resultado de la función objetivo.
II. El algoritmo simplemente no ha sido capaz de encontrar una solución mejor.
Ya que no es posible saber en qué caso se encuentra el algoritmo global, se debe de realizar
varias iteraciones.Este número de iteraciones se guarda en una variable llamada IT, y será diez
veces el número de días en el conjunto D del problema a resolver.
Cuando terminen todas estas iteraciones, se tiene la mejor solución encontrada por el algoritmo
genético a lo largo de todas esas iteraciones.
Al final del programa se crea una hoja de cálculo donde se exponen los datos que definen la solución
ideal. Las instrucciones de lectura de información de esta hoja de cálculo se pueden encontrar en el
ANEXO VI.
Se ha creado una gráfica para facilitar la comprensión del algoritmo, mostandro el algoritmo genético y el
bucle exterior que lo lanza varias veces, y las condiciones y acciones que la definen:
6 EJEMPLOS
6.1 Ejemplo 1
El primer ejemplo trata una red muy simple, con dos líneas que se cruzan (la línea 1 es la línea roja. La línea
2 es la azul), y donde sólo se consideran dos días en el conjunto D, que se repite consecutivamente a lo largo
del horizonte temporal. Se puede ver una representación gráfica de esta red simple a continuación:
Figura 15. Representación Gráfica de la Red Ferroviaria del Ejemplo 1.
Las distancias, en kilómetros, entre estaciones de la red del ejemplo 1 son las siguientes:
Tabla 5. Distancias entre Estaciones del Sistema del Ejemplo 1.
Las rutas que satisfacen los horarios preestablecidos se pueden ver expresadas en la siguiente tabla:
Tabla 6. Información de Rutas del Ejemplo 2.
L1E1 L1E2 L2E1 L2E2
L1E1 0 20 15 20
L1E2 20 0 15 20
L2E1 15 15 0 15
L2E2 15 20 15 0
Inicio 1 0 1 0 1 0 1 0 0 1
Fin 1 0 0 1 0 1 1 0 1 0
Km
Línea 2
Día2
Rutas
75
Ruta 1 Ruta 1
80 60 75 80
Ruta 1
Día1
Línea 1 Línea 2 Línea 1
Ruta 1 Ruta 2
53
Figura 16. Representación gráfica de rutas de la red ferroviaria del Ejemplo 1.
Se ha considerado un horizonte temporal de 25 años. El coste de construir un depósito se ha estimado en:
1000000€/depósito. El coste de viajar un kilómetro en vacío, es decir, sin carga/pasajeros, se ha estimado en
40€/km. El peso del equilibrio se ha dado como valor 1, o sea, no se cambia el valor natural del equilibrado
frente a los costes.
6.1.1 Aplicación de Modelo Matemático:
El modelo ha explorado una serie de soluciones
posibles, que rápidamente han ido
convergiendo en un valor mínimo de la función
objetivo. Esta evolución se muestra en la
siguiente gráfica:
Se puede observar cómo, en el inicio, el
modelo encuentra soluciones “malas” por su
alto valor de función objetivo, pero en poco
tiempo y en pocas iteraciones, converge en una
solución óptima.
Este proceso se realiza en unos 0.09 segundos.
Este tiempo es prácticamente despreciable, y se
puede decir que se realiza de forma cuasi-
instantáneo.
6.1.1.1 Solución
La solución obtenida por el modelo matemático es la siguiente.
XRtdlr XDep_itdle_ic XDep_ftdle_ic
xr.1.1.1.1 1 Xdi.1.1.11..11 1 Xdi.1.1.11..11 1
Nº de
Depósitos:
Coste de
Construcción:
Coste Semanal (2 días)
de Operación:
Coste de Operación
TOTAL:
Número Total de
trenes necesarios:
3 Depósitos 3.000.000 € 800 €/Semana 3.65x 106 € 3 Trenes
0
5000000
10000000
15000000
20000000
25000000
30000000
1 2 3 4 5 6 7 8 9 10
Fun
ció
n O
bje
tivo
Nodos encontrados
Figura 17. Gráfica de Valores Función Objetivo en cada nodo encontrado
por el Modelo Matemático
Xr.1.2.1.1 1 Xdi.1.2.11..11 1 Xdi.1.2.11..11 1
Xr.2.1.2.1 1 Xdi.2.1.21..21 1 Xdi.2.1.22..22 1
Xr.2.2.2.1 1 Xdi.2.2.22..22 1 Xdi.2.2.21..21 1
Xr.3.1.1.2 1 Xdi.3.1.11..11 1 Xdi.3.1.12..11 1
Xdi.3.2.11..11 1 Xdi.3.2.11..11 1
Recorridos (2 días) Tren 1 Tren 2 Tren 3
Km en Vacío 0 0 20
Km Totales 160 150 80
Tabla 7. Resultados de Modelo Matemático Ejemplo 1.
Estos resultados se pueden ver expuestos en la siguiente representación gráfica:
Figura 18. Asignación de Rutas de la Solución del Modelo Matemático del Ejemplo 1.
Se puede concluir que el modelo matemático ha sido capaz de encontrar la solución óptima global a este
problema, en un tiempo prácticamente instantáneo. Esto lleva a pensar que el modelo matemático es, para
empezar muy buen recurso para resolver este tipo de problema. Sin embargo, habrá que compararlo con el
algoritmo genético.
XVtdle_ic
Xv.3.2.11..11 1
Ale
A.1.1 1
A.2.1 1
A.2.2 1
55
6.1.2 Aplicación de Algoritmo Genético:
El algoritmo genético, como se explicó en
el apartado 5, crea un grupo inicial,
aleatorio, de soluciones posibles. Se eligen
las mejores de estas, y se combinan, para
crear nuevas soluciones. En la figura 18
primera gráfica se puede ver el valor de la
FO de la mejor solución de cada
generación creada. Cómo se puede ver, el
algoritmo encuentra gran cantidad de
soluciones, pero finalmente sólo
seleccionará la mejor de todas estas.
La línea roja muestra el valor de la solución
que se ha guardado como mejor tras cada
iteración. Se puede discernir, que el
algoritmo encuentra una buena solución
muy pronto. Sin embargo, debido a que el
algoritmo sólo se para cuándo se llegue a
un límite que está en función del tamaño de
problema y no de las soluciones
encontradas, el programa sigue buscando soluciones, aunque haya encontrado ya una solución
aparentemente óptima.
Este proceso se realiza en unos 24.81 segundos. Es un tiempo reducido, pero comparado con el modelo
matemático que encuentra la solución de forma cuasi-instantánea, es un tiempo muy elevado para el tamaño
de problema.
Sin embargo, se debe estudiar la solución encontrada por el algoritmo, antes de poder comparar las dos
metodologías, aplicadas a este ejemplo.
6.1.2.1 Solución
La solución obtenida por el algoritmo genético es la siguiente:
Asignación de Rutas
Tren 1 Tren 2 Tren 3
Día 1 Día 2 Día 1 Día 2 Día 1 Día 2
Ruta 2 0 1 1 1 1
Línea 1 0 1 1 2 2
Nº de
Depósitos:
Coste de
Construcción:
Coste Semanal (2
días) de Operación:
Coste de
Operación
TOTAL:
Número Total de
trenes necesarios:
2 Depósitos 2.000.000 € 2.400 €/Semana 1.095 x 107 € 2 Trenes
Gráfica x. Valores de FO durante resolución de Ejemplo 1
aplicando el algoritmo genético.
Figura 19. Gráfica de Valores de función obetivo de cada solución ideal
de cada generación creada por el algoritmo genético.
Uso de Depósitos
Tren 1 Tren 2 Tren 3
Día 1 Día 2 Día 1 Día 2 Día 1 Día 2
E1 E2 E1 E2 E1 E2 E1 E2 E1 E2 E1 E2
Línea 1 1 0 0 0 1 0 1 0 0 0 0 0
Línea 2 0 0 1 0 0 0 0 0 1 0 1 0
Recorridos (2 días) Tren 1 Tren 2 Tren 3
Km en Vacío 30 0 30
Km Totales 90 160 180
Tabla 8. Resultados de Algoritmo del Ejemplo 1.
Estos resultados se pueden ver expuestos en la siguiente representación gráfica:
Figura 20. Asignación de Rutas de la Solución del Algoritmo del Ejemplo 1.
Comparando con la solución del modelo matemático, que es la solución óptima global, se entiende que el
algoritmo ha encontrado un óptimo local. Esto se observa en el hecho de que el coste de operación y de
construcción es mayor en la solución encontrada por el algoritmo que en aquella encontrada por el modelo
matemático.
Parece que, tanto por eficiencia de tiempo y calidad de solución, el modelo matemático es mejor que el
algoritmo a la hora de resolver este problema de asignación de rutas y localización de depósitos de un sistema
ferroviario. No obstante, este ejemplo es un caso muy simple, y con unas dimensiones muy pequeñas. Será
necesario probar ambas metodologías en casos más grandes y complejos, antes de llegar a alguna conclusión
definitiva.
57
6.2 Ejemplo 2
El segundo ejemplo se trata de una red más compleja, con tres líneas. Tiene dos líneas que comparten una
estación 2 (Línea 1, rojo y Línea 3, verde) y otra línea que cruza esta estación compartida (Línea 2, azul). En
este caso se consideran 3 días en el conjunto D, que se repite consecutivamente a lo largo del horizonte
temporal. Se puede ver una representación gráfica de esta red simple a continuación:
Figura 21. Representación Gréfia de la Red Ferroviaria del Ejemplo 2.
Las distancias, en kilómetros, entre estaciones de la red del ejemplo 2 son las siguientes:
Tabla 9. Distancias entre Estaciones del Sistema del Ejemplo 2.
Las rutas que satisfacen los horarios preestablecidos se pueden ver expresadas en las siguientes tablas:
L1E1 L1E2 L2E1 L2E2 L3E1 L3E2
L1E1 0 15 25 30 30 15
L1E2 15 0 10 15 15 0
L2E1 25 10 0 25 25 10
L2E2 30 15 25 0 30 15
L3E1 30 15 25 30 0 15
L3E2 15 0 10 15 15 0
Linea 1 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 1 1 60
Ruta 2 1 2 45
Ruta 3 1 2 45
Linea 2 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 1 2 75
Ruta 2 2 1 75
Linea 3 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 2 2 75
DIA 1
Tabla 10. Información de Rutas del Ejemplo 2.
Estas rutas se representan de forma gráfica a continuación
Tabla 11. Representación Gráfica de Rutas del Sistema del Ejemplo 2.
Se ha considerado un horizonte temporal de 25 años. El coste de construir un depósito se ha estimado en:
1000000€/depósito. El coste de viajar un kilómetro en vacío, es decir, sin carga/pasajeros, se ha estimado en
Linea 1 Estacion InicioEstación Fin Kilometros Recorridos
Ruta 1 1 1 60
Ruta 2 1 2 45
Linea 2 Estacion InicioEstación Fin Kilometros Recorridos
Ruta 1 1 2 75
Ruta 2 2 1 75
Linea 3 Estacion InicioEstación Fin Kilometros Recorridos
Ruta 1 2 2 75
Ruta 2 1 1 75
DIA 2
Linea 1 Estacion InicioEstación Fin Kilometros Recorridos
Ruta 1 1 1 60
Linea 2 Estacion InicioEstación Fin Kilometros Recorridos
Ruta 1 1 2 75
Ruta 2 2 1 75
Linea 3 Estacion InicioEstación Fin Kilometros Recorridos
Ruta 1 2 2 75
DIA 3
59
40€/km. El peso del equilibrio se ha dado como valor 1, o sea, no se cambia el valor natural del equilibrado
frente a los costes.
6.2.1 Aplicación de Modelo Matemático:
Al igual que en el ejemplo 1, el modelo rápidamente han ido convergiendo a un valor mínimo de la función
objetivo. Esta evolución se muestra en la siguiente gráfica:
Este proceso se realiza en unos 16.33 segundos. Se puede observar, que al aumentar el tamaño del problema,
el tiempo de resolución ha aumentado considerablemente, comparado con el sistema simple del ejemplo 1.
6.2.1.1 Solución
La solución obtenida por el modelo matemático es la siguiente.
XRtdlr XDep_itdle_ic XDep_ftdle_ic
Xr.1.1.1.1 1 Xdi.1.1.11..11 1 Xdf.1.1.11..11 1
Xr.1.2.1.1 1 Xdi.1.2.11..11 1 Xdf.1.2.11..11 1
Xr.1.3.1.1 1 Xdi.1.3.11..11 1 Xdf.1.3.11..11 1
Xr.2.1.3.1 1 Xdi.2.1.32..32 1 Xdf.2.1.32..32 1
Nº de
Depósitos:
Coste de
Construcción:
Coste Semanal (3
días) de Operación:
Coste de
Operación
TOTAL:
Número Total de
trenes necesarios:
4 Depósitos 4.000.000 € 4.600 €/Semana 1.4 x107 € 6 Trenes
0
10000000
20000000
30000000
40000000
50000000
60000000
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Fun
ció
n O
bje
tivo
Nodos encontrados
Figura 22. Gráfica de Valores Función Objetivo en cada nodo encontrado por el Modelo
Matemático
Xr.2.2.3.2 1 Xdi.2.2.32..31 1 Xdf.2.2.31..32 1
Xr.3.1.1.2 1 Xdi.2.3.32..12 1 Xdf.2.3.12..32 1
Xr.3.2.2.1 1 Xdi.3.1.11..11 1 Xdf.3.1.12..21 1
Xr.3.3.2.2 1 Xdi.3.2.21..21 1 Xdf.3.2.22..22 1
Xr.4.1.2.1 1 Xdi.3.3.22..22 1 Xdf.3.3.21..11 1
Xr.4.2.2.2 1 Xdi.4.1.21..21 1 Xdf.4.1.22..22 1
Xr.5.1.2.2 1 Xdi.4.2.22..22 1 Xdf.4.2.21..21 1
Xr.5.2.1.2 1 Xdi.4.3.21..21 1 Xdf.4.3.21..21 1
Xr.5.3.2.1 1 Xdi.5.1.22..22 1 Xdf.5.1.21..21 1
Xr.6.1.1.3 1 Xdi.5.2.21..11 1 Xdf.5.2.12..32 1
Xr.6.2.3.1 1 Xdi.5.3.32..21 1 Xdf.5.3.22..22 1
Xr.6.3.3.1 1 Xdi.6.1.11..11 1 Xdf.6.1.12..32 1
Xdi.6.2.32..32 1 Xdf.6.2.32..32 1
Xdi.6.3.32..32 1 Xdf.6.3.32..11 1
Recorridos (3 días) Tren 1 Tren 2 Tren 3 Tren 4 Tren 5 Tren 6
Km en Vacío 0 30 35 0 35 15
Km Totales 180 180 230 150 230 210
Tabla 12. Resultados del Modelo Matemático del Ejemplo 2.
XVtdle_ic
Xv.2.3.12..12 1
Xv.4.3.21..21 1
Ale
A.1.1 1
A.2.1 1
A.2.2 1
A.3.2 1
61
Estos resultados se pueden ver expuestos en la siguiente representación gráfica:
Figura 23. Asignación de Rutas del Sistema del Ejemplo 2.
6.2.2 Aplicación de Algoritmo Genético:
En este segundo ejemplo, el algoritmo
llega a una muy buena solución muy
pronto. Tras varias generaciones,
encuentra soluciones mínimamente
mejores. Se puede observar que, al igual
que en el ejemplo 1, el algoritmo
examina un gran número de soluciones
posibles, guardando las mejores.
El algoritmo tarda 63.306 segundos en
completarse. Este tiempo mayor que
aquel necesario para el modelo
matemático. Esto sigue siendo
considerablemente peor que el modelo.
Sin embargo, habrá que examinar
también la calidad de solución del
algoritmo, para poder comparar
completamente ambos procedimientos.
6.2.2.1 Solución
La solución obtenida por el algoritmo genético es la siguiente:
En la solucio n encontrada, los depo sitos se encuentran en la estacio n 2 de la lí nea 1 y en la estacio n 2 de la lí nea 3. Sin embargo, como en la realidad representan la misma estacio n fí sica, so lo se computa como un u nico depo sito.
Nº de
Depósitos:
Coste de
Construcción:
Coste Semanal (2 días)
de Operación:
Coste total
de Operativo
Número Total de
trenes necesarios:
1 Depósitos 1.000.000 € 12,600 €/Semana 3.83 x107 € 6 Trenes
Figura 24. Gráfica de Valores de función obetivo de cada solución ideal de
cada generación creada por el algoritmo genético
Asignación de Rutas
Tren 1 Tren 2 Tren 3
Día 1 Día 2 Día 3 Día 1 Día 2 Día 3 Día 1 Día 2 Día 3
Ruta 1 1 1 1 2 0 2 2 1
Línea 1 1 2 3 3 0 2 2 3
Tren 4 Tren 5 Tren 6
Día 1 Día 2 Día 3 Día 1 Día 2 Día 3 Día 1 Día 2 Día 3
Ruta 1 1 2 2 2 0 2 2 0
Línea 2 3 2 1 1 0 1 1 0
Uso de DEPOSITOS
Tren 1 Tren 2
Día 1 Día 2 Día 3 Día 1 Día 2 Día 3
E1 E2 E1 E2 E1 E2 E1 E2 E1 E2 E1 E2
Línea 1 0 1 0 1 0 0 0 0 1 0 1 0
Línea 2 0 0 0 0 0 0 0 0 0 0 0 0
Línea 3 0 0 0 0 0 1 0 1 0 0 0 0
Tren 3 Tren 4
Día 1 Día 2 Día 3 Día 1 Día 2 Día 3
E1 E2 E1 E2 E1 E2 E1 E2 E1 E2 E1 E2
Línea 1 0 0 1 0 1 0 1 0 0 0 0 0
Línea 2 0 0 0 0 0 0 0 0 0 0 0 0
Línea 3 0 1 0 0 0 0 0 0 0 1 0 1
Tren 5 Tren 6
Día 1 Día 2 Día 3 Día 1 Día 2 Día 3
63
Recorridos (3 días) Tren 1 Tren 2 Tren 3 Tren 4 Tren 5 Tren 6
Km en Vacío 85 30 50 50 30 70
Km Totales 280 180 275 275 120 250
Tabla 13. Resultados del Algoritmo del Ejemplo 2.
Estos resultados se pueden ver expuestos en la siguiente representación gráfica:
Figura 25. Asignación de Rutas del Algorimo del Ejemplo 2.
Comparando los resultados del algoritmo con las del modelo matemático, se puede discernir que, de nuevo,
el modelo matemático ha sido capaz de encontrar la solución óptima global, mientras que el algoritmo se ha
quedado en una solución óptima local. Además, el modelo ha logrado encontrar una solución en un tiempo
mucho más corto que algoritmo.
Parece que, viendo los resultados de los ejemplos 1 y 2, el modelo matemático es mejor para la solución de
este problema que el algoritmo genético diseñado para resolverlo. Sin embargo, el ejemplo 2, aun siendo un
problema con mayor dimensión que el primer ejemplo ejecutado, sigue sin ser un sistema real.
Con la meta de llegar a una conclusión final sobre la efectividad y eficiencia de la meta-heuristica del
algoritmo genético frente al modelo matemático, se realiza un último ejemplo: la Red de Cercanías de
Sevilla.
E1 E2 E1 E2 E1 E2 E1 E2 E1 E2 E1 E2
Línea 1 1 0 0 0 0 0 0 1 0 1 0 0
Línea 2 0 0 0 0 0 0 0 0 0 0 0 0
Línea 3 0 0 0 1 0 1 0 0 0 0 0 1
6.3 Red de Cercanías de Sevilla
Como se ha visto en los ejemplos anteriores, tanto el modelo matemático como el algoritmo meta heurístico
llegan a soluciones admisibles, aunque el modelo parece ser más efectivo a la hora de encontrar la solución
óptima del problema. Sin embargo, se trata de ejemplos muy pequeños, simples e imaginariaos. Ya que estas
soluciones se quieren aplicar contra sistemas ferroviarios reales, se tendrá que probar su eficiencia y
efectividad con un sistema real de mayor dimensión.
Se ha elegido el sistema de cercanías de Sevilla. Esto se debe a varias razones. La primera es la naturaleza
del sistema. Es una red real, pero relativamente pequeña comparada con otros sistemas de España, como los
de las ciudades de Madrid o Barcelona, lo que facilita la codificación de datos y resultados. Además, el
problema de planificación de rutas para satisfacer los horarios previamente definidos para la red de cercanías
de Sevilla ya ha sido resuelto en el Proyecto de A. Téllez [1], que ha sido previamente citado. Todo esto
convierte la red de Sevilla como una opción ideal para usar como ejemplo real a la hora de estudiar la
eficiencia y efectividad del modelo matemático y el algoritmo meta heurístico diseñado para el problema
de asignación de rutas y localización de depósitos.
La red de cercanías de Sevilla consiste de 5 líneas llamadas C1, C2, C3, C4 y C5. Las líneas C2, C3 y C5
parten de la Estación Santa Justa y van hasta La Cartuja, Cazalla y Benacazón respectivamente. La línea C4
es circular, pasando siempre por la Estación de Santa Justa. La línea C1 parte de Lora de Río, pasa por la
Estación Santa Justa y termina en Lebrija.
Figura 26. Representación Gráfica de la Red de Cercanías de Sevilla
65
Para la aplicación del modelo matemático y el algoritmo meta-heurístico se ha redefinido la red para poder
simplificar la codificación de datos y resultados.
- Línea C1: Esta línea, aunque es físicamente una sola, se puede dividir en dos, ya que hay
horarios que parten de la estación intermedia de Santa Justa, y van a sus respectivas estaciones
límites y vuelven a la estación Santa Justa. Por tanto, se dividirá la línea C5 en las líneas 5 y 6.
La línea 5 será aquella que tiene como estación 1 la Estación Santa Justa y estación 2 la de
Lora del Rio. La otra mitad de la línea, que tiene como estación 1 la Estación de Santa Justa y
como estación 2 la de Lebrija, contiene un gran número de servicios, y rutas, lo que, a efecto
del objetivo de presente trabajo, complica enormemente la introducción de datos.
- Línea C2: Esta línea será nombrada Línea 2 de ahora en adelante. Su estación 1 es la Estación
de Santa Justa y su estación 2 es Cartuja.
- Línea C3: A partir de ahora, la Línea C3 será nombrada Línea 3. Su estación 1 es la Estación
de Santa Justa, y su estación 2 será Cazalla.
- Línea C4: La línea C4, ahora nombrada simplemente Línea 4, tendrá como estaciones límite,
la Estación de Santa Justa. Sin embargo, aunque sean físicamente la misma estación, se
definirán dos diferentes estaciones para esta línea (E1,E2) que estarán a 0km de distancia. Esta
diferenciación de estaciones permite que una ruta pueda incluir un cambio de sentido.
- Línea C5: Esta línea será denominada Línea 5 de ahora en adelante. Su estación 1 es la
Estación de Santa Justa y su estación 2 es Benacazón.
A continuación se puede ver una representación gráfica de la red simplificada:
Figura 27. Red de Cercanías de Sevilla Simplificada
Las distancias, en kilómetros, entre estaciones de la Red de Sevilla son las siguientes:
Tabla 14. Distancias entre Estaciones de la Red de Cercanías de Sevilla.
Las rutas que satisfacen los horarios preestablecidos se pueden ver expresadas en el Anexo III.
Se ha considerado un horizonte temporal realista para una inversión en la instalación y operación de un
sistema ferroviario en la realidad; en este caso, se ha tomado un horizonte de 25 años.
Se ha considerado un horizonte temporal de 25 años. El coste de construir un depósito se ha estimado en:
1000000€/depósito. El coste de viajar un kilómetro en vacío, es decir, sin carga/pasajeros, se ha estimado en
40€/km. El peso del equilibrio se ha dado como valor 1, o sea, no se cambia el valor natural del equilibrado
frente a los costes.
6.3.1 Aplicación del Modelo Matemático
Se ha tratado de resolver el problema de asignación de rutas y localización de rutas para la Red de Cercanías
de Sevilla, usando Gurobi a partir del modelo de programación mixta-entera.
El modelo, tras varias horas de búsqueda, no ha sido capaz de encontrar soluciones admisibles de calidad.
Esto se debe a que, a diferencia de los ejemplos iniciales, la red de Sevilla supone un problema de
dimensiones considerablemente mayores.
Por tanto, se puede llegar a la conclusión de, aunque efectivo y eficiente con sistemas simples y de
dimensiones relativamente pequeñas, el modelo matemático aplicado a sistemas reales, que suponen una
mayor complejidad y dimensión de problema, no es efectivo ni eficiente en la búsqueda de soluciones.
Habrá que estudiar los resultados del algoritmo genético aplicado al mismo problema para comprobar si este
es capaz de encontrar una solución buena y válida para sistemas reales, complejos, y de dimensiones
elevadas.
6.3.2 Aplicación de Algoritmo Genético
Se ha aplicado el algoritmo diseñado para el problema de asignación de rutas y localización de depósitos a
la Red de Cercanías de Sevilla, tal y como se ha definido en apartados anteriores. El algoritmo ha encontrado
una solución válida y relativamente buena en 22 minutos y 9 segundos aproximadamente.
Considerando que el modelo mático no ha sido capaz de terminar de encontrar una solución tras varias horas
de funcionamiento, el tiempo usado por el algoritmo genético ajustado se puede considerar muy reducido.
En la gráfica siguiente se ven todos los valores ideales de cada una de las generaciones creadas a lo largo de
la ejecución del algoritmo. Observando la línea roja, el algoritmo ha encontrado cinco buenas soluciones,
siendo la última la mejor de ellas.
L1E1 L1E2 L2E1 L2E2 L3E1 L3E2 L4E1 L4E2 L5E1 L5E2
L1E1 0 66 0 0 0 78 0 33 0 5
L1E2 66 0 66 76 66 144 66 99 66 71
L2E1 0 66 0 0 0 78 0 33 0 5
L2E2 0 76 0 0 0 88 0 43 0 15
L3E1 0 66 0 0 0 78 0 33 0 5
L3E2 78 144 78 88 78 0 78 111 78 83
L4E1 0 66 0 0 0 78 0 33 0 5
L4E2 33 99 33 43 33 111 33 0 33 38
L5E1 0 66 0 0 0 78 0 33 0 5
L5E2 5 71 5 15 5 83 5 38 5 0
67
Figura 28. Gráfica de Valores de función obetivo de cada solución ideal de cada generación creada por el algoritmo genético para
la Red de Cercanías de Sevilla.
La naturaleza del algoritmo genético causa que puede haber momentos donde, en vez de verse mejorado la
generación, se propagan malas cualidades. El algoritmo imita el fenómeno natural de la evolución genética
de especies en la naturaleza. Es relativamente común que en una población exista un caulidad no deseada
(p.ej. una malformación, una mutación degenerativa) que se propague y afecte a muchos individuos. Sin
embargo, se ha podido obervar cómo la naturaleza es capaz de eliminar estas cualidades malas de la
pobablión, dado suficiente tiempo.
En el caso del algoritmo genético, estas cualidades malignas, o no deseadas, se observan en la forma de
valores de función objetivo elevados. Este suceso de propagación de cualidades malignas se puede observar
en la zona de la gráfica rodeada en verde. También se puede observar que, al igual que en la naturaleza, el
algoritmo ha sido capaz de eventualmente corregirse, eliminando estas cualidades malignas, y encontrando
solcuiones buenas.
Finalmente, se puede decir que el algoritmo ha sido efectivo encontrando una solución buena en un tiempo
razonable. Aunque la solución encontrada posiblemente no sea el óptimo global, es lógico aceptar que, en
una situación realista, donde se dispone de tiempo limitado, el algoritmo funciona bien a la hora de encontrar
soluciones buenas.
La solución encontrada para la Red de Sevilla con los parámetos de horizonte temporal, coste de inversión
y de operación y tamaño de población, se resume a continuación:
Nº de
Depósitos:
Coste de
Construcción:
Coste Semanal (2
días) de Operación:
Coste de Operación
TOTAL:
Número Total de
trenes necesarios:
1 Depósitos 1.000.000 € 145560 €/Semana 1.897x 108 € 18 Trenes
Tabla 15. Resultados de Costes de Red de Cercanías de Sevilla
En el conjunto de Asignación de Depósitos en la solución encontrada por el algoritmo, las estaciones del
sistema que son depósitos son las siguientes:
1. Línea 1, Estación 1.
2. Línea 2, Estación 1.
3. Línea 3, Estación 1.
4. Línea 4, Estación 1.
5. Línea 5, Estación 1.
Estas estaciones, aunque diferentes a la hora de introducirlos en el programa, representan el mismo lugar
físico, la Estación de Santa Justa. Por tanto, en la solución encontrada, sólo hay un depósito en la Red de
cercanías de Sevilla, y se encuentra en la Estación de Santa Justa. Esto, lógicamente, implica que el coste de
contrucción de depósitos es 1000000€.
Las distancias recorridas por cada una de los 18 trenes necesarios para la realización de todas las rutas del
sistema de la Red de Cercanías de Sevilla son las siguientes:
Tabla 16. Kilómetros recorridos en una semana por los trenes de la Red de Cercanías de Sevilla.
Como se puede observar, las distancias recorridas por el material rodante, aunque no iguales, están bastante
equilibradas. La máxima distancia recorrida es de 3512 kilómetros y la mínima de 1392 kilómetros. Además,
ya que se tiene la asignación de trenes semanal, se podrá realizar una rotación del material rodante,
minimizando el desgaste de dicho material; es decir, el material rodante que trabaja como tren ‘t1’ en una
semana del horizonte temporal puede ser rotado a la planificación de otro tren ‘t2’ para, de esta forma,
equilibrar las distancias a lo largo de todo el horizonte temporal. Es decir, la planificación de trenes fija las
rutas que debe hacer el material rodante dentro de una misma semana, pero el material rodante puede cambiar
(rotarse) en semanas consecutivas
La planificación de rutas semanal se muestra a continuación:
Tren Tren 1 Tren 2 Tren 3 Tren 4 Tren 5 Tren 6
Recorrido en Vacio 274 154 165 297 180 187
Recorrido Total 2342 2102 2290 3630 2432 1774
Tren Tren 7 Tren 8 Tren 9 Tren 10 Tren 11 Tren 12
Recorrido en Vacio 170 378 428 170 119 286
Recorrido Total 2090 3512 2680 2499 1728 1766
Tren Tren 13 Tren 14 Tren 15 Tren 16 Tren 17 Tren 18
Recorrido en Vacio 156 142 189 81 144 119
Recorrido Total 1392 2430 2204 3165 2844 1868
69
Tabla 17. Asignación de Rutas de la Red de Cercanías de Sevilla.
La asignación de ruta del tipo [0,0] corresponde a que el tren no realiza ninguna ruta. Si se produce cambio
en la asignación de depósitos se trataría de rutas en vacío. Sin embargo, en la realidad de esta solución, ya
que todos los trenes usan un mismo depósito localizado en la Estación de Santa Justa, estas rutas vacías no
representan ningún traslado real; son sólo una herramienta imaginaria para permitir que el programa
mantenga la continuidad temporal y espacial de la solución.
1 2 3 4 5 6 7 8 9
1 [2, 5] [1, 5] [5, 5] [1, 4] [4, 1] [2, 3] [5, 1] [6, 5] [1, 1]
2 [3, 4] [5, 1] [3, 5] [1, 1] [6, 1] [4, 5] [6, 5] [1, 4] [2, 5]
3 [6, 1] [4, 1] [1, 2] [3, 4] [1, 4] [1, 3] [4, 5] [5, 1] [3, 1]
4 [3, 1] [3, 5] [1, 4] [3, 4] [1, 3] [2, 4] [1, 1] [6, 1] [1, 5]
5 [5, 5] [1, 3] [2, 1] [3, 4] [6, 5] [2, 5] [1, 4] [5, 1] [6, 1]
6 [0, 0] [1, 3] [1, 2] [1, 4] [1, 5] [3, 4] [0, 0] [1, 1] [2, 3]
7 [0, 0] [0, 0] [1, 1] [3, 1] [0, 0] [3, 4] [0, 0] [2, 5] [0, 0]
10 11 12 13 14 15 16 17 18
1 [3, 4] [4, 5] [6, 1] [1, 3] [2, 1] [2, 4] [1, 2] [3, 1] [3, 5]
2 [2, 1] [2, 4] [2, 3] [5, 5] [1, 5] [1, 3] [3, 1] [4, 1] [1, 2]
3 [5, 5] [2, 5] [2, 1] [3, 5] [1, 1] [2, 3] [6, 5] [2, 4] [1, 5]
4 [6, 5] [5, 1] [5, 5] [4, 1] [1, 2] [2, 3] [2, 1] [4, 5] [2, 5]
5 [1, 1] [3, 5] [1, 5] [2, 3] [2, 4] [4, 5] [4, 1] [1, 2] [3, 1]
6 [3, 1] [0, 0] [0, 0] [0, 0] [0, 0] [2, 1] [2, 5] [2, 4] [0, 0]
7 [0, 0] [1, 5] [0, 0] [2, 3] [2, 4] [1, 2] [2, 1] [1, 3] [1, 4]
[X,Y] = X es la Ruta; Y es la línea
Dia
Tren
Dia
Tren
7 EXPERIMENTOS CON PARÁMETROS DEL
SISTEMA
Tras la aplicación del AG tanto a ejemplos imaginarios, como a un sistema real, se puede concluir que, bajo
las condiciones elegidas, el algoritmo llega a soluciones buenas del problema de planificación de rutas y
localización de depósitos.
Aun así, ya que existen varios parámetros que afectan al resultado del algoritmo, parece necesario realizar
más experimentos con el algoritmo diseñado, para finalmente concluir que, de hecho, es una herramienta
útil, efectiva, eficiente y recomendable a la hora de resolver este tipo de problemas.
Se han realizado una serie de experimentos, haciendo uso de los ejemplos anteriores, cambiando algunos de
los parámetros que más afectan el algoritmo, comprobando su efecto sobre la solución.
7.1 Coste de construcción de Depósito
Es razonable suponer que, a medida que aumenta el coste de inversión asociado a la construcción de un
depósito, el número de depósitos de la solución debe disminuir, ya que se busca minimizar el coste de
inversión del sistema ferroviario que se está estudiando.
A continuación, se puede ver una gráfica donde se muestra el número de depósitos de las soluciones
encontradas para el sistema del ejemplo 1 (azul) y el sistema del ejemplo 2 (rojo). Se ha estudiado el resultado
al aumentar el coste de construcción de depósitos desde 250.000€/depósito hasta 2.000.000 €/depósito.
Los demás parámetros se han mantenido iguales para cada una de los experimentos.
Figura 29. Nº de Depósitos según Coste de construcción
Se puede observar que, efectivamente, el algoritmo busca soluciones con menos depósitos a medida que
aumenta el coste de construcción de depósitos.
0
0,5
1
1,5
2
2,5
3
3,5
4
4,5
0 500000 1000000 1500000 2000000 2500000
Nº
DE
DEP
ÓSI
TOS
COSTE DE CONTRUCCIÓN (€)
Ejemplo 1 Ejemplo 2 Red Sevilla
71
7.2 Tamaño de Población
El tamaño de población es el número de individuos que forman cada una de las generaciones creadas en
cada iteración del algoritmo genético. Ya que este número puede afectar la efectividad del algoritmo, cabe
estudiar el valor ideal del tamaño de población.
Es razonable pensar que es posible que este tamaño ideal de población pueda ser diferente según las
dimensiones del problema. Esto es, se puede pensar que, el tamaño de población que llevará a las mejores
soluciones del problema, depende de alguna forma de las dimensiones del problema.
Las siguientes gráficas muestran los resultados de la función objetivo según el tamaño de población que se
usa a la hora de aplicar el algoritmo genético ajustado al problema. Al igual que anteriormente, estos
experimentos se han realizado tanto con los sistemas ejemplo 1, ejemplo 2 y la Red de Cercanías de Sevilla,
definidos en capítulos anteriores.
Figura 30. Evolución de Función Objetivo con el Tamaño de Población (Ejemplo 1 & 2)
Figura 31. Evolución de Función Objetivo con el Tamaño de Población (Red de Cercanías de Sevilla)
Se puede observar que, a medida que aumenta el tamaño de población, el algoritmo encuentra soluciones
mejores. Sin embargo, cuando el tamaño de las generaciónes que se crean superan un cierto número (300 ~
400 individuos) el continuo autmento de la población no tiene efecto sobre la calidad de soluciones, y sólo
contribuye al aumento de tiempo necesario para llegar a una solución buena.
0
5000000
10000000
15000000
20000000
25000000
30000000
35000000
40000000
45000000
0 200 400 600 800 1000
FUN
CIÓ
N O
BJE
TIV
O
TAMAÑO POBLACIÓN
Ejemplo 1 Ejemplo 2
183000000
184000000
185000000
186000000
187000000
188000000
189000000
190000000
191000000
192000000
0 200 400 600 800 1000
FUN
CIÓ
N O
BJE
TIV
O
TAMAÑO DE POBLACIÓN
73
8 CONCLUSIÓN
El problema planteado en el presente trabajo, la optimización de circulación de vehículos y localización de
depósitos en sistemas ferroviarios de tránsito rápido, es de especial interés, ya que el tránsito ferroviario es
un método de transporte muy común en zonas metropolitanas, y la demanda sobre estos sistemas está
creciendo a medida que crece la población donde se encuentran. Una herramienta robusta que encuentra de
forma rápida, buenas soluciones a este tipo problema puede suponer un imporante aumento de la eficiencia
de sistemas ferroviarios, tanto existentes, como nuevos. Además, disponer de una forma rápida de optimizar
la circulación del material rodante de un sistema ferroviario puede implicar una importante redución en el
consumo energéico, y por tanto, en el rendimiento económico de dicho sistema, cosa que cada vez resulta
ser más necesario.
El objetivo de este trabajo fue de encontrar una herramienta que pudiese encontrar soluciones buenas al
problema anteriormente mencionado, de manera eficiente y eficaz. Se buscaba una técnica adaptable a
cualquier tipo de sistema ferroviario, capaz de buscar la mejor solución posible en un tiempo razonable.
Primero, se ha desarrollado un Modelo Matemático que define el problema y sus restricciones. Gracias a la
naturaleza de sistemas ferroviarios, se ha podido plantear un modelo basado en grafos; los posibles
movimientos del material rodante dentro del sistema ferroviario se traducen en arcos del grafo; del mismo
modo, las estaciones del sistema se tratan como los nodos del grafo.
Después de plantear el modelo general, se ha aplicado a ejemplos de redes ferroviarios, resolviendo con el
solver Gurobi Optimizer. Estudiando los resultados obtenidos al aplicar dicho modelo a los sistemas de los
ejemplos del apartado 6, se puede deducir que el modelo matemático exacto es una herramienta ideal a la
hora de resolver problemas de pequeña dimensión y límitada complejidad. Sin embargo, en cuanto el sistema
ferroviario pase de un cierto nivel de complejidad, como la de la Red de Cercanías de Sevilla, el Modelo ya
no es capaz de encontrar soluciones admisibles en un tiempo razonable. Esto se debe a que el número de
variables aumenta de forma exponencial a medida que aumenta el tamaño de la red al que se desea aplicar
el modelo.
Ya que la gran mayoría de las redes ferroviarias reales superan los ejemplos 1 y 2 en complejidad y
dimensión, es lógico concluir que, aunque una herramienta muy útil para sistemas simples, el modelo
matemático exacto no es la técnia ideal para la resolución del problema planteado por este trabajo. Por tanto,
era necesario estudiar otros métodos de solución
La siguiente técnica estudiada ha sido la de los algoritmos meta-heurísticos. Con el estudio previo de la
naturaleza y las características del problema, y con los recursos disponibles, se ha decidido desarrollar un
algorimo genético, programado en Python 3.5, que busca optimizar la circulación de vehículos y localización
de depósitos.
Aplicando el algoritmo a los mismos ejemplos anteriores se observa que el algortimo encuentra soluciones
buenas para el problema en un tiempo razonablemente reducido, tanto en sistemas reducidos y simples,
como en sistemas de gran dimensión y complejas, como la Red de Cercanías de Sevilla.
Comparando las dos herramientas, se puede llegar a la conclusión que en el caso de sistemas ferroviarios
reducidos, donde la red es simple y se realiza un pequeño numero de rutas, el modelo matemático es
preferible frente al algirtmo genético, ya que el modelo es capaz de encontrar la solución óptima global,
mientras que el algortimo sólo es capaz de acercarse con soluciones buenas. Sin embargo, en cuanto se desea
planificar sistemas relativamente complejos, el modelo matemático deja de ser útil, y el algoritmo genético
supone una herramienta lo suficientemente robusta y eficiente para encuentrar soluciones admisibles y
razonablemente buenas en un tiempo reducido. Además, el algoritmo permite cambiar los parámetros que
la definen, pudiendo adaptar el programa a distintos problemas, lo que aumenta la eficiencia y eficacia de
esta para cada caso al que se aplica.
Finalmente, tras haber desarrollado, y posteriormente estudiado y comparado varias herramientas, se ha
llegado a la siguiente conclusión: El Algortimo Genético desarrollado en el presente trabajo resulta ser eficaz
a la hora de encontrar soluciones para el problema de tipo NP-Hard de optimización de circulación de
75
9 ANEXOS
9.1 Anexo I
#Modelo Matemático escrito en Python 3.5 y resuelto usando Gurobi Optimizer.
# -*- coding: utf-8 -*-
from gurobipy import *
import xlrd
################################################################################
def Trees_por_dia(Num_Dias,Num_Lineas,RUTAS):
# Calcula los trenes por dia que se usan. Devuelve una lista de tama?o
#TOTAL_trenes.
TpD=[]
x=0
day=0;line=0
while day<Num_Dias:
TpD.append([])
while line<Num_Lineas:
Num_rutas=len(RUTAS[day][line])
x=x+Num_rutas
line=line+1
TpD[day]=x
x=0;line=0
day=day+1
return TpD
###############################################################################
def Create_DE(num_line):
DE=[]
l1=0; k1=0; l2=0; k2=0;
while l1<num_line:
DE.append([])
while k1<2:
DE[l1].append([])
while l2<num_line:
DE[l1][k1].append([])
while k2<2:
DE[l1][k1][l2].append(0)
k2=k2+1
k2=0
l2=l2+1
l2=0
k1=k1+1
k1=0
l1=l1+1
l1=0
return DE
###############################################################################
def DATA_DE(XL_name,num_line):
book = xlrd.open_workbook(XL_name)
sheet = book.sheet_by_index(0)
if num_line>1:
ajuste=num_line-2
else:
ajuste=0
print ("Numero de lineas:",num_line)
DE=Create_DE(num_line)
l1=0; k1=0; l2=0; k2=0;
while l1<num_line:
while k1<2:
while l2<num_line:
while k2<2:
R=l1*(num_line-ajuste)+k1+5
77
C=l2*(num_line-ajuste)+k2+1
DE[l1][k1][l2][k2]=int(sheet.cell(R,C).value)
k2=k2+1
k2=0
l2=l2+1
l2=0
k1=k1+1
k1=0
l1=l1+1
l1=0
while l1<num_line:
print(DE[l1])
l1=l1+1
print("")
return DE
################################################################################
def Create_RUTAS(Num_Dias, Num_Lineas):
# Crea una Matriz que guarda las estaciones de comienzo y final de cada tren
#para toda la semana y para cada dia. Todos los valores aqui seran 0.
# Devuelve la Matriz "vacia" o con valores 0.
RUTAS=[];
ruta=0;day=0;infd=0;line=0;sta=0;k=0
while day<Num_Dias:
RUTAS.append([])
while line<Num_Lineas:
RUTAS[day].append([])
a=day+1;b=line+1
Num_rutas=int(sheet2.cell(6+line,1+day).value)
while ruta<Num_rutas:
RUTAS[day][line].append([])
while infd<3:
RUTAS[day][line][ruta].append([])
if infd!=2:
while sta<2:
RUTAS[day][line][ruta][infd].append(0)
sta=sta+1
sta=0
else:
RUTAS[day][line][ruta][infd].append(0)
infd=infd+1
infd=0
ruta=ruta+1
ruta=0
line=line+1
line=0
day=day+1
day=0
return RUTAS
###############################################################################
def Data_RUTAS(XL_name,num_dia,num_line):
#Recoge los datos de localizacion de comienzo y salida de cada ruta, por
#cada dia. Devuelve la matriz RUTAS rellenada con los datos previos.
RUTAS=Create_RUTAS(num_dia,num_line)
book = xlrd.open_workbook(XL_name)
sheet3 = book.sheet_by_index(2)
day=0;line=0;ruta=0
while day<num_dia:
R=4
while line<num_line:
Num_rutas=len(RUTAS[day][line])
79
while ruta<Num_rutas:
#estacion de inicio:
R=R+1
C=1+day*5
inicio=int(sheet3.cell(R,C).value)
if inicio==1:
RUTAS[day][line][ruta][0][0]=1
if inicio==2:
RUTAS[day][line][ruta][0][1]=1
#estacion de fin
C=C+1
fin=int(sheet3.cell(R,C).value)
if fin==1:
RUTAS[day][line][ruta][1][0]=1
if inicio==2:
RUTAS[day][line][ruta][1][1]=1
C=C+1
km=float(sheet3.cell(R,C).value)
RUTAS[day][line][ruta][2][0]=km
ruta=ruta+1
ruta=0
R=R+3
line=line+1
line=0
day=day+1
day=0
return RUTAS
################################################################################
def main():
pass
if __name__ == '__main__':
main()
try:
m=Model("V2_AsignacionTrenes")
##############################################################################
# DEFINICION DE DATOS #
##############################################################################
#Numero de dias y de lineas:
print("Cuanto dura el horizonte temporal de la inversion (en años)")
N_years=int(input("Horizonte Temporal en anos:"))
print("Indoduce el nombre el archivo con la información del sistema ferroviario")
print("Recuerda incluir .xlsx al final del nombre")
XL_name=input("Archivo .xlsx= ")
book = xlrd.open_workbook(XL_name)
sheet1 = book.sheet_by_index(0)
sheet2 = book.sheet_by_index(1)
num_line=int(sheet1.cell(2,3).value)
num_dias=int(sheet2.cell(2,0).value)
N_Sem=N_years*365/num_dias
alfa=float(input('Coeficiente de Equilibrio= [0,1]: '))
#Coste de viajar en vacio:
CV=int(input("Coste de viajar en vacio ="))
81
#Coste de construir 1 deposito:
CD=int(input("Coste de contruir 1 deposito ="))
#Definimos primero los datos previamente conocidos
DE=DATA_DE(XL_name,num_line)
RUTAS=Data_RUTAS(XL_name,num_dias,num_line)
#Buscamos el numero de trenes usados al dia:
TpD=Trenes_por_dia(num_dias,num_line,RUTAS)
#Y de aqui tenemos el numero de trenes usados en total:
N_T=max(TpD)
print("Numero de trenes=",N_T)
##############################################################################
# DEFINICION DE VAIRABLES #
##############################################################################
#XR[t][d][l][r] se activara {0,1} si el tren t se asigna al dia d, en la linea l,
# en la ruta r
XR=[]
t=0;
while t<N_T:
XR.append([])
d=0
while d<num_dias:
XR[t].append([])
l=0
while l<num_line:
XR[t][d].append([])
r=0
while r<len(RUTAS[d][l]):
XR[t][d][l].append([])
a=str(t+1);b=str(d+1);j=str(l+1);h=str(r+1)
XR[t][d][l][r]=m.addVar(vtype=GRB.BINARY,name='xr.'+a+'.'+b+'.'+j+'.'+h)
r=r+1
l=l+1
d=d+1
t=t+1
#XV[t][d][l][e][i][c] (binaria) se activiara cuando el tren t, en el dia d,
# realiza una ruta en vacio (sin pasajeros) desde la linea l estacion e hasta
# la estacion c de la linea i.
XV=[]
t=0
while t<N_T:
XV.append([])
d=0
while d<num_dias:
XV[t].append([])
l=0
while l<num_line:
XV[t][d].append([])
e=0
while e<2:
XV[t][d][l].append([])
i=0
while i<num_line:
XV[t][d][l][e].append([])
c=0
while c<2:
XV[t][d][l][e][i].append([])
a=str(t+1);b=str(d+1);j=str(l+1);f=str(e+1);h=str(i+1);g=str(c+1)
XV[t][d][l][e][i][c]=m.addVar(vtype=GRB.BINARY,name='x_vacio.'+a+'.'+b+'.'+j+f+'..'+h+g)
c=c+1
i=i+1
e=e+1
l=l+1
d=d+1
t=t+1
#Xdep_i[t][d][l][e][i][c] (binaria) se activiara cuando el tren t, en el dia d,
83
# sale de un deposito en la estacion e de la linea l y va a comenzar el dia en
# la estacion c de la linea i.
Xdep_i=[]
t=0
while t<N_T:
Xdep_i.append([])
d=0
while d<num_dias:
Xdep_i[t].append([])
l=0
while l<num_line:
Xdep_i[t][d].append([])
e=0
while e<2:
Xdep_i[t][d][l].append([])
i=0
while i<num_line:
Xdep_i[t][d][l][e].append([])
c=0
while c<2:
Xdep_i[t][d][l][e][i].append([])
a=str(t+1);b=str(d+1);j=str(l+1);f=str(e+1);h=str(i+1);g=str(c+1)
Xdep_i[t][d][l][e][i][c]=m.addVar(vtype=GRB.BINARY,name='xdi.'+a+'.'+b+'.'+j+f+'..'+h+g)
c=c+1
i=i+1
e=e+1
l=l+1
d=d+1
t=t+1
#Xdep_f[t][d][l][e][i][c] (binaria) se activiara cuando el tren t, en el dia d,
# entra en un deposito en la estacion c de la linea i y habiendo terminado el
# dia en la estacion e de la linea l.
Xdep_f=[]
t=0
while t<N_T:
Xdep_f.append([])
d=0
while d<num_dias:
Xdep_f[t].append([])
l=0
while l<num_line:
Xdep_f[t][d].append([])
e=0
while e<2:
Xdep_f[t][d][l].append([])
i=0
while i<num_line:
Xdep_f[t][d][l][e].append([])
c=0
while c<2:
Xdep_f[t][d][l][e][i].append([])
a=str(t+1);b=str(d+1);j=str(l+1);f=str(e+1);h=str(i+1);g=str(c+1)
Xdep_f[t][d][l][e][i][c]=m.addVar(vtype=GRB.BINARY,name='xdf.'+a+'.'+b+'.'+j+f+'..'+h+g)
c=c+1
i=i+1
e=e+1
l=l+1
d=d+1
t=t+1
#Rec[t] es la variable que contabiliza la distancia total recorrida por cada tren t
Rec=[]
t=0
while t<N_T:
Rec.append([])
a=str(t+1)
Rec[t]=m.addVar(vtype=GRB.CONTINUOUS, name='Rec.'+a)
t=t+1
85
#RV[t] es la distancia recorrida en vacio por el tren t
RV=[]
t=0
while t<N_T:
RV.append([])
a=str(t+1)
RV[t]=m.addVar(vtype=GRB.CONTINUOUS, name='RV.'+a)
t=t+1
#A[l][e] (binaria) se activara si la estacion e de la linea l es un deposito
A=[]
l=0
while l<num_line:
A.append([])
e=0
while e<2:
A[l].append([])
a=str(l+1);b=str(e+1)
A[l][e]=m.addVar(vtype=GRB.BINARY, name='A.'+a+'.'+b)
e=e+1
l=l+1
#C_Total sera el coste total de la linea
C_Total=m.addVar(vtype=GRB.CONTINUOUS,name='Coste_Total')
#Coeficiente de equilibrio.
C_Equ=m.addVar(vtype=GRB.CONTINUOUS,name='Coste_Equilibrio')
#Variables auxiliares
RMAX=m.addVar(vtype=GRB.CONTINUOUS,name='Recorrido maximo')
RMIN=m.addVar(vtype=GRB.CONTINUOUS,name='Recorrido minimo')
#Integrarar nuevas variables
m.update()
##############################################################################
# DEFINICION DE RESTRICCIONES #
##############################################################################
# |1| #
# Aseguramos que se asignan toas las rutas y que una ruta r solo se asigne
#a un solo tren t:
d=0
while d<num_dias:
l=0
while l<num_line:
r=0
while r<len(RUTAS[d][l]):
Res1=LinExpr()
t=0
while t<N_T:
Res1.add(XR[t][d][l][r],1)
t=t+1
m.addConstr(Res1,GRB.EQUAL,1)
r=r+1
l=l+1
d=d+1
# |2| #
# Aseguramos que, si un tren es asignado a una ruta r, las correspondientes
#variables de depositos son tmbn asignadas/activadas:
# Activamos la viarable de deposito de inicio de dia: Xdep_i[t][d][l][e][i][c]
t=0
while t<N_T:
d=0
while d<num_dias:
l=0
while l<num_line:
r=0
while r<len(RUTAS[d][l]):
87
if RUTAS[d][l][r][0][0]==1:
e=0
else:
e=1
Res31=LinExpr()
i=0
while i<num_line:
c=0
while c<2:
Res31.add(Xdep_i[t][d][i][c][l][e],1)
c=c+1
i=i+1
m.addConstr(Res31,GRB.GREATER_EQUAL,XR[t][d][l][r])
r=r+1
l=l+1
d=d+1
t=t+1
# # Activamos la viarable de deposito de fin de dia: Xdep_f[t][d][l][e][i][c]
t=0
while t<N_T:
d=0
while d<num_dias:
l=0
while l<num_line:
r=0
while r<len(RUTAS[d][l]):
if RUTAS[d][l][r][1][0]==1:
e=0
else:
e=1
Res32=LinExpr()
i=0
while i<num_line:
c=0
while c<2:
Res32.add(Xdep_f[t][d][l][e][i][c],1)
c=c+1
i=i+1
m.addConstr(Res32,GRB.GREATER_EQUAL,XR[t][d][l][r])
r=r+1
l=l+1
d=d+1
t=t+1
# |3| #
# Aseguramos que no se active mas de 1 variable de deposito de inicio y 1
#variable de fin por tren y por dia:
#Limitamos Xdep_i[t][d][l][e][i][c]
t=0
while t<N_T:
d=0
while d<num_dias:
l=0
Res41=LinExpr()
while l<num_line:
e=0
while e<2:
i=0
while i<num_line:
c=0
while c<2:
Res41.add(Xdep_i[t][d][l][e][i][c],1)
c=c+1
i=i+1
e=e+1
l=l+1
m.addConstr(Res41,GRB.EQUAL,1)
d=d+1
t=t+1
89
#Limitamos Xdep_f[t][d][l][e][i][c]
t=0
while t<N_T:
d=0
while d<num_dias:
l=0
Res42=LinExpr()
while l<num_line:
e=0
while e<2:
i=0
while i<num_line:
c=0
while c<2:
Res42.add(Xdep_f[t][d][l][e][i][c],1)
c=c+1
i=i+1
e=e+1
l=l+1
m.addConstr(Res42,GRB.EQUAL,1)
d=d+1
t=t+1
# |4| #
# Aseguramos que el deposito de fin del tren t en el dia d sea el de inicio
#del mismo tren en el dia d+1:
t=0
while t<N_T:
d=0
while d<num_dias-1:
i=0
while i<num_line:
c=0
while c<2:
Res51=LinExpr()
Res52=LinExpr()
l=0
while l<num_line:
e=0
while e<2:
Res51.add(Xdep_f[t][d][l][e][i][c],1)
Res52.add(Xdep_i[t][d+1][i][c][l][e])
e=e+1
l=l+1
m.addConstr(Res51,GRB.EQUAL,Res52)
c=c+1
i=i+1
d=d+1
t=t+1
# # |4.1| # Conectamos el ultimo dia con el primero:
t=0
while t<N_T:
i=0
while i<num_line:
c=0
while c<2:
Res51=LinExpr()
Res52=LinExpr()
l=0
while l<num_line:
e=0
while e<2:
Res51.add(Xdep_f[t][num_dias-1][l][e][i][c],1)
Res52.add(Xdep_i[t][0][i][c][l][e])
e=e+1
l=l+1
m.addConstr(Res51,GRB.EQUAL,Res52)
c=c+1
i=i+1
t=t+1
# |5|#
# Aseguramos que se asigna solo 1 ruta vacia a un tren por dia:
91
t=0
while t<N_T:
d=0
while d<num_dias:
Res121=LinExpr()
Res122=LinExpr()
l=0
while l<num_line:
e=0
while e<2:
i=0
while i<num_line:
c=0
while c<2:
Res121.add(XV[t][d][l][e][i][c],1)
c=c+1
i=i+1
e=e+1
l=l+1
l=0
while l<num_line:
r=0
while r<len(RUTAS[d][l]):
Res122.add(XR[t][d][l][r],1)
r=r+1
l=l+1
m.addConstr(Res122+Res121,GRB.EQUAL,1)
d=d+1
t=t+1
# |6| #
# Aseguramos que, si un tren es asignado a una ruta vacia, las correspondientes
#variables de depositos son tmbn asignadas/activadas:
# Activamos la viarable de deposito de inicio de dia: Xdep_i[t][d][l][e][i][c]
t=0
while t<N_T:
d=0
while d<num_dias:
l=0
while l<num_line:
e=0
while e<2:
Res1311=LinExpr()
Res1312=LinExpr()
i=0
while i<num_line:
c=0
while c<2:
Res1311.add(Xdep_i[t][d][i][c][l][e],1)
Res1312.add(XV[t][d][l][e][i][c],1)
c=c+1
i=i+1
m.addConstr(Res1312,GRB.LESS_EQUAL,Res1311)
e=e+1
l=l+1
d=d+1
t=t+1
# Activamos la viarable de deposito de fin de dia: Xdep_f[t][d][l][e][i][c]
t=0
while t<N_T:
d=0
while d<num_dias:
l=0
while l<num_line:
e=0
while e<2:
Res1321=LinExpr()
Res1322=LinExpr()
i=0
while i<num_line:
c=0
93
while c<2:
Res1321.add(Xdep_f[t][d][l][e][i][c],1)
Res1322.add(XV[t][d][i][c][l][e],1)
c=c+1
i=i+1
m.addConstr(Res1322,GRB.LESS_EQUAL,Res1321)
e=e+1
l=l+1
d=d+1
t=t+1
# |7| #
# Aseguramos que no se usen estaciones como depositos que no lo sean:
t=0
while t<N_T:
d=0
while d<num_dias:
l=0
while l<num_line:
e=0
while e<2:
i=0
while i<num_line:
c=0
while c<2:
m.addConstr(Xdep_i[t][d][l][e][i][c],GRB.LESS_EQUAL,A[l][e])
m.addConstr(Xdep_f[t][d][l][e][i][c],GRB.LESS_EQUAL,A[i][c])
c=c+1
i=i+1
e=e+1
l=l+1
d=d+1
t=t+1
# |8| #
# Definimos RV[t]:
t=0
while t<N_T:
Res71=LinExpr()
Res72=LinExpr()
d=0
while d<num_dias:
l=0
while l<num_line:
e=0
while e<2:
i=0
while i<num_line:
c=0
while c<2:
Res71.add((Xdep_i[t][d][l][e][i][c]+Xdep_f[t][d][l][e][i][c]+XV[t][d][l][e][i][c])*DE[l][e][i][c],1)
c=c+1
i=i+1
e=e+1
l=l+1
d=d+1
m.addConstr(RV[t],GRB.EQUAL,Res71)
t=t+1
# |9| #
# Definimos Rec[t]:
t=0
while t<N_T:
Res8=LinExpr()
d=0
while d<num_dias:
l=0
while l<num_line:
r=0
while r<len(RUTAS[d][l]):
Res8.add(XR[t][d][l][r]*RUTAS[d][l][r][2][0],1)
r=r+1
l=l+1
95
d=d+1
m.addConstr(RV[t]+Res8,GRB.EQUAL,Rec[t])
t=t+1
# |10| #
# Definimos C_Total:
Res91=LinExpr()
Res92=LinExpr()
t=0
while t<N_T:
Res91.add(RV[t],1)
t=t+1
l=0
while l<num_line:
e=0
while e<2:
Res92.add(A[l][e],1)
e=e+1
l=l+1
Res92.add(N_Dep,-1)
m.addConstr(CV*Res91*N_Sem+CD*(Res92),GRB.EQUAL,C_Total)
#|11|#
#Definimos C_Equ:
t=0
while t<N_T:
m.addConstr(Rec[t],GRB.LESS_EQUAL,RMAX)
m.addConstr(Rec[t],GRB.GREATER_EQUAL,RMIN)
t=t+1
m.addConstr(RMAX-RMIN,GRB.EQUAL,C_Equ)
##############################################################################
# DEFINICION DE FUNCION OPJETIVO#
##############################################################################
m.setObjective(C_Total+alfa*C_Equ,sense=GRB.MINIMIZE)
##############################################################################
# RESOLUCION DE MODELO
##############################################################################
m.optimize()
for v in m.getVars():
if v.x!=0:
print('%s %g' % (v.varName, v.x))
print('Obj: %g' % m.objVal)
except GurobiError:
print('Error reported')
9.2 Anexo II
#Algoritmo Genético en Python 3.5:
#-------------------------------------------------------------------------------
import xlrd
import xlsxwriter
################################################################################
def espar(number):
# Calcula si un numero (number) es par o no, y devuelve un 1 si lo es,
# y un 2 si no.
if number==0:
b=1;
97
else:
a=number%2
if a==0:
b=1;
else:
b=2;
return b
################################################################################
def Trenes_por_dia(Num_Dias,Num_Lineas,RUTAS):
# Calcula los trenes por dia que se usan. Devuelve una lista de tama?o
#TOTAL_trenes.
TpD=[]
x=0
day=0;line=0
while day<Num_Dias:
TpD.append([])
while line<Num_Lineas:
Num_rutas=len(RUTAS[day][line])
x=x+Num_rutas
line=line+1
TpD[day]=x
x=0;line=0
day=day+1
return TpD
###############################################################################
def Create_DE(num_line):
DE=[]
l1=0; k1=0; l2=0; k2=0;
while l1<num_line:
DE.append([])
while k1<2:
DE[l1].append([])
while l2<num_line:
DE[l1][k1].append([])
while k2<2:
DE[l1][k1][l2].append(0)
k2=k2+1
k2=0
l2=l2+1
l2=0
k1=k1+1
k1=0
l1=l1+1
l1=0
return DE
###############################################################################
def DATA_DE(XL_name,num_line):
book = xlrd.open_workbook(XL_name)
sheet = book.sheet_by_index(0)
if num_line>1:
ajuste=num_line-2
else:
ajuste=0
DE=Create_DE(num_line)
l1=0; k1=0; l2=0; k2=0;
while l1<num_line:
while k1<2:
while l2<num_line:
while k2<2:
R=l1*(num_line-ajuste)+k1+5
C=l2*(num_line-ajuste)+k2+1
DE[l1][k1][l2][k2]=int(sheet.cell(R,C).value)
k2=k2+1
k2=0
99
l2=l2+1
l2=0
k1=k1+1
k1=0
l1=l1+1
l1=0
return DE
################################################################################
def Create_RUTAS(Num_Dias, Num_Lineas):
# Crea una Matriz que guarda las estaciones de comienzo y final de cada tren
#para toda la semana y para cada dia. Todos los valores aqui seran 0.
# Devuelve la Matriz "vacia" o con valores 0.
RUTAS=[];
ruta=0;day=0;infd=0;line=0;sta=0;k=0
while day<Num_Dias:
RUTAS.append([])
while line<Num_Lineas:
RUTAS[day].append([])
a=day+1;b=line+1
Num_rutas=int(sheet2.cell(6+line,1+day).value)
while ruta<Num_rutas:
RUTAS[day][line].append([])
while infd<3:
RUTAS[day][line][ruta].append([])
if infd!=2:
while sta<2:
RUTAS[day][line][ruta][infd].append(0)
sta=sta+1
sta=0
else:
RUTAS[day][line][ruta][infd].append(0)
infd=infd+1
infd=0
ruta=ruta+1
ruta=0
line=line+1
line=0
day=day+1
day=0
return RUTAS
################################################################################
def Data_TrainSchedule(XL_name,num_dia,num_line):
#Recoge los datos de localizacion de comienzo y salida de cada ruta, por
#cada dia. Devuelve la matriz RUTAS rellenada con los datos previos.
RUTAS=Create_RUTAS(num_dia,num_line)
book = xlrd.open_workbook(XL_name)
sheet3 = book.sheet_by_index(2)
day=0;line=0;ruta=0
while day<num_dia:
R=4
while line<num_line:
Num_rutas=len(RUTAS[day][line])
while ruta<Num_rutas:
#estacion de inicio:
R=R+1
C=1+day*5
inicio=int(sheet3.cell(R,C).value)
if inicio==1:
101
RUTAS[day][line][ruta][0][0]=1
if inicio==2:
RUTAS[day][line][ruta][0][1]=1
#estacion de fin
C=C+1
fin=int(sheet3.cell(R,C).value)
if fin==1:
RUTAS[day][line][ruta][1][0]=1
if inicio==2:
RUTAS[day][line][ruta][1][1]=1
C=C+1
km=float(sheet3.cell(R,C).value)
RUTAS[day][line][ruta][2][0]=km
ruta=ruta+1
ruta=0
R=R+3
line=line+1
line=0
day=day+1
day=0
return RUTAS
################################################################################
def Create_Depositos(TOTAL_Trenes,Num_Dias, Num_Lineas):
# Crea una Matriz que guarda las estaciones de comienzo y final de cada tren
#para toda la semana y para cada dia. Todos los valores aqui seran 0.
# Devuelve la Matriz "vacia" o con valores 0.
DEP=[];
train=0;day=0;line=0;sta=0;k=0
while train<TOTAL_Trenes:
DEP.append([])
while day<Num_Dias:
DEP[train].append([])
while line<Num_Lineas:
DEP[train][day].append([])
while sta<2:
DEP[train][day][line].append(0)
sta=sta+1
sta=0
line=line+1
line=0
day=day+1
day=0
train=train+1
train=0
return DEP
################################################################################
def Create_TRAINSsol(Num_Dias,Num_Lineas,TOTAL_Trenes):
TRAINS=[]
day=0;train=0;rl=0
while train<TOTAL_Trenes:
TRAINS.append([])
while day<Num_Dias:
TRAINS[train].append([])
while rl<2:
TRAINS[train][day].append(0)
rl=rl+1
rl=0
103
day=day+1
day=0;
train=train+1
train=0
return TRAINS
################################################################################
def Create_Recorrido(TOTAL_Trenes):
Rec_Tren=[]
train=0;
while train<TOTAL_Trenes:
Rec_Tren.append(0)
train=train+1
return Rec_Tren
################################################################################
def Calculo_distancia(DEP,TRAINS,RUTAS,DIST,TOTAL_Trenes,Num_Lineas,Num_Dias):
Rec_Tren=Create_Recorrido(TOTAL_Trenes)
RV=Create_Recorrido(TOTAL_Trenes)
train=0
while train<TOTAL_Trenes:
day=0
while day<Num_Dias:
#Primero calculamos las distancias recorridas en las rutas:
if TRAINS[train][day][1]!=0:
line=TRAINS[train][day][1]-1
ruta=TRAINS[train][day][0]-1
Rec_Tren[train]=Rec_Tren[train]+RUTAS[day][line][ruta][2][0]
#Calculamos ahora las distancias en vacio
#Encontramos el deposito de inicio:
l=0
while l<Num_Lineas:
e=0
while e<2:
if DEP[train][day][l][e]==1:
l1=l
e1=e
e=e+1
l=l+1
#Encontramos el inicio de la ruta:
if TRAINS[train][day][0]!=0:
r=TRAINS[train][day][0]-1
lr=TRAINS[train][day][1]-1
if RUTAS[day][lr][r][0][0]==1:
er=0
else:
er=1
RV[train]=RV[train]+DIST[l1][e1][lr][er]
day=day+1
day=0
while day<Num_Dias-1:
#Encontramos el deposito de fin:
l=0
while l<Num_Lineas:
e=0
while e<2:
if DEP[train][day+1][l][e]==1:
l1=l
e1=e
e=e+1
l=l+1
#Encontramos el fin de la ruta:
105
if TRAINS[train][day][0]!=0:
r=TRAINS[train][day][0]-1
lr=TRAINS[train][day][1]-1
if RUTAS[day][lr][r][1][0]==1:
er=0
else:
er=1
RV[train]=RV[train]+DIST[lr][er][l1][e1]
day=day+1
#Conexion de fin de semana con el inicio:
#Encontramos el deposito de inicio de la semana:
l=0
while l<Num_Lineas:
e=0
while e<2:
if DEP[train][0][l][e]==1:
l1=l
e1=e
e=e+1
l=l+1
#Encontramos el fin de la ruta del ultimo dia
if TRAINS[train][Num_Dias-1][0]!=0:
r=TRAINS[train][Num_Dias-1][0]-1
lr=TRAINS[train][Num_Dias-1][1]-1
if RUTAS[day][lr][r][1][0]==1:
er=0
else:
er=1
RV[train]=RV[train]+DIST[lr][er][l1][e1]
#Si tenemos un dia donde el tren train no realiza una ruta:
day=0
while day<Num_Dias-1:
if TRAINS[train][day][0]==0:
#Encontramos el deposito de inicio de dia:
l=0
while l<Num_Lineas:
e=0
while e<2:
if DEP[train][day][l][e]==1:
l1=l
e1=e
e=e+1
l=l+1
#Encontramos el deposito de fin de dia:
l=0
while l<Num_Lineas:
e=0
while e<2:
if DEP[train][day+1][l][e]==1:
l2=l
e2=e
e=e+1
l=l+1
RV[train]=RV[train]+DIST[l1][e1][l2][e2]
day=day+1
#Conexion con fin de semana e inicio:
if TRAINS[train][Num_Dias-1][0]==0:
#Encontramos el deposito de inicio de dia:
l=0
while l<Num_Lineas:
e=0
while e<2:
if DEP[train][Num_Dias-1][l][e]==1:
l1=l
107
e1=e
e=e+1
l=l+1
#Encontramos el deposito de fin de dia:
l=0
while l<Num_Lineas:
e=0
while e<2:
if DEP[train][0][l][e]==1:
lf=l
ef=e
e=e+1
l=l+1
RV[train]=RV[train]+DIST[l1][e1][lf][ef]
Rec_Tren[train]=Rec_Tren[train]+RV[train]
train=train+1
return [Rec_Tren,RV]
################################################################################
def Create_Cont_Trains(TOTAL_Trenes,Num_Dias):
day=0;train=0;
Cont_Trains=[]
while day<Num_Dias:
Cont_Trains.append([])
while train<TOTAL_Trenes:
Cont_Trains[day].append(1)
train=train+1
train=0
day=day+1
return Cont_Trains
################################################################################
def Create_Cont_Rutas(Num_Dias,Num_Lineas,Num_Rutas):
day=0;line=0;ruta=0;
Cont_Rutas=[]
while day<Num_Dias:
Cont_Rutas.append([])
while line<Num_Lineas:
Cont_Rutas[day].append([])
while ruta<Num_Rutas[day][line]:
Cont_Rutas[day][line].append(1)
ruta=ruta+1
ruta=0
line=line+1
line=0
day=day+1
day=0
return Cont_Rutas
################################################################################
def Create_rutas(Num_Lineas, Num_Dias, RUTAS):
Num_Rutas=[];day=0;line=0
while day<Num_Dias:
Num_Rutas.append([])
while line<Num_Lineas:
Num_Rutas[day].append(0)
Num_Rutas[day][line]=len(RUTAS[day][line])
line=line+1
line=0
day=day+1
day=0
return Num_Rutas
################################################################################
def Fobj_Coste(RV,NDep,TOTAL_Trenes,CV,CD,N_Sem):
109
#Esta funcion calcula los kilometros totales recorridos por todos los trenes
Fun_Obj1=0;
train=0
while train<TOTAL_Trenes:
Fun_Obj1=Fun_Obj1+RV[train]*CV
train=train+1
Fun_Obj1=Fun_Obj1*N_Sem
Fun_Obj1=Fun_Obj1+NDep*CD
return Fun_Obj1
################################################################################
def FObj_Equibilibrio(Rec_Tren1, TOTAL_Trenes):
#Esta funcion calcula el valor de la funcion objetivo que busca equilibar las
#distancias recorridas por cada tren:
## 1 si es el primero, 2 si es el segundo
MAX=max(Rec_Tren1)
MIN=min(Rec_Tren1)
Fun_Obj1=abs(MAX-MIN)
return Fun_Obj1
################################################################################
def Random_Solution_Trains(RUTAS,TpD,Num_Dias,Num_Lineas,TOTAL_Trenes):
##Crea una soluci?n valida, elegida de forma completamente aleatoria
#!/usr/bin/python
import random
import math
Cont_RL=Create_rutas(Num_Lineas, Num_Dias, RUTAS)
Cont_Rutas=Create_Cont_Rutas(Num_Dias,Num_Lineas,Cont_RL)
Cont_Trains=Create_Cont_Trains(TOTAL_Trenes,Num_Dias)
SOL=Create_TRAINSsol(Num_Dias,Num_Lineas,TOTAL_Trenes)
day=0;tpd=0;line=0
while day<Num_Dias:
while tpd<TpD[day]:
#Elegimos aleatoriamente el tren que vamos a asignar.
flag1=0
while flag1==0:
r1=random.uniform(0,TOTAL_Trenes)
train=math.floor(r1)
train=int(train)
if Cont_Trains[day][train]==1:
Cont_Trains[day][train]=0 ## Se van eliminando los trenes que se han usado ese dia
flag1=1
#Tenemos ahora el tren "train", elegido aleatoriamente.
#Elegimos aleatoriamente la linea por la que se va a mover:
flag2=0
while flag2==0:
r2=random.uniform(0,Num_Lineas)
line=math.floor(r2)
line=int(line)
if Cont_RL[day][line]!=0: ## Se van reduciendo el numero de rutas por ocupar en cada lineaque
se van rellenando
Cont_RL[day][line]=Cont_RL[day][line]-1
flag2=1
#Elegimos alteatoriamente la ruta de la linea "line" del dia "day" que el tren "train" va ha realizar
flag3=0
111
while flag3==0:
r3=random.uniform(0,len(Cont_Rutas[day][line]))
ruta=math.floor(r3)
ruta=int(ruta)
if Cont_Rutas[day][line][ruta]==1:
Cont_Rutas[day][line][ruta]=0
flag3=1
#Tenemos ahora la ruta, la linea, y el tren que lo realizar?
#Asignamos la linea y ruta a la lista TRAINS
## La ruta estara en la posicion TRAINS[train][day][0] (representamos la ruta 0 como ruta+1, para
no confundirlo con un tren que no realiza ruta)
## La linea estara en la posicin TRAINS[train][day][1](representamos la linea 0 como linea+1, para
no confundirlo con un tren que no realiza ruta)
SOL[train][day][0]=ruta+1
SOL[train][day][1]=line+1
tpd=tpd+1
tpd=0
day=day+1
day=0
return SOL
################################################################################
def Random_Solution_Dep(Num_Dias,Num_Lineas,TOTAL_Trenes):
#Por ahora, consideramos que el n? de depositos es fijo.
import random
import math
DEP=Create_Depositos(TOTAL_Trenes,Num_Dias,Num_Lineas)
nd=random.uniform(1,Num_Lineas*2+1)
nd=math.floor(nd)
Num_Dep=int(nd)
#Creamos una lista para guardar la localizacion de cada deposito:
## Se representar?n con Line+1 y sta+1, para no confundir con localizaciones sin deposito
npd=0;k=0
Loc_Dep=[]
while npd<Num_Dep:
Loc_Dep.append([])
while k<2:
Loc_Dep[npd].append(0)
k=k+1
k=0
npd=npd+1
npd=0
day=0;line=0;sta=0;
while day<Num_Dias:
while npd<Num_Dep:
#Elegimos aleatoriamente la linea en la que se va encontrar el deposito "npd":
r1=random.uniform(0,Num_Lineas)
line=math.floor(r1)
line=int(line)
Loc_Dep[npd][0]=line
#Elegimos aleatoriamente la estacion
r2=random.uniform(0,2)
sta=math.floor(r2)
sta=int(sta)
Loc_Dep[npd][1]=sta
npd=npd+1
npd=0
day=day+1
day=0
#Ya tenemos la localizaci?n de los "Num_Dep" depositos
113
#Asignamos aleatoriamente el deposito de cada tren y cada dia
train=0
while train<TOTAL_Trenes:
while day<Num_Dias:
#Elegimos aleatoriamente el deposito del tren "train" del dia "day"
r3=random.uniform(0,Num_Dep)
dep=math.floor(r3)
dep=int(dep)
DEP[train][day][Loc_Dep[dep][0]][Loc_Dep[dep][1]]=1
day=day+1
day=0
train=train+1
train=0
return DEP
################################################################################
def Calculo_Dep(DEP,DIST,TOTAL_Trenes,Num_Lineas,Num_Dias):
NDep=1
Memo=[]
line=0
while line<Num_Lineas:
Memo.append([])
station=0
while station<2:
Memo[line].append(0)
station=station+1
line=line+1
DEPOSITOS=[]
t=0
while t<TOTAL_Trenes:
d=0
while d<Num_Dias:
l=0
while l<Num_Lineas:
sta=0
while sta<2:
if DEP[t][d][l][sta]==1:
if Memo[l][sta]==0:
DEPOSITOS.append([l,sta])
Memo[l][sta]=1
sta=sta+1
l=l+1
d=d+1
t=t+1
dp1=0;dp2=0
while dp1<len(DEPOSITOS):
while dp2<len(DEPOSITOS):
if dp2==dp1:
dp2+=1
else:
if
DIST[DEPOSITOS[dp1][0]][DEPOSITOS[dp1][1]][DEPOSITOS[dp2][0]][DEPOSITOS[dp2][1]]!=0:
NDep+=1
dp2+=1
dp1+=1
return [DEPOSITOS,NDep]
################################################################################
def Crear_Sol_Random(RUTAS,TpD,Num_Dias,Num_Lineas,TOTAL_Trenes,
DIST,CV,CD,N_Sem,alfa):
TRAINS1=Random_Solution_Trains(RUTAS,TpD,Num_Dias,Num_Lineas,TOTAL_Trenes)
115
DEP1=Random_Solution_Dep(Num_Dias,Num_Lineas,TOTAL_Trenes)
Depositos=Calculo_Dep(DEP1,DIST,TOTAL_Trenes,Num_Lineas,Num_Dias)
NDep=int(Depositos[1])
R=Calculo_distancia(DEP1,TRAINS1,RUTAS,DIST,TOTAL_Trenes,Num_Lineas,Num_Dias)
Rec_Tren1=R[0];RV=R[1]
FOBJ=Fobj_Coste(RV,NDep,TOTAL_Trenes,CV,CD,N_Sem)+alfa*FObj_Equibilibrio(Rec_Tren1,TOT
AL_Trenes)
SOL=[FOBJ,TRAINS1,DEP1,Rec_Tren1,RV,Depositos]
return SOL
################################################################################
def Create_Random_popX(RUTAS,TpD,Num_Dias,Num_Lineas,TOTAL_Trenes,DIST,X,CV,CD,alfa):
#esta funcion crea X soluciones aleatorias
Familia=[]
k=0
while k<X:
Familia.append(Crear_Sol_Random(RUTAS,TpD,Num_Dias,Num_Lineas,TOTAL_Trenes,DIST,CV,C
D,N_Sem,alfa))
k=k+1
return Familia
################################################################################
def Genetic_selection(GEN):
# Esta funcion selecciona de la poblacion GEN el grupo que seran los
# reproductores, el grupo que se mutara e introducira en la siguiente
# poblacion y el grupo que sera eliminada de la poblacion.
# Primero ordenamos segun las distancias recorridas:
GEN.sort()
INDI=len(GEN)
#Calculo de cantidades según porcentajes:
DELETE=int(0.6*INDI)
MUTATIONS=int(0.1*INDI)
PAPAS=int(0.3*INDI)
if (PAPAS%2)!=0:
PAPAS=PAPAS+1
MUTATIONS=MUTATIONS
DELETE=DELETE-1
# Eliminamos 60% de los peores:
i=INDI-1
while i>INDI-1-DELETE:
del GEN[i]
i=i-1
# Cogemos los 25 con los mayores recorridos y los metemos en la lista de MUTS, que seran
# las que seran mutados e introducidos en la siguiente generacion.
MUTS=[]
i=INDI-1-DELETE
aux=i
while i>aux-MUTATIONS:
MUTS.append(GEN[i])
del GEN[i]
i=i-1
#Ahora definimos tres grupos diferentes que seran los grupos reproductores:
#|1|# El primer grupo cruzara el mejor con el segundo mejor,
#el tercero con el cuarto...
Padres1=[]
Madres1=[]
117
i=0
while i<PAPAS:
Padres1.append(GEN[i])
Madres1.append(GEN[i+1])
i=i+2
#|2|# El segundo grupo cruzara los 25 mejores equilibrados, con los otros 25
#individuos que quedan. (1-25;2-26,3-27...)
Padres2=[]
Madres2=[]
i=0
while i<(PAPAS/2):
Padres2.append(GEN[i])
Madres2.append(GEN[i+int(PAPAS/2)])
i=i+1
#########################
# Esta seleccion y combinacion de individuos se guardar?n en una lista de resultados:
FAM1=[Padres1,Madres1]
FAM2=[Padres2,Madres2]
SEL_GEN=[FAM1,FAM2,MUTS]
return SEL_GEN
################################################################################
def Mutacion(MUTS,Num_Dias,Num_Lineas,TOTAL_Trenes,CV,CD,N_Sem,DIST):
#Esta funcion introduce mutaciones en los individuos de la lista MUTS
import math
import random
INDI=len(MUTS)
m=0
while m<len(MUTS):
#Eleccion de numero de dias con mutaciones
dm=int(math.floor(random.uniform(0,math.floor((Num_Dias)/2))))
DIA=[]
i=0
while i<dm:
DIA.append(0)
i=i+1
i=0
#Eleccion de que dias tendran mutaciones
while i<dm:
d=int(math.floor(random.uniform(1,Num_Dias+1)))
k=0
flag=0
while k<dm:
if d==DIA[k]:
flag=1
k=k+1
if flag==0:
DIA[i]=d
i=i+1
i=0
while i<dm:
d=DIA[i]-1
#Eleccion de numero de intercambios realizados
l=int(math.floor(random.uniform(0,math.floor((Num_Lineas)/4))))
tm=l*2
TRN=[]
t=0
while t<tm:
119
TRN.append(0)
t=t+1
t=0
#Eleccion de entre que trenes habra intercambio de rutas
while t<tm:
t1=int(math.floor(random.uniform(1,TOTAL_Trenes+1)))
k=0
flag=0
while k<tm:
if t1==TRN[k]:
flag=1
k=k+1
if flag==0:
TRN[t]=t1
t=t+1
a=espar(tm)
if a==2:
tm=tm-1
k=0
while k<tm:
aux=[]
t1=TRN[k]-1
t2=TRN[k+1]-1
aux=MUTS[m][1][t2][d]
MUTS[m][1][t2][d]=MUTS[m][1][t1][d]
MUTS[m][1][t1][d]=aux
k=k+2
i=i+1
M=Calculo_distancia(MUTS[m][2],MUTS[m][1],RUTAS,DIST,TOTAL_Trenes,Num_Lineas,Num_Dia
s)
MUTS[m][3]=M[0]
MUTS[m][4]=M[1]
MUTS[m][5]=Calculo_Dep(MUTS[m][2],DIST,TOTAL_Trenes,Num_Lineas,Num_Dias)
MUTS[m][0]=Fobj_Coste(MUTS[m][4],MUTS[m][5][1],TOTAL_Trenes,CV,CD,N_Sem)+FObj_Equibi
librio(MUTS[m][3],TOTAL_Trenes)
m=m+1
MUTS.sort()
if (INDI%2)!=0:
i=INDI-1
while i>INDI-4:
del MUTS[i]
i-=1
return MUTS
################################################################################
def Combinar1(Padres,Madres,TOTAL_Trenes,RUTAS,DIST,Num_Lineas,Num_Dias,CV,CD,N_Sem):
#Esta funcion crea 0.5*Xp individuos nuevos a partir de Xp individuos. (Xp=Numero de
padres+madres)
import random
import math
COM=[]
INDI=len(Padres)
m=0
while m<INDI:
121
#El nuevo individuo tendra la planificacion del padre para la primera mitad de los dias y
# la planificacion de la madre para la segunda mitad de los dias
COM.append(Padres[m])
N_D=Num_Dias//2
d=Num_Dias-1
while d>N_D-1:
t=0
while t<TOTAL_Trenes:
COM[m][1][t][d]=Madres[m][1][t][d]
COM[m][2][t][d]=Madres[m][2][t][d]
t=t+1
d=d-1
R1=Calculo_distancia(COM[m][2],COM[m][1],RUTAS,DIST,TOTAL_Trenes,Num_Lineas,Num_Dias)
COM[m][3]=R1[0]
COM[m][4]=R1[1]
COM[m][5]=Calculo_Dep(COM[m][2],DIST,TOTAL_Trenes,Num_Lineas,Num_Dias)
COM[m][0]=Fobj_Coste(COM[m][4],COM[m][5][1],TOTAL_Trenes,CV,CD,N_Sem)+FObj_Equibilibr
io(COM[m][3],TOTAL_Trenes)
m=m+1
return COM
################################################################################
def Combinar2(Padres,Madres,TOTAL_Trenes,RUTAS,DIST,Num_Lineas,Num_Dias,CV,CD,N_Sem):
import random
import math
COM=[]
INDI=len(Padres)
m=0
while m<INDI:
#Opcion 2:
COM.append(Madres[m])
N_D=Num_Dias//2
d=Num_Dias-1
while d>N_D-1:
t=0
while t<TOTAL_Trenes:
COM[m][1][t][d]=Padres[m][1][t][d]
COM[m][2][t][d]=Padres[m][2][t][d]
t=t+1
d=d-1
R1=Calculo_distancia(COM[m][2],COM[m][1],RUTAS,DIST,TOTAL_Trenes,Num_Lineas,Num_Dias)
COM[m][3]=R1[0]
COM[m][4]=R1[1]
COM[m][5]=Calculo_Dep(COM[m][2],DIST,TOTAL_Trenes,Num_Lineas,Num_Dias)
COM[m][0]=Fobj_Coste(COM[m][4],COM[m][5][1],TOTAL_Trenes,CV,CD,N_Sem)+FObj_Equibilibr
io(COM[m][3],TOTAL_Trenes)
m=m+1
return COM
################################################################################
def Combinar3(Padres,Madres,TOTAL_Trenes,RUTAS,DIST,Num_Lineas,Num_Dias,CV,CD,N_Sem):
#Opcion 3
import random
123
import math
COM=[]
INDI=len(Padres)
m=0
while m<INDI:
COM.append(Padres[m])
N_D=Num_Dias//3
d=Num_Dias-N_D-1
while d>N_D-1:
t=0
while t<TOTAL_Trenes:
COM[m][1][t][d]=Madres[m][1][t][d]
COM[m][2][t][d]=Madres[m][2][t][d]
t=t+1
d=d-1
R1=Calculo_distancia(COM[m][2],COM[m][1],RUTAS,DIST,TOTAL_Trenes,Num_Lineas,Num_Dias)
COM[m][3]=R1[0]
COM[m][4]=R1[1]
COM[m][5]=Calculo_Dep(COM[m][2],DIST,TOTAL_Trenes,Num_Lineas,Num_Dias)
COM[m][0]=Fobj_Coste(COM[m][4],COM[m][5][1],TOTAL_Trenes,CV,CD,N_Sem)+FObj_Equibilibr
io(COM[m][3],TOTAL_Trenes)
m=m+1
return COM
################################################################################
def Combinar4(Padres,Madres,TOTAL_Trenes,RUTAS,DIST,Num_Lineas,Num_Dias,CV,CD,N_Sem):
#Opcion 4
import random
import math
COM=[]
INDI=len(Padres)
m=0
while m<INDI:
COM.append(Madres[m])
N_D=Num_Dias//3
d=Num_Dias-N_D-1
while d>N_D-1:
t=0
while t<TOTAL_Trenes:
COM[m][1][t][d]=Padres[m][1][t][d]
COM[m][2][t][d]=Padres[m][2][t][d]
t=t+1
d=d-1
R1=Calculo_distancia(COM[m][2],COM[m][1],RUTAS,DIST,TOTAL_Trenes,Num_Lineas,Num_Dias)
COM[m][3]=R1[0]
COM[m][4]=R1[1]
COM[m][5]=Calculo_Dep(COM[m][2],DIST,TOTAL_Trenes,Num_Lineas,Num_Dias)
COM[m][0]=Fobj_Coste(COM[m][4],COM[m][5][1],TOTAL_Trenes,CV,CD,N_Sem)+FObj_Equibilibr
io(COM[m][3],TOTAL_Trenes)
m=m+1
return COM
################################################################################
def Combinar5(Padres,Madres,TOTAL_Trenes,RUTAS,DIST,Num_Lineas,Num_Dias,CV,CD,N_Sem):
#Opcion 5
125
import random
import math
COM=[]
INDI=len(Padres)
m=0
while m<INDI:
COM.append(Padres[m])
N_D=Num_Dias//4
d=Num_Dias-N_D-1
while d>N_D-1:
t=0
while t<TOTAL_Trenes:
COM[m][1][t][d]=Madres[m][1][t][d]
COM[m][2][t][d]=Madres[m][2][t][d]
t=t+1
d=d-1
d=Num_Dias-2*N_D-1
while d>N_D-1:
t=0
while t<TOTAL_Trenes:
COM[m][1][t][d]=Madres[m][1][t][d]
COM[m][2][t][d]=Madres[m][2][t][d]
t=t+1
d=d-1
R1=Calculo_distancia(COM[m][2],COM[m][1],RUTAS,DIST,TOTAL_Trenes,Num_Lineas,Num_Dias)
COM[m][3]=R1[0]
COM[m][4]=R1[1]
COM[m][5]=Calculo_Dep(COM[m][2],DIST,TOTAL_Trenes,Num_Lineas,Num_Dias)
COM[m][0]=Fobj_Coste(COM[m][4],COM[m][5][1],TOTAL_Trenes,CV,CD,N_Sem)+FObj_Equibilibr
io(COM[m][3],TOTAL_Trenes)
m=m+1
return COM
################################################################################
def Combinar6(Padres,Madres,TOTAL_Trenes,RUTAS,DIST,Num_Lineas,Num_Dias,CV,CD,N_Sem):
#Opcion 6
import random
import math
COM=[]
INDI=len(Padres)
m=0
while m<INDI:
COM.append(Madres[m])
N_D=Num_Dias//4
d=Num_Dias-N_D-1
while d>N_D-1:
t=0
while t<TOTAL_Trenes:
COM[m][1][t][d]=Padres[m][1][t][d]
COM[m][2][t][d]=Padres[m][2][t][d]
t=t+1
d=d-1
d=Num_Dias-2*N_D-1
while d>N_D-1:
t=0
while t<TOTAL_Trenes:
COM[m][1][t][d]=Padres[m][1][t][d]
COM[m][2][t][d]=Padres[m][2][t][d]
t=t+1
127
d=d-1
R1=Calculo_distancia(COM[m][2],COM[m][1],RUTAS,DIST,TOTAL_Trenes,Num_Lineas,Num_Dias)
COM[m][3]=R1[0]
COM[m][4]=R1[1]
COM[m][5]=Calculo_Dep(COM[m][2],DIST,TOTAL_Trenes,Num_Lineas,Num_Dias)
COM[m][0]=Fobj_Coste(COM[m][4],COM[m][5][1],TOTAL_Trenes,CV,CD,N_Sem)+FObj_Equibilibr
io(COM[m][3],TOTAL_Trenes)
m=m+1
return COM
################################################################################
def Nueva_GENERACION(COM1,COM2,COM3,COM4,COM5,COM6,MUTS,PAPAS):
#Esta funcion coge los 4 conjuntos de individuos creados por las distintas
#combinaciones.
GEN=[]
i=0
while i<len(COM1[0]):
GEN.append(COM1[i])
GEN.append(COM2[i])
GEN.append(COM3[i])
GEN.append(COM4[i])
GEN.append(COM5[i])
GEN.append(COM6[i])
i=i+1
i=0
while i<len(MUTS):
GEN.append(MUTS[i])
i=i+1
return GEN
################################################################################
def Mejor_IND(GEN):
#Esta funcion crea 25 individuos nuevos a partir de 50 individuos
GEN.sort()
return GEN[0]
################################################################################
def main():
pass
if __name__ == '__main__':
main()
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
# Data Collection:
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
print("Cuanto dura el horizonte temporal de la inversion (en anos)")
N_years=int(input("Horizonte Temporal en anos:"))
print("Indoduce el nombre el archivo con la informacion del sistema ferroviario")
print("Recuerda incluir .xlsx al final del nombre")
XL_name=input("Archivo .xlsx= ")
book= xlrd.open_workbook(XL_name)
sheet1 = book.sheet_by_index(0)
sheet2 = book.sheet_by_index(1)
num_line=int(sheet1.cell(2,3).value)
num_dias=int(sheet2.cell(2,0).value)
N_Sem=N_years*365/num_dias
IT=10*num_dias
alfa=float(input('Coeficiente de Equilibrio= [0,1]: '))
129
#Coste de viajar en vacio:
CV=int(input("Coste de viajar en vacio ="))
#Coste de construir 1 deposito:
CD=int(input("Coste de contruir 1 deposito ="))
#Definimos primero los datos previamente conocidos
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
#Data Basica
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
DE=DATA_DE(XL_name,num_line)
RUTAS=Data_TrainSchedule(XL_name,num_dias,num_line)
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
# Muestra de datos finales
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
TpD=Trenes_por_dia(num_dias,num_line,RUTAS)
TOTAL_Trenes=max(TpD)
#print ("Numero minimo de trenes necesarios: ", TOTAL_Trenes)
print (" ")
wait = input("PRESS ANY KEY TO CONTINUE")
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
#Data de distancias entre estaciones
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
DIST=DATA_DE(XL_name,num_line)
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
#Algoritmo genetico
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
DISTANCIAS=0;
t=0;
while t<num_line:
DISTANCIAS=DISTANCIAS+DE[t][0][t][1]
t=t+1
MIN=CD*num_line+(CV*num_dias*DISTANCIAS*TOTAL_Trenes)*N_Sem
IDEAL=[MIN]
VAL=[]
MeM=[]
it=0
import time
time1=time.time()
SEL=int(input('Nº de Individuos Reproductores: '))
MUT=int(input('Nº de Individuos Mutados: '))
X=3*SEL+MUT
PAPAS=0.3*int(X)
if PAPAS%2!=0:
PAPAS=PAPAS+1
NGEN=int(input(‘Nº de Generaciones Máximos Creados: ’))
while it<IT:
# Creamos una poblacion inicial de X individuos:
GEN=Create_Random_popX(RUTAS,TpD,num_dias,num_line,TOTAL_Trenes,DIST,X,CV,CD,alfa)
#Pasamos 10 generaciones para encontrar una solucion. Escogeremos la mejor solucion
131
#de la undecima generacion.
gen=0
flag=IDEAL[0]
print (flag)
while flag>=MIN:
#Se realiza la seleccion y division de los individuos:
SEL_GEN=Genetic_selection(GEN)
#Introducimos mutaciones en los individuos seleciondos para MUTS:
MUTS=Mutacion(SEL_GEN[2],num_dias,num_line,TOTAL_Trenes,CV,CD,N_Sem,DIST)
#Creamos 100 individuos nuevos (25 por cada grupo) a partir de los individuos
#anteriores:
COM1=Combinar1(SEL_GEN[0][0],SEL_GEN[0][1],TOTAL_Trenes,RUTAS,DIST,num_line,num_dia
s,CV,CD,N_Sem)
COM2=Combinar3(SEL_GEN[1][0],SEL_GEN[1][1],TOTAL_Trenes,RUTAS,DIST,num_line,num_dia
s,CV,CD,N_Sem)
COM3=Combinar5(SEL_GEN[0][0],SEL_GEN[0][1],TOTAL_Trenes,RUTAS,DIST,num_line,num_dia
s,CV,CD,N_Sem)
COM4=Combinar2(SEL_GEN[1][0],SEL_GEN[1][1],TOTAL_Trenes,RUTAS,DIST,num_line,num_dia
s,CV,CD,N_Sem)
COM5=Combinar4(SEL_GEN[0][0],SEL_GEN[0][1],TOTAL_Trenes,RUTAS,DIST,num_line,num_dia
s,CV,CD,N_Sem)
COM6=Combinar6(SEL_GEN[1][0],SEL_GEN[1][1],TOTAL_Trenes,RUTAS,DIST,num_line,num_dia
s,CV,CD,N_Sem)
#Juntamos todos los individuos que constituiaran la nueva generarion:
GEN=Nueva_GENERACION(COM1,COM2,COM3,COM4,COM5,COM6,MUTS,PAPAS)
gen=gen+1
#Encontramos la mejor solucion de la nueva generacion:
IDEAL=Mejor_IND(GEN)
flag=IDEAL[0]
if gen>NGEN:
flag=0
MeM.append(IDEAL)
VAL.append(IDEAL[0])
MeM.sort()
if MIN>MeM[0][0]:
MIN=MeM[0][0]
else:
it=it+1
print( "Iteracion",it, "El minimo ahora es:",MIN)
print ("Iteracion",it, "El mejor es:",MeM[0][0])
time2=time.time()
gasto=time2-time1
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
#Resultados finales
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
Coste_Total=MeM[0][0]-FObj_Equibilibrio(MeM[0][3], TOTAL_Trenes)
Coste_Dep=CD*MeM[0][5][1]
Coste_Op=Coste_Total-Coste_Dep
Coste_Sem=Coste_Op/N_Sem
##########################################################################
## Create a workbook and add a worksheet.
workbook = xlsxwriter.Workbook('Resultados.xlsx')
worksheet1 = workbook.add_worksheet('RESUMEN DE DATOS')
133
worksheet1.write(0,0,'Resumen de Resultados')
#Datos generales
worksheet1.write(3,0,'Horizonte temportal:')
worksheet1.write(4,0,N_years)
worksheet1.write(4,1,'anos')
worksheet1.write(3,2,'Trenes Usados:')
worksheet1.write(4,2,TOTAL_Trenes)
worksheet1.write(4,3,'trenes')
worksheet1.write(3,4,'Nº de Depositos')
worksheet1.write(4,4,MeM[0][5][1])
worksheet1.write(4,5,'Depósitos')
#Se imprime la localización de los depositos:
dp1=0
while dp1<len(MeM[0][5][0]):
aux=0
while aux<2:
MeM[0][5][0][dp1][aux]+=1
aux+=1
dp1+=1
worksheet1.write(3,6,'Estaciones deposito:')
worksheet1.write(4,6,str(MeM[0][5][0]))
worksheet1.write(3,12,'Tiempo Usado')
worksheet1.write(4,12,gasto)
worksheet1.write(4,13,'Segundos')
worksheet1.write(3,8,'Coste Operacional Semanal')
worksheet1.write(4,8,Coste_Sem)
worksheet1.write(4,9,'Euros')
worksheet1.write(3,10,'Coste Operacional Semanal')
worksheet1.write(4,10,Coste_Op)
worksheet1.write(4,11,'Euros')
#Recorridos
rkm=8
worksheet1.write(6,1,'Km Semanales')
worksheet1.write(7,1,'Tren')
worksheet1.write(7,2,'Recorrido en Vacio')
worksheet1.write(7,3,'Recorrido Total')
while rkm<TOTAL_Trenes+8:
t=rkm-7
worksheet1.write(rkm,1,t)
worksheet1.write(rkm,2,MeM[0][4][t-1])
worksheet1.write(rkm,3,MeM[0][3][t-1])
rkm+=1
#Asignacion de Rutas
worksheet1.write(rkm+2,2,'Asignación de Trenes')
worksheet1.write(rkm+2,3,'X es Ruta, Y es Linea')
worksheet1.write(rkm+3,2,'Tren')
worksheet1.write(rkm+4,1,'Dia')
rtr=4+rkm;ctr=3
while ctr<TOTAL_Trenes+3:
t=ctr-2
worksheet1.write(rkm+3,ctr,t)
while rtr<num_dias+4+rkm:
d=rtr-3-rkm
worksheet1.write(rtr,2,d)
135
worksheet1.write(rtr,ctr,str(MeM[0][1][t-1][d-1]))
rtr+=1
rdp=rtr
rtr=4+rkm
ctr+=1
ctr=3
rdp=rdp+1
#Asignacion de Depositos
worksheet1.write(rdp,2,'Asignación de Depositos')
worksheet1.write(rdp,3,'[Linea 1[Estación 1,Estación 2], Linea 2[Estación 1,Estación 2]]')
worksheet1.write(rdp+1,2,'Tren')
worksheet1.write(rdp+2,1,'Dia')
rdp=rdp+2
rrr=rdp
while ctr<TOTAL_Trenes+3:
t=ctr-2
worksheet1.write(rdp-1,ctr,t)
while rrr< num_dias+rdp:
d=rrr-rdp+1
worksheet1.write(rrr,2,d)
worksheet1.write(rrr,ctr,str(MeM[0][2][t-1][d-1]))
rrr+=1
rrr=rdp
ctr+=1
################################################################################
################################################################################
import matplotlib.pyplot as plt
X_val=[]
k=0
while k<len(VAL):
X_val.append(k)
k=k+1
plt.plot(X_val,VAL)
plt.show()
################################################################################
print (" ")
print ("THE END")
print (" ")
wait=input("Press any key to end: ")
9.3 Anexo III
Rutas de la Red de Cercanía de Sevilla (simplificada) que satisfacen los servicios horarios previamente
definidos:
Linea 1 Estacion Inicio Estación Fin Kilometros Recorridos Linea 1 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 2 2 528 Ruta 1 2 1 594
Ruta 2 1 1 528 Ruta 2 1 2 462
Ruta 3 1 1 792 Ruta 3 1 1 792
Ruta 4 1 1 528 Ruta 4 1 1 528
Ruta 5 2 1 594 Ruta 5 2 1 594
Ruta 6 2 2 660 Ruta 6 2 2 660
Linea 2 Estacion Inicio Estación Fin Kilometros Recorridos Linea 2 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 1 1 280 Ruta 1 1 1 280
Linea 3 Estacion Inicio Estación Fin Kilometros Recorridos Linea 3 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 1 1 312 Ruta 1 1 1 312
Ruta 2 2 1 78 Ruta 2 2 1 78
Linea 4 Estacion Inicio Estación Fin Kilometros Recorridos Linea 4 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 1 2 429 Ruta 1 1 2 462
Ruta 2 2 1 495 Ruta 2 2 1 495
Ruta 3 2 1 495 Ruta 3 2 2 462
Linea 5 Estacion Inicio Estación Fin Kilometros Recorridos Linea 5 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 2 2 160 Ruta 1 2 2 160
Ruta 2 2 2 100 Ruta 2 2 2 100
Ruta 3 1 1 120 Ruta 3 1 1 120
Ruta 4 1 1 140 Ruta 4 1 1 140
Ruta 5 1 1 120 Ruta 5 1 1 120
Ruta 6 2 1 130 Ruta 6 2 1 130
DIA 1 DIA 2
137
Linea 1 Estacion Inicio Estación Fin Kilometros Recorridos Linea 1 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 2 1 594 Ruta 1 2 1 594
Ruta 2 1 2 462 Ruta 2 1 2 462
Ruta 3 1 2 726 Ruta 3 1 2 726
Ruta 4 1 1 528 Ruta 4 1 1 528
Ruta 5 2 1 594 Ruta 5 2 1 594
Ruta 6 2 2 660 Ruta 6 2 2 660
Linea 2 Estacion Inicio Estación Fin Kilometros Recorridos Linea 2 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 1 1 280 Ruta 1 1 1 280
Linea 3 Estacion Inicio Estación Fin Kilometros Recorridos Linea 3 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 1 1 312 Ruta 1 1 1 312
Ruta 2 2 1 78 Ruta 2 2 1 78
Linea 4 Estacion Inicio Estación Fin Kilometros Recorridos Linea 4 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 1 2 462 Ruta 1 1 2 429
Ruta 2 2 1 495 Ruta 2 2 1 495
Ruta 3 2 2 462 Ruta 3 2 1 495
Linea 5 Estacion Inicio Estación Fin Kilometros Recorridos Linea 5 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 2 2 160 Ruta 1 2 2 160
Ruta 2 2 2 100 Ruta 2 2 2 100
Ruta 3 1 1 120 Ruta 3 1 1 120
Ruta 4 1 1 140 Ruta 4 1 1 140
Ruta 5 1 1 120 Ruta 5 1 1 120
Ruta 6 2 1 130 Ruta 6 2 1 130
DIA 3 DIA 4
Linea 1 Estacion Inicio Estación Fin Kilometros Recorridos Linea 1 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 2 1 594 Ruta 1 2 1 594
Ruta 2 1 2 462 Ruta 2 1 1 792
Ruta 3 1 2 726 Ruta 3 1 1 528
Ruta 4 1 1 528
Ruta 5 2 1 594
Ruta 6 2 2 660 Linea 2 Estacion Inicio Estación Fin Kilometros Recorridos
1 1 120
Linea 2 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 1 1 280 Linea 3 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 2 1 234
Ruta 2 2 1 78
Linea 3 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 1 1 312
Ruta 2 2 1 78 Linea 4 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 1 2 363
Ruta 2 2 1 231
Linea 4 Estacion Inicio Estación Fin Kilometros Recorridos Ruta 3 2 1 231
Ruta 1 1 2 462
Ruta 2 2 1 495
Ruta 3 2 2 462 Linea 5 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 2 2 160
Ruta 2 2 2 100
Linea 5 Estacion Inicio Estación Fin Kilometros Recorridos Ruta 3 1 1 140
Ruta 1 2 2 160 Ruta 4 2 1 130
Ruta 2 2 2 100
Ruta 3 1 1 120
Ruta 4 1 1 140
Ruta 5 1 1 120
Ruta 6 2 1 130
DIA 6DIA 5
9.4 Anexo IV
Instrucciones de creación de hoja de cálculo de introducción de datos. Esta hoja de cálculo se debe guardar
en la misma carpeta que el código del programa.
A la hora de crear la hoja de cálculo, es necesario cumplir con la siguiente estructura:
1. La primera hoja debe contener el número de líneas y la matriz de distancias entre estaciones límite
de todas las líneas. Además, para el funcionamiento correcto del programa, se deben colocar los
datos en los espacios indicados deacuerdo al siguiente ejemplo:
El número de líneas debe estar en la celda 3D. La matriz de distancias debe ser una matriz simétrica
que comienza en la celda 6B.
Linea 1 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 2 1 594
Ruta 2 1 1 792
Ruta 3 1 1 528
Linea 2 Estacion Inicio Estación Fin Kilometros Recorridos
1 1 120
Linea 3 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 2 1 234
Ruta 2 2 1 78
Linea 4 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 1 2 363
Ruta 2 2 1 231
Ruta 3 2 1 231
Linea 5 Estacion Inicio Estación Fin Kilometros Recorridos
Ruta 1 2 2 160
Ruta 2 2 2 100
Ruta 3 1 1 140
Ruta 4 2 1 130
DIA 7
139
2. La segunda hoja debe contener el número de días y el número de rutas por línea y por día. Al igual
que antes, se debe rellenar la hoja de cálculo siguiendo la estructura definida en el siguiente
ejemplo:
El número de días del conjunto D, o que forman una semana debe colocarse en la celda 2A. El
número de rutas que se realizan en cada línea y en cada día se debe rellenar entero. Si no se realiza
ninguna ruta, se debe colocar un 0. Por tanto, debe haber una matriz de Numero Líneas x Número
de Días cuyo valor [0,0] debe de colocarse en la celda 7B, y los demás valores se deben de colocar
en función de esta.
3. La tercera y última hoja debe contener la información de las rutas. Es decir, se debe de incluir
todos los datos que definen cada una de las rutas. Igualmente, se debe de seguir la siguiente
estructura al rellenar la hoja de cálculo para asegurar el correcto funcionamiento del programa:
La estación de inicio se indica con un 1 si se comienza la ruta en la estación 1, y un 2 si comienza
la ruta en la estación 2. Los kilómetros totales recorridos se indican a continuación.
A la hora de añadir rutas y días, se debe asegurar que coincidan con los datos introducidos en las
hojas anteriores.
Deben haber 2 filas vacías entre la última ruta de una línea y el cabecero de la siguiente línea, en un
mismo días. Debe haber una columna vacía entre un día y otro.
9.5 Anexo V
Instrucciones de lectura de datos de hoja de resultados.
La hoja de resultados se crea al final del programa bajo el nombre ‘Resultados.xlsx’, en la carpeta donde se
encuentra el código del programa.
Todos los resultados se imprimen en la misma hoja.
En las filas 5 y 6 se muestran los datos resumidos de la solución que el algoritmo. Estos incluyen:
- Duración del Horizonte temporal en años
- Número de trenes totales necesarios para el sistema
- Las estaciones límite que son depósito
- El número de depósitos del sistema
- El coste operacional semanal
- El coste operacional total
- El tiempo usado en completar el algoritmo.
A continuación se muestra el resumen de los kilómetros recorridos por cada tren a lo largo de los días del
conjunto D, tanto los recorridos en vacío (traslados sin pasajeros) y recorridos totales.
En las filas posteriores a los recorridos se muestra la matriz de asignación de rutas a trenes. Esta matriz tiene
dimensiones Número de Trenes x Número de Días. Cada elemento de esta matriz contiene dos valores [X,Y]
donde Y es la línea y R es la ruta de esta línea.
Finalmente, tras la matriz de asignación, se muestra la matriz de uso de depósitos, de las mismas dimensiones
que la matriz anterior (Número de Trenes x Número de Días). Muestra todos los depósitos posibles a usar,
donde el valor 1 indica el depósito realmente usado por el tren t al final del día d-1 y al inicio del día d.
141
10 BIBLIOGRAFÍA
[1] Alberto Téllez, (2015). PFC GESTIÓN DE MATERIAL RODANTE Y LOCALIZACIÓN DE
DEPÓSITOS EN REDES DE FERROCARRIL DE TRÁNSITO RÁPIDO, Dep. Organización y Gestión
de Empresas I, Escuela Técnica Superior de Ingeniería, Universidad de Sevilla
[2] España. Ley 38/2015, de 29 de septiembre, del sector ferroviario, Boletín Oficial del Estado, de 30 de
septiembre de 2015, núm. 234
[3] Gandomi, A.H., Yang, X.S., Talatahari, S. and Alavi, A.H., 2013. Metaheuristic algorithms in modeling
and optimization. Metaheuristic Applications in Structures and infrastructures, edited by Amir Hossein
GandomiXin-She YangSiamak TalatahariAmir Hossein Alavi, Elsevier, Oxford, pp.1-24.
[4] Dorigo, M., Di Caro, G. and Gambardella, L.M., 1999. Ant algorithms for discrete optimization.
Artificial life, 5(2), pp.137-172.
[5] Johnson, D.S., Aragon, C.R., McGeoch, L.A. and Schevon, C., 1989. Optimization by simulated
annealing: an experimental evaluation; part I, graph partitioning. Operations research, 37(6), pp.865-892.
[6] Glover, F., 1989. Tabu search-part I. ORSA Journal on computing, 1(3), pp.190-206.
[7] Shi, Y., 2001. Particle swarm optimization: developments, applications and resources. In
evolutionary computation, 2001. Proceedings of the 2001 Congress on (Vol. 1, pp. 81-86). IEEE.
[8] Geem, Z.W., Kim, J.H. and Loganathan, G.V., 2001. A new heuristic optimization algorithm:
hamony search. Simulation, 76(2), pp.60-68.
[9] Erol, O.K. and Eksin, I., 2006. A new optimization method: big bang–big crunch. Advances in
Engineering Software, 37(2), pp.106-111.
[10] Yang, X.S., 2009, October. Firefly algorithms for multimodal optimization. In International
Symposium on Stochastic Algorithms (pp. 169-178). Springer Berlin Heidelberg.
[11] Yang, X.S. and Deb, S., 2009, December. Cuckoo search via Lévy flights. In Nature &
Biologically Inspired Computing, 2009. NaBIC 2009. World Congress on (pp. 210-214). IEEE.
[12] Galante, Miguel. "Genetic algorithms as an approach to optimize real‐ world trusses."
International Journal for Numerical Methods in Engineering 39.3 (1996): 361-382.
[13] Darwin, Charles. El origen de las especies. SELECTOR, 2016.