En Ingeniería de Tecnologías Industriales, Intensificación...

142
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

Transcript of En Ingeniería de Tecnologías Industriales, Intensificación...

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

5

A mi familia

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:

51

Figura 14. Diagrama de Flujo del Algoritmo Diseñado

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

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

vehículos y localcización de depósitos de redes ferroviarios de tránsito rápido.

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.