Commit 5a414d96 authored by Alexandre Gondran's avatar Alexandre Gondran
Browse files

modif du TP1 2021

parent 15525033
No preview for this file type
This diff is collapsed.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%% pdflatex -shell-escape tpgraph1.tex %%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\documentclass[a4paper, 10pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[francais]{babel}
\usepackage{a4}
%\usepackage{url}
\usepackage{hyperref}
%\usepackage[french,algonl,ruled]{algorithm2e}
\usepackage{amssymb}
\usepackage{xcolor}
\usepackage{minted}
\topmargin -2cm
%\oddsidemargin -1cm
%\evensidemargin -1cm
%\headsep 1cm
%\headheight 0.5cm
\textheight 25.5cm
%\textwidth 18cm
%\parindent 0.0cm
%\lefthyphenmin 2
%\righthyphenmin 2
\title{TP Graphes et Réseaux 1}
\author{Simon de Givry et George Katsirelos}
\date{9 octobre 2020}
\begin{document}
\maketitle
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Préliminaires}
Le TP est noté~: envoyez vos réponses à \texttt{simon.de-givry@inrae.fr} sous forme d'un petit document (LibreOffice, Word) en reprenant les numéros de section pour vos réponses et en ajoutant en pièces jointes vos codes python.
Précisez moi dans le message votre environnement de travail (Ubuntu ENAC/domicile, Windows domicile, Mac domicile).
\subsection{Installation sous Windows à la maison}~\label{windows}
Installer {\sf Visual Studio 2019} Communauté \url{https://visualstudio.microsoft.com/fr/downloads}.
Lors de l'installation, choisir de modifier l'installation par défaut, en incluant dans "Charge de travail" le module "Développement Python" avec Python 2.
Pour la partie sur les problèmes de tournées, installer {\sf Concorde} (Windows GUI) \url{http://www.math.uwaterloo.ca/tsp/concorde.html}. Télécharger \texttt{LKH-2.exe} \url{http://webhotel4.ruc.dk/~keld/research/LKH}, à copier dans le répertoire \texttt{tpgraph1/tsp} (voir plus loin).
Pour la partie sur la coloration de graphe, installer {\sf MiniZinc} \url{https://www.minizinc.org}.
Installation optionnelle~: {\sf or-tools} \url{https://developers.google.com/optimization} en téléchargeant la version {\em FlatZinc Binary distribution}.
Ouvrez le fichier \texttt{tpgraph1win.zip} à l'adresse
\url{https://forgemia.inra.fr/degivry/enac/raw/master/tpgraph1win.zip}
Décompactez le dossier \texttt{tpgraph1} dans \texttt{Documents}.
Démarrer Visual Studio 2019 et créer un nouveau projet en sélectionnant le répertoire \texttt{Documents/tpgraph1/tsp}. Choisir l'environnement Python 2.7 et finir l'installation en ajoutant le package {\sf networkx} (cliquer sur l'icone juste à droite du choix de Python 2.7).
\subsection{Installation sous Ubuntu dans une salle TP à l'ENAC}~\label{ubuntu}
Démarrer sous Linux Ubuntu et ouvrez le fichier \texttt{tpgraph1.zip} à l'adresse
\url{https://forgemia.inra.fr/degivry/enac/raw/master/tpgraph1.zip}
Décompactez le dossier \texttt{tpgraph1} dans \texttt{/tmp} puis ouvrez un terminal de commandes {\sf xterm} et aller dans le dossier du TP en faisant \texttt{cd /tmp/tpgraph1}.
Les différents solvers utiles à ce TP ainsi que leur documentation dont celle de la librairie python {\sf networkx} d'algorithmes sur les graphes se trouvent dans le dossier \texttt{solvers}.
Lancer les commandes {\sf bash} suivantes pour avoir accès à ces solvers~:
%\texttt{chmod -R 755 solvers}\\
%\texttt{PATH=\$PATH:/tmp/tpgraph1/solvers:/tmp/tpgraph1/solvers/gecode:.}\\
%\texttt{LD\_LIBRARY\_PATH=/tmp/tpgraph1/solvers/gecode:.}\\
%\texttt{export LD\_LIBRARY\_PATH}\\
\begin{minted}{bash}
chmod -R 755 solvers
PATH=$PATH:/tmp/tpgraph1/solvers:/tmp/tpgraph1/solvers/gecode:.
LD_LIBRARY_PATH=/tmp/tpgraph1/solvers/gecode:.
export LD_LIBRARY_PATH
\end{minted}
\subsection{Installation sous Ubuntu à la maison}
Installer Python2 et la librairie {\sf networkx}~:
%\texttt{sudo apt update}\\
%\texttt{sudo apt upgrade}\\
%\texttt{sudo apt install python2.7}\\
%\texttt{sudo apt install python-pip}\\
%\texttt{sudo pip install networkx}\\
\begin{minted}{bash}
sudo apt update
sudo apt upgrade
sudo apt install python2.7
sudo apt install python-pip
sudo pip install networkx
\end{minted}
Puis suivre les instructions à la Section~\ref{ubuntu}.
\subsection{Installation sous MacOS à la maison}
Installer la version Mac OS X de Visual Studio 2019 Communauté (pour avoir Python 2) et celle de MiniZinc ainsi que or-tools (optionnel), en suivant les instructions données en Section~\ref{windows}.
Il n'existe pas de version Mac OS X de LKH et Concorde, ne pas faire les questions des Sections~\ref{francecmp} et~\ref{monde}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Construction de tournées d'aéroports (10 pts)}
Sous Ubuntu, allez dans le dossier \texttt{/tmp/tpgraph1/tsp}. Sous Windows/Mac, vous avez déjà ouvert \texttt{tpgraph1/tsp} sous Visual Studio 2019.
\subsection{Tournée des aéroports de France}
Le fichier \texttt{france.geo} contient les coordonnées latitude/longitude en degré des principaux aéroports français.
\subsubsection{Obtention d'un minorant à l'aide de l'arbre couvrant (2 pts)}
Modifier le fichier python \texttt{airports.py} pour calculer un minorant du tour des aéroports français.
Pour cela, utiliser la fonction \texttt{minimum\_spanning\_tree} dans {\sf networkx}, en s'inspirant de l'exemple donné dans la documentation \texttt{networkx.pdf}.
Donner la valeur du minorant trouvé.
\subsubsection{Obtention d'un majorant à l'aide de l'heuristique nearest neihbor (4 pts)}
Construire un tour approché en utilisant l'heuristique {\em nearest neihbor}. Il s'agit de partir d'un sommet quelconque puis d'ajouter successivement le plus proche voisin non visité jusqu'à inclure tous les sommets et revenir au sommet initial. Donner la valeur du majorant trouvé.
Quelle est la complexité de votre algorithme en fonction du nombre d'aéroports ?
\subsubsection{Comparaison avec des solvers exacts et approchés (2 pts)}~\label{francecmp}
Comparer en terme de coût et de temps de calcul le solver de recherche locale {\sf LKH} contre une méthode exacte utilisant la programmation linéaire {\sf concorde}. Donner les résultats de votre comparaison. Que concluez vous par rapport à la solution trouvée dans la section précédente ?
Commandes pour exécuter les solvers sous Ubuntu~:\\
\texttt{LKH france.par}\\
\texttt{concorde france.tsp}\\
Sous Windows, il faut ouvrir une {\em Invite de commandes} dans \texttt{Accessoires}, aller dans le répertoire \texttt{Documents/tpgraph1/tsp} et exécuter\\
\texttt{LKH-2.exe france.par}\\
Pour Concorde, il faut charger \texttt{france\_concorde\_windows.tsp} et choisir \texttt{Edges/Set Edge Norm/Geographic} avant de faire \texttt{Solve}.
\subsection{Tournée mondiale (2 pts)}~\label{monde}
Le fichier \texttt{airports.geo} contient les coordonnées latitude/longitude en degré des principaux aéroports internationaux.
Sachant la vitesse de croisière du concorde à 2 158 km/h, en déduire une estimation du temps nécessaire pour survoler tous les aéroports (sans limite de carburant).
Commandes pour exécuter les solvers sous Ubuntu~:\\
\texttt{LKH airports.par}\\
\texttt{concorde airports.tsp}\\
Sous Windows, faire de même que précédemment.
Pour Concorde, utiliser \texttt{airports\_concorde\_windows.tsp}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Construction de routes aériennes (10 pts)}
Sous Ubuntu, aller dans le dossier \texttt{/tmp/tpgraph1/coloring}.
Sous Windows/Mac, ouvrir le dossier local \texttt{Documents/tpgraph1/coloring} avec Visual Studio 2019.
Les fichiers \texttt{flightsA01.txt} et \texttt{flightsB01.txt} contiennent des listes de vols directs de British Airways.
On cherche à attribuer un niveau de vol à chaque route aérienne (correspondant à un ensemble de vols effectuant le même trajet) de manière que si deux routes se croisent alors elles utilisent un niveau différent.
\subsection{Nombre chromatique du graphe d'intersections (6 pts)}
En utilisant le script python2 \texttt{flights.py} et le théorème de Brooks, donner un minorant et un majorant du nombre chromatique pour chaque liste de vols.
Utiliser les fonctions {\sf networkx} \texttt{graph\_clique\_number} et \texttt{G.degree}.
Comparer avec la solution trouvée par l'heuristique DSATUR sur les deux scénarios (fonction {\sf networkx} \texttt{greedy\_color}).
Générer ensuite un problème au format {\sf MiniZinc} de coloration du graphe d'intersections avec $k$ couleurs.
Résoudre ce problème à l'aide du solver {\sf mzn-gecode}.
Trouver le nombre chromatique pour les deux scénarios.
Prouver leur optimalité. Expliquer votre démarche.
Commandes sous Ubuntu pour générer le problème et exécuter le solver avec $k=10$ couleurs sur le premier scénario~:\\
\texttt{python2 flights.py airports.geo flightsA01.txt 10}\\
\texttt{../solvers/gecode/mzn-gecode -s flightsA01.mzn}\\
Sous Windows/Mac, avec Visual Studio 2019, modifier le fichier \texttt{flights.py} suivant le scénario choisi et le nombre de couleurs voulu.
Exécuter le code \texttt{flights.py} pour générer le fichier \texttt{.mzn} correspondant.
Double-cliquer dessus pour lancer MiniZinc IDE et le résoudre.
\subsection{Amélioration des performances de la résolution (2 pts)}
Modifier \texttt{flights.py} pour ajouter dans le modèle {\sf MiniZinc} généré des contraintes \texttt{alldifferent} pour l'ensemble des cliques du graphe d'intersection (fonction {\sf networkx} \texttt{find\_cliques}).
Est ce que cela permet de réduire le nombre de noeuds de l'arbre de recherche pour la preuve d'optimalité ? de réduire le temps de résolution ? Tester sur les deux scénarios et donner vos résultats.
Exemple de syntaxe {\sf MiniZinc} pour définir une clique sur les sommets $(6,17,19,57,63)$~:\\
\texttt{constraint alldifferent([x6, x17, x19, x57, x63]);}\\
Comparer avec un modèle n'ajoutant qu'une seule clique maximale par sommet (fonction {\sf networkx} \texttt{cliques\_containing\_node}).
\subsection{Minimisation des écarts au niveau de vol optimal (2 pts)}
On suppose que les avions préfèrent le niveau 0 ou sinon un niveau proche.
Modéliser la somme des écarts au niveau de vol optimal comme une somme sur les variables du problème.
Minimiser cette somme. Donner votre meilleur résultat.
Exemple de syntaxe {\sf MiniZinc} pour minimiser une somme sur les sommets $(6,7,8,9)$~:\\
\texttt{solve minimize sum([x6, x7, x8, x9]);}\\
\texttt{output [show(sum([x6, x7, x8, x9]))];}\\
Commande sous Ubuntu pour exécuter le solver en mode optimisation et voir les solutions intermédiaires~:\\
\texttt{../solvers/gecode/mzn-gecode -s -a flightsA01.mzn}\\
Sous Windows/Mac, vous pouvez directement lancer la résolution par défaut avec {\sf gecode} ou bien ajouter un nouveau solver en indiquant le lien vers l'exécutable {\sf fzn-or-tools} et en cochant toutes les options (v,s,\ldots).
\end{document}
This diff is collapsed.
import sys
import networkx as nx
import matplotlib.pyplot as plt
################################## compute if there is an intersection between two routes A-B and C-D
def getIntersectionPoint(_A_x, _A_y, _B_x, _B_y, _C_x, _C_y, _D_x, _D_y, m = 0., k = 0., diviseur = 1., P_x = 0., P_y = 0.):
if ((_A_x==_C_x and _A_y==_C_y) or (_A_x==_D_x and _A_y==_D_y) or (_B_x==_C_x and _B_y==_C_y) or (_B_x==_D_x and _B_y==_D_y)):
return False
I_x = _B_x - _A_x
I_y = _B_y - _A_y
J_x = _D_x - _C_x
J_y = _D_y - _C_y
diviseur = (I_x * J_y - I_y * J_x)
if(diviseur == 0):
return False
m = (I_x * _A_y - I_x * _C_y - I_y * _A_x + I_y * _C_x ) / diviseur
k = (J_x * _A_y - J_x * _C_y - J_y * _A_x + J_y * _C_x ) / diviseur
P_x = _C_x + m * J_x
P_y = _C_y + m * J_y
if ((P_x <= _A_x and P_x <= _B_x) or (P_x >= _A_x and P_x >= _B_x) or (P_y <= _A_y and P_y <= _B_y) or (P_y >= _A_y and P_y >= _B_y)):
return False
if ((P_x <= _C_x and P_x <= _D_x) or (P_x >= _C_x and P_x >= _D_x) or (P_y <= _C_y and P_y <= _D_y) or (P_y >= _C_y and P_y >= _D_y)):
return False
return True
# read airport positions
def read_airports(filename):
x = {} # latitude of airports
y = {} # longitude of airports
with open(filename, "r") as file:
for line in file:
line = line.split()
name,xs,ys = list(line)
x[name]=float(xs)
y[name]=float(ys)
return x, y
# read direct flight planning
def read_routes(filename):
routes = {} # list of different routes
with open(filename, "r") as file:
for line in file:
ident,source,destination,departuretime,arrivaltime = list(line.split())
key = (source, destination) if (source < destination) else (destination, source)
routes[key] = 1
return routes
def buildGraph(routes, x, y):
n = len(routes)
# associate an identification number to every route
order = list(sorted(routes))
# create the intersection graph
G = nx.Graph()
G.add_nodes_from(range(n))
for i,r1 in enumerate(order):
for j,r2 in enumerate(order):
if (i < j):
if getIntersectionPoint(x[r1[0]],y[r1[0]],x[r1[1]],y[r1[1]],x[r2[0]],y[r2[0]],x[r2[1]],y[r2[1]]):
G.add_edge(i,j)
return G
def build_minizinc_file(filename_routes, G, colormax, allCliques=False, oneCliquePerNode=False, sumcoloring=False):
# output the associated coloring problem
output = filename_routes.replace(".txt",f"_{colormax}.mzn")
with open(output, 'w') as file :
file.write("%coloring flights\n")
file.write('include "globals.mzn";\n')
for v in G.nodes():
file.write(f"var 0..{colormax-1}: x{v};\n")
for i,j in G.edges():
file.write(f"constraint x{i} != x{j};\n")
# add cliques here ...
file.write("solve satisfy;\n")
strliste = ",".join([f'"\\t x{v}=",show(x{v})' for v in G.nodes()])
file.write(f"output [{strliste}];\n")
################################### main program
if __name__ == "__main__":
n = len(sys.argv)
if n < 3 or n > 4:
print("Usage : python flights.py <filename_airports> <filename_routes> [<colormax=100>]")
print("Example : python flights.py airports.geo flightsA01.txt")
else :
filename_airports = sys.argv[1]
filename_routes = sys.argv[2]
colormax = 100 if n != 4 else int(sys.argv[3]) # number of colors
x, y = read_airports(filename_airports) # latitude/longitude of airports
routes = read_routes(filename_routes) # list of different routes
n = len(routes)
print(f"found {n} different routes")
G = buildGraph(routes, x, y)
nx.draw(G) # make this line a comment to skip it
plt.show() # make this line a comment to skip it
#print("lower bound on chromatic number is ...)
#print("upper bound on chromatic number is ...)
# DSATUR glouton ....
# modif de build_minizinc_file(...)
145 CDG MLH 08:05 09:15
146 MLH CDG 09:55 11:10
147 CDG MLH 12:00 13:10
148 MLH CDG 13:50 15:05
149 CDG MLH 15:45 16:55
150 MLH CDG 17:35 18:50
151 CDG MLH 19:55 21:05
152 MLH CDG 06:05 07:20
1363 ORY AJA 08:25 10:05
1364 AJA ORY 05:55 07:35
1374 BIA ORY 05:55 07:30
1375 ORY BIA 13:25 15:00
1377 ORY BIA 19:00 20:35
1378 BIA ORY 11:00 12:35
1379 ORY BIA 08:30 10:05
1380 BIA ORY 15:50 17:25
2517 TLS NTE 12:15 13:15
2518 NTE TLS 10:45 11:45
2519 TLS NTE 08:55 09:55
2520 NTE TLS 07:25 08:25
2521 RNS MPL 09:50 11:05
2522 MPL RNS 11:35 12:55
2523 ORY UIP 07:45 08:50
2524 UIP ORY 05:45 06:55
2525 ORY UIP 16:35 17:40
2526 UIP ORY 09:45 10:55
2533 NTE BES 10:55 11:35
2534 BES NTE 06:00 06:45
2543 RDZ ORY 05:40 06:50
2544 ORY RDZ 07:25 08:30
2573 LIG ORY 05:30 06:35
2574 ORY LIG 08:00 09:00
2581 LIG CDG 10:05 11:20
2582 CDG LIG 12:30 13:45
2583 RNS CDG 05:25 06:25
2584 CDG RNS 12:30 13:35
2585 RNS CDG 14:55 15:55
2586 CDG RNS 19:00 19:55
2587 CFR LYS 05:25 06:35
2588 LYS CFR 07:40 08:55
2593 LIG LYS 05:35 06:35
2595 CFR LYS 12:30 13:40
2596 LYS CFR 15:00 16:15
2597 LEH URO 05:00 05:20
2598 URO LYS 05:40 07:00
2599 LYS LEH 07:40 09:10
2600 LEH URO 09:30 09:50
2601 URO LEH 15:00 15:20
2602 LEH LYS 15:40 17:10
2603 LYS URO 17:50 19:10
2604 URO LEH 19:30 19:50
2605 RNS TLS 06:40 07:45
2606 TLS RNS 08:10 09:20
2609 NCE RNS 14:05 15:45
2610 RNS NCE 07:00 08:35
2613 RNS LYS 05:30 06:45
2614 LYS RNS 07:45 09:05
2619 RNS LYS 12:35 13:50
2620 LYS RNS 14:45 16:05
2623 MRS NTE 09:00 10:25
2624 NTE MRS 07:05 08:25
2625 MRS NTE 15:45 17:10
2626 NTE MRS 13:50 15:10
2629 MRS NTE 12:55 14:20
2630 NTE MRS 11:00 12:20
2633 SXB NTE 09:05 10:25
2634 NTE SXB 07:15 08:35
2643 LYS SXB 15:00 16:00
2644 SXB LYS 13:10 14:10
2647 LYS SXB 07:40 08:40
2648 SXB LYS 05:50 06:50
2653 BES LYS 05:25 06:55
2654 LYS BES 07:40 09:15
2655 BES LYS 12:20 13:50
2656 LYS BES 14:30 15:55
2657 BES MRS 10:05 11:45
2658 MRS BES 12:25 14:05
2661 NCE BES 09:10 11:05
2662 BES NCE 11:45 13:35
2663 NCE FSC 17:30 18:25
2673 SXB LGW 05:55 07:20
2674 LGW SXB 07:55 09:25
2793 LRT ORY 06:00 07:10
2794 ORY LRT 07:55 09:00
2795 LRT ORY 09:45 10:50
2796 ORY LRT 12:10 13:15
2797 LRT ORY 14:00 15:05
2798 ORY LRT 13:00 14:05
2866 MRS ORY 05:30 06:50
2867 ORY MRS 19:10 20:25
2868 MRS ORY 07:30 08:50
2869 ORY MRS 12:10 13:25
2870 MRS ORY 17:00 18:20
2872 MRS ORY 06:30 07:50
2873 ORY MRS 07:35 08:50
2874 MRS ORY 14:00 15:20
2877 ORY MRS 09:35 10:50
2878 MRS ORY 14:55 16:05
2879 ORY MRS 08:35 09:50
2883 ORY MRS 11:35 12:50
2886 MRS ORY 10:30 11:50
2888 MRS ORY 11:30 12:50
2889 ORY MRS 13:35 14:50
2892 MRS ORY 13:30 14:50
2895 ORY MRS 15:35 16:50
2896 MRS ORY 14:30 15:50
2899 ORY MRS 16:35 17:50
2900 MRS ORY 15:30 16:50
2903 ORY MRS 17:35 18:50
2907 ORY MRS 18:35 19:50
2908 MRS ORY 17:30 18:50
2912 MRS ORY 18:30 19:50
2919 ORY MRS 12:35 13:50
2965 ORY TLS 05:50 07:00
2966 TLS ORY 05:40 07:00
2967 ORY TLS 18:25 19:45
2968 TLS ORY 06:10 07:30
2969 ORY TLS 06:50 08:00
2970 TLS ORY 06:40 08:00
2972 TLS ORY 09:10 10:30
2973 ORY TLS 07:50 09:00
2974 TLS ORY 07:40 09:00
2975 ORY TLS 08:50 10:00
2976 TLS ORY 08:40 10:00
2977 ORY TLS 09:50 11:00
2978 TLS ORY 08:10 09:30
2980 TLS ORY 09:40 11:00
2981 ORY TLS 10:50 12:00
2982 TLS ORY 10:40 12:00
2983 ORY TLS 11:50 13:00
2984 TLS ORY 11:40 13:00
2985 ORY TLS 12:50 14:00
2986 TLS ORY 12:40 14:00
2988 TLS ORY 13:40 15:00
2989 ORY TLS 13:50 15:00
2991 ORY TLS 14:50 16:00
2992 TLS ORY 14:40 16:00
2995 ORY TLS 15:50 17:00
2996 TLS ORY 15:40 17:00
2999 ORY TLS 16:50 18:00
3000 TLS ORY 16:40 18:00
3003 ORY TLS 17:50 19:00
3004 TLS ORY 17:40 19:00
3007 ORY TLS 18:50 20:00
3008 TLS ORY 18:40 20:00
3011 ORY TLS 19:50 21:00
3063 ORY NCE 14:00 15:25
3064 NCE ORY 06:05 07:30
3065 ORY NCE 07:00 08:20
3067 ORY NCE 07:30 08:50
3068 NCE ORY 08:05 09:30
3069 ORY NCE 08:00 09:20
3070 NCE ORY 09:05 10:30
3071 ORY MRS 19:20 20:35
3073 ORY NCE 10:00 11:20
3074 NCE ORY 10:05 11:30
3075 ORY NCE 11:00 12:20
3076 NCE ORY 11:35 13:00
3077 ORY NCE 12:00 13:20
3080 NCE ORY 13:05 14:30
3081 ORY NCE 14:00 15:20
3082 NCE ORY 14:05 15:30
3083 ORY NCE 15:00 16:20
3084 NCE ORY 15:05 16:30
3085 ORY NCE 16:00 17:20
3086 NCE ORY 12:35 14:00
3088 NCE ORY 12:05 13:30
3090 NCE ORY 17:05 18:30
3091 ORY NCE 13:00 14:20
3092 NCE ORY 18:05 19:30
3093 ORY NCE 19:00 20:20
3094 NCE CFE 19:25 20:25
3095 ORY NCE 20:00 21:20
3097 ORY NCE 10:35 11:55
3099 ORY NCE 17:10 18:30
3102 NCE ORY 16:05 17:30
3103 ORY NCE 06:00 07:20
3106 NCE ORY 17:05 18:30
3107 ORY NCE 06:30 07:50
3108 NCE ORY 08:35 10:00
3111 ORY NCE 11:30 12:50
3112 NCE ORY 13:35 15:00
3117 ORY BOD 07:15 08:20
3118 BOD ORY 06:10 07:20
3119 ORY BOD 08:10 09:15
3121 ORY BOD 10:10 11:15
3122 BOD ORY 08:00 09:10
3123 ORY BOD 12:10 13:15
3124 BOD ORY 10:05 11:15
3127 ORY BOD 15:10 16:15
3128 BOD ORY 14:05 15:15
3131 ORY BOD 17:25 18:30
3134 BOD ORY 17:05 18:15
3135 ORY BOD 17:10 18:15
3138 BOD ORY 19:25 20:35
3144 BOD ORY 09:10 10:20
4164 SXB ORY 07:00 08:00
4165 ORY SXB 08:00 09:00
4167 ORY SXB 10:25 11:25
4168 SXB ORY 08:10 09:10
4169 ORY SXB 20:00 21:00
4170 SXB ORY 10:10 11:10
4171 ORY SXB 14:25 15:25
4174 SXB ORY 13:35 14:35
4180 SXB ORY 17:00 18:00
4189 ORY SXB 19:25 20:25
4194 MLH ORY 05:30 06:40
4195 ORY MLH 08:15 09:15
4197 ORY MLH 12:10 13:10
4200 MLH ORY 10:05 11:15
4202 MLH ORY 13:55 15:05
4203 ORY MLH 18:45 19:45
4213 RNS ORY 14:00 15:05
4214 ORY RNS 16:15 17:15
4224 BES ORY 05:35 06:50
4225 ORY BES 08:10 09:20
4228 BES ORY 10:05 11:20
4229 ORY BES 11:15 12:25
4232 BES ORY 13:05 14:20
4237 ORY BES 20:20 21:30
4238 BES ORY 16:35 17:50
4239 ORY BES 14:40 15:50
4264 LYS ORY 05:50 06:55
4265 ORY LYS 07:40 08:45
4268 LYS ORY 09:30 10:35
4269 ORY LYS 09:30 10:35
4270 LYS ORY 11:20 12:25
4271 ORY LYS 13:40 14:45
4272 LYS ORY 13:10 14:15
4273 ORY LYS 11:20 12:25
4274 LYS ORY 16:50 17:55
4275 ORY LYS 18:40 19:45
4276 LYS ORY 16:10 17:15
4279 ORY LYS 15:00 16:05
4295 ORY CFE 08:10 09:05
4296 CFE ORY 05:40 06:35
4298 CFE ORY 09:50 10:45
4301 ORY CFE 16:55 17:50
4314 PUF ORY 05:40 07:00
4315 ORY PUF 08:00 09:15
4317 ORY PUF 12:05 13:20
4319 ORY PUF 16:20 17:35
4320 PUF ORY 10:10 11:30
4321 ORY PUF 20:25 21:40
4322 PUF ORY 14:10 15:30
4324 PUF ORY 18:30 19:50
4333 ORY AVN 08:15 09:30
4334 AVN ORY 05:30 06:45
4336 AVN ORY 10:05 11:20
4337 ORY AVN 12:20 13:35
4342 ORY BIQ 20:05 21:20
4343 ORY BIQ 07:55 09:10
4344 BIQ ORY 05:50 07:10
4345 ORY BIQ 10:45 12:00
4347 ORY BIQ 18:20 19:35
4348 BIQ ORY 12:50 14:10
4349 ORY LDE 12:55 14:15
4350 LDE ORY 10:45 12:10
4351 ORY BIQ 15:55 17:10
4352 BIQ ORY 16:20 17:40
4354 BIQ ORY 18:00 19:20
4358 BIQ ORY 20:25 21:45
4359 ORY LDE 08:45 10:05
4360 LDE ORY 06:30 07:55
4363 ORY TLN 07:55 09:15
4364 TLN ORY 05:45 07:10
4365 ORY TLN 15:35 16:55
4366 TLN ORY 10:05 11:30
4368 TLN ORY 17:35 19:00
4369 ORY TLN 12:30 13:50
4370 TLN ORY 14:40 16:05
4371 ORY TLN 17:55 19:15
4375 ORY TLN 06:25 07:50
4376 TLN ORY 08:35 10:05
4385 ORY PGF 07:25 08:45
4386 PGF ORY 09:35 11:00
4387 ORY PGF 12:00 13:20
4388 PGF ORY 14:05 15:30
4389 ORY PGF 15:35 17:00
4390 PGF ORY 17:50 19:15
4393 ORY FSC 09:40 11:25
4394 FSC ORY 12:15 14:00
4400 FSC ORY 07:30 09:15
4404 MPL ORY 05:40 07:05
4405 ORY MPL 07:45 09:00
4406 MPL ORY 08:05 09:25
4407 ORY MPL 18:30 19:35
4408 MPL ORY 09:50 11:10
4409 ORY MPL 10:15 11:30
4410 MPL ORY 12:20 13:40