30
2014-2015 Encadrant : Bertrand LE GAL Programmation Linéaire Projet SE PR310 DUROU Baptiste FAUCHER François LE PAILLEUR Wilfried TRUCHOT Clément

Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

Embed Size (px)

Citation preview

Page 1: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

2014-2015

Encadrant : Bertrand LE GAL

Programmation Linéaire Projet SE PR310

DUROU Baptiste

FAUCHER François

LE PAILLEUR Wilfried

TRUCHOT Clément

Page 2: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

1

Table des matie res

INTRODUCTION ................................................................................................................................................ 2

CONTEXTE ET APPLICATION ............................................................................................................................. 3

1. CONTEXTE ..................................................................................................................................................... 3

2. CORRECTION D’ERREURS .................................................................................................................................. 3

3. RAPIDITE ....................................................................................................................................................... 4

PROGRAMMATION LINEAIRE : DEFINITIONS .................................................................................................... 5

1. DEFINITION .................................................................................................................................................... 5

2. PROBLEME DU MAXIMUM ................................................................................................................................. 5

3. PROBLEME DU MINIMUM ................................................................................................................................. 6

4. OBTENIR UN PROBLEME SOUS FORME STANDARD .................................................................................................. 6

5. UN EXEMPLE POUR COMPRENDRE ...................................................................................................................... 7

PROGRAMME PRINCIPAL ................................................................................................................................. 9

1. DESCRIPTIONS DES FICHIERS TXT A UTILISER .......................................................................................................... 9

2. ALGORITHME UTILISE ..................................................................................................................................... 10

3. FONCTIONS EN LANGAGE C ............................................................................................................................. 13

4. UTILISATION DU PROGRAMME ......................................................................................................................... 14

TEST DE L’ALGORITHME ................................................................................................................................. 15

1. CHOIX DU SOLVEUR DE REFERENCE ................................................................................................................... 15

2. PREMIERE MACRO DE VERIFICATION : SOLVEUR_UN_PB.XLSM ................................................................................ 15

2.1. Fonctionnement .............................................................................................................................. 15

2.2. Code de la macro solveur_un_pb.xlsm ............................................................................................ 17

VERIFICATION A GRANDE ECHELLE ................................................................................................................. 18

1. MACRO SOLVEUR_PLUSIEURS_PB.XLSM ............................................................................................................ 18

1.1. Fonctionnement .............................................................................................................................. 18

1.2. Code de la macro solveur_plusieurs_pb.xlsm .................................................................................. 19

2. MACRO DE COMPARAISON ............................................................................................................................. 20

3. RESULTATS DES TESTS .................................................................................................................................... 21

PERFORMANCES............................................................................................................................................. 23

1. FONCTION CLOCK() ........................................................................................................................................ 23

2. TIMER TSC .................................................................................................................................................. 24

OPTIMISATION ............................................................................................................................................... 27

1. CODAGE ...................................................................................................................................................... 27

2. TESTS ......................................................................................................................................................... 27

3. ACCES MEMOIRE ........................................................................................................................................... 28

CONCLUSION .................................................................................................................................................. 29

1. ANALYSE DU TRAVAIL ..................................................................................................................................... 29

2. CONCLUSION GENERALE ................................................................................................................................. 29

Page 3: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

2

Introduction

L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de

programmation linéaire. Apres avoir validé le bon fonctionnement du solveur il nous a fallu

l’améliorer en terme d’efficacité et étudier son implantation sur différentes cibles matérielles.

L’ouvrage de base nécessaire à notre compréhension de la programmation linéaire et à la résolution

de problèmes linéaires est la publication de Thomas S. Ferguson (professeur à l’université de

Californie) intitulée « Linear Programming: A Concise Introduction ».

Page 4: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

3

Contexte et application

Cette partie a pour but de présenter l’application potentielle de notre projet. En effet, l’objectif

est de pouvoir utiliser la programmation linéaire dans le domaine des communications numériques.

Nous allons donc voir le contexte d’utilisation sans rentrer dans les détails techniques de l’application

qui sont inutiles pour notre travail et car cela nécessiterait un rapport complet pour le présenter.

1. Contexte

Aujourd’hui avec l’augmentation de l’utilisation d’internet et surtout l'accroissement du volume

de donnée consommé le débit des connexions internet est devenu très important. Lors d’un échange

de donnée la fiabilité des informations échangées n’est pas sûre à 100% car il peut y avoir des erreurs

de transmission dues à des interférences ou à du bruit dans le canal de transmission par exemple.

L’opérateur doit en revanche garantir une bonne qualité de service, c’est pour cela qu’il est

nécessaire de vérifier que les données envoyées correspondent bien aux données reçues.

Par exemple l’ajout d’un bit de parité est un moyen simple pour détecter des erreurs. En effet, si la

parité du message ne correspond pas, on peut en déduire qu’il y a un bit incorrect (ou plusieurs). En

revanche il est impossible de savoir lequel est faux pour le corriger et il est nécessaire que le message

complet soit réémis ce qui implique une perte de débit.

Le but de notre application serait de détecter et surtout de corriger les erreurs au moment de la

réception.

2. Correction d’erreurs

La méthode utilise une matrice complète sur plusieurs paquets de données. Lors de la réception

un coefficient de fiabilité compris entre 0 et 1 est associé à chaque bit en fonction du niveau

(puissance) reçu. A partir de la matrice et des ces coefficients cela permet de construire un problème

d’optimisation linéaire.

La résolution du problème permet de déterminer le ou les bits qui ont la plus grande probabilité

d’être faux en tenant compte de leur coefficient associé et de la matrice d’erreur. Cette méthode

n’est pas fiable à 100% car elle se base sur de l’optimisation et sur des probabilités, mais elle

permettrait dans la majeure partie des cas de corriger les erreurs en évitant que les données soient

envoyées une deuxième fois.

Page 5: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

4

3. Rapidité

Cette méthode nécessite de résoudre rapidement des problèmes d’optimisation linéaire car si la

durée pour corriger les erreurs est supérieure au temps nécessaire pour transmettre le message

complet la méthode perd tout son intérêt.

C’est le but de notre projet d’optimiser l’efficacité de la résolution de problèmes de programmation

linéaire.

Page 6: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

5

Programmation line aire : de finitions

1. Définition

La programmation linéaire également appelée optimisation linéaire consiste à résoudre un

problème mathématique constitué d’une fonction objectif et d’une série d’inéquations. La fonction

objectif est une fonction linéaire à plusieurs variables. La série d’inéquations impose des contraintes

sur ces variables. Le but du problème est de maximiser ou de minimiser la fonction tout en

respectant les contraintes fixées par les inéquations.

Pour les problèmes de programmation linéaire, il y a deux formes standard. On peut donc se réduire

qu’à deux types de résolution : la résolution du problème du maximum et la résolution du problème

du minimum. Tous les problèmes de programmation linéaire peuvent se mettre sous l’une de ces

deux formes standard. Dans les deux formes standard les inconnues doivent toujours être positives.

Lorsqu’on réalise une résolution, on peut être confronté à trois cas :

Le problème admet une solution bornée, il est faisable (Feasible)

Les solutions ne sont pas bornées, il est faisable non borné (Unbounded feasible)

Le problème n’admet pas de solution, il est infaisable (Infeasible)

2. Problème du maximum

Définition d’un problème de maximisation de programmation linéaire :

Figure 1 : Problème du maximum

Page 7: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

6

3. Problème du minimum

Définition d’un problème de minimisation de programmation linéaire :

Figure 2 : Problème du minimum

4. Obtenir un problème sous forme standard

Il peut arriver que le problème de programmation linéaire ne soit pas sous forme standard. Dans

ce cas, on peut se toujours se ramener à une des deux formes standards. Lorsque le problème n’est

pas sous forme standard, on distingue deux cas :

Toutes les inéquations ne sont pas dans le même sens (présence de ≤ et ≥)

Présence d’équation en plus des inéquations

Certaines inconnues ne sont pas positives

Si certaines inéquations ne sont pas dans le bon sens, il faut les multiplier par -1 afin de n’obtenir que

des inéquations de même signe (soit que ≤ soit que ≥).

Si le problème présente une équation, il faut utiliser une méthode de substitution. Grâce à

l’équation, on isole une variable, puis on la remplace dans toutes les inéquations. S’il y a plusieurs

équations, il faut réitérer cette méthode.

Pour les inconnues non positives, on les remplace par la différence de deux variables positives Par

exemple pour 𝑥 non positif:

𝑥 = 𝑢 − 𝑣

𝑢 ≥ 0 𝑣 ≥ 0

Page 8: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

7

5. Un exemple pour comprendre

Pour voir concrètement en quoi consiste un problème d’optimisation linéaire et ce qu’implique

sa résolution nous allons voir un exemple simple et sa résolution par une méthode graphique.

Considérons le problème suivant :

{

max𝑥,𝑦∈𝑅

𝑓(𝑥, 𝑦) = 4𝑥 + 5𝑥

𝑥 + 𝑦 ≤ 8 (𝑐1)𝑥 + 2𝑦 ≤ 12 (𝑐2)𝑥, 𝑦 ≥ 0

Le but est de trouver le couple (x,y) qui maximise la fonction f en respectant les contraintes. Pour

résoudre ce problème, nous allons faire une résolution graphique.

On trace sur un graphique les droites qui définissent les zones frontières des inéquations puis on ne

conserve que les zones qui sont commune à toutes les contraintes. On obtient la zone en vert sur le

graphique suivant (figure 3) :

Figure 3 : Représentation graphique des contraintes

Il a été démontré que les solutions optimales possibles sont sur les sommets du polygone obtenu.

Nous avons quatre sommets, donc 4 solutions potentielles : (0,0), (0,6), (4,4) et (8,0).

{

f(0,0) = 0

f(0,6) = 30f(4,4) = 36f(8,0) = 32

Donc on peut en déduire que la solution optimale est le couple x=4 et y=4.

Page 9: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

8

Remarque 1 : on voit donc facilement avec la méthode graphique les différents cas que l’on peut

avoir lors de la résolution. En effet, si la zone en commun est nulle il n’y a pas de solution, le

problème est infaisable. Si la zone est infinie le problème est alors faisable mais non borné.

Remarque 2 : la résolution graphique est assez simple ici car la fonction n’est composée que de deux

variables. Si nous avions 3 variables il aurait fallu faire une résolution avec un graphique en trois

dimension ce qui tout de suite est plus complexe pour déterminer les sommets du polyèdre. Un

problème de dimension 4 ou plus est impossible à résoudre graphiquement.

Or notre algorithme doit être en mesure de résoudre des problèmes de dimension 30 000 donc il

nous faut une méthode de résolution plus adaptée.

La méthode que nous avons choisie est la méthode du Simplex.

Page 10: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

9

Programme Principal

1. Descriptions des fichiers txt à utiliser

Notre programme peut générer des fichiers problèmes aléatoirement et les résoudre ou alors

résoudre des problèmes spécifiques. Dans les deux cas les fichiers problèmes sont des fichiers txt

comme le suivant.

Figure 4: Fichier problème

Sur la première ligne :

1 ou 0 pour un problème du maximum ou du minimum

Nombre de colonnes de la matrice (en comptant la colonne des contraintes)

Nombre de lignes dans la matrice (nombre d’équations + une ligne pour la fonction à

maximiser ou minimiser)

Ensuite, il s’agit de la matrice contenant les inéquations et la fonction de maximisation (ou de

minimisation).

Avec l’exemple ci-dessus, on a le problème :

−3𝑥1 − 9𝑥2 − 2𝑥3 − 1𝑥4 + 9𝑥5 − 10𝑥6 ≤ −7

−3𝑥1 − 8𝑥2 + 6𝑥3 + 0𝑥4 + 3𝑥5 − 6𝑥6 ≤ 9

−4𝑥1 − 1𝑥2 + 10𝑥3 − 2𝑥4 − 1𝑥5 + 0𝑥6 ≤ 4

𝑀𝐴𝑋:−10𝑥1 − 4𝑥2 + 6𝑥3 − 6𝑥4 − 7𝑥5 − 10𝑥6

On remarque que les coefficients de la dernière ligne sont multipliés par -1 entre le problème réel et

le tableau d’entrée du programme.

Page 11: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

10

2. Algorithme utilisé

L’algorithme retenu est la méthode du simplex. Cette méthode utilise une matrice dite tableau

du simplex, voir figure 5. Elle est initialisée avec les conditions du problème, ainsi que la fonction

linéaire à maximiser ou minimiser.

Figure 5 - Tableau du simplex, avec A une matrice

L’algorithme consiste à trouver un pivot, transformer la matrice à l’aide de la « méthode du

rectangle » et recommencer ces deux opérations tant qu’on peut trouver un pivot. S’il n’y a pas de

pivot, il y a 3 possibilités :

une solution est trouvée

il n’y a pas de solution au problème

le problème n’est pas borné, la solution est donc infinie.

La méthode du rectangle est définie comme suivant :

Figure 6 - méthode dite du rectangle

Avec p le pivot, q la case à modifier, r sur la ligne du pivot et c sur la colonne du pivot. On va donc

dans un premier temps modifier toutes les valeurs de la matrice qui ne sont ni sur la ligne ni sur la

colonne du pivot avec la formule q – (rc/p), ensuite modifier la ligne du pivot avec r/p et la colonne

du pivot avec –c/p, et enfin modifier la case du pivot avec 1/p.

Pour trouver un pivot, il y a deux cas à considérer :

Si toutes les valeurs de la colonne b sont positives

Si au moins une des valeurs de la colonne b est strictement négative

Si les b sont positifs :

Prendre n’importe quelle colonne avec la valeur de la ligne –c négative. Soit j0 cette colonne,

avec –cj0 < 0.

Pour les lignes i de la colonne j0 pour les quelles ai,j0 > 0, choisir i0 tel que le ratio bi/ai,j0 soit le

plus petit. S’il y a des égalités, peu importe le i0 choisi parmi ces valeurs.

Pivoter autour de ai0,j0.

Page 12: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

11

Figure 7 - Exemple du cas b positifs

Dans l’exemple de la figure 7, les pivots possibles sont entourés. Plusieurs pivots possibles peuvent

en effet être trouvés pour un même tableau.

S’il n’est pas possible de trouver une colonne avec –ci < 0, alors la résolution est terminée et une

solution est trouvée.

Si l’on a trouvé –cj0 < 0 mais que l’on ne peut pas trouver de ai,j0 > 0, alors le problème est faisable

mais non borné.

Si au moins un bi est négatif :

Choisir la ligne avec le premier bi négatif, bk < 0.

Prendre n’importe quelle case négative sur la ligne k, ak,j0 < 0. (Le pivot sera dans la

colonne j0)

Comparer bk/ak,j0 et bi/ai,j0 pour lesquels bi ≥ 0 and ai,j0 > 0, et choisir i0 tel que ce ratio soit

le plus petit (i0 peut être égal à k). S’il y a des égalités, peu importe le i0 choisi parmi ces

valeurs.

Pivoter autour de ai0,j0.

Figure 8 - Exemple du cas bi négatif

Dans l’exemple de la figure 8, les pivots sont entourés. Plusieurs pivots sont également possibles

pour un même tableau.

Si l’on a trouvé bk < 0, mais que l’on ne peut pas trouver de ak,j0 < 0, alors le problème est infaisable, il

n’y a pas de solution.

Page 13: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

12

Si la résolution est finie est qu’il y a une solution, elle peut être lue grâce à la matrice obtenue. Ci-

dessous un exemple pour illustrer la lecture de la solution.

Minimiser 3y1 − 2y2 + 5y3 avec yi ≥ 0 et

− y2 + 2y3 ≥ 1

y1 + y3 ≥ 1

2y1 − 3y2 + 7y3 ≥ 5.

Ci-dessous la mise en tableau et le premier pivot correspondant à ce problème.

Figure 9 - Exemple de résolution d'un problème de minimisation - premier pivot

On remarque que y2 et x1 ont permuté. Ce sont ces permutations qui vont permettre de lire le

résultat de la résolution.

Figure 10 - Exemple de résolution d'un problème de minimisation - problème résolu

Ici toutes les valeurs de la dernière ligne sont positives, on a donc trouvé une solution. La solution

peut être lue en associant les yi de la première ligne avec les valeurs de la dernière ligne. On obtient

donc y1=0, y2=2/3 et y3=1, avec une valeur de minimum lue dans la case en bas à droite, égale à 11/3.

Pour un problème de maximum, les résultats sont à lire sur les lignes et non les colonnes, avec les x

correspondants.

Page 14: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

13

3. Fonctions en langage C

Tout d’abord, nous avons créé une structure de données pour pouvoir stocker la matrice et les

informations nécessaires pour résoudre le problème :

Nous avons ensuite défini les fonctions de l’algorithme principal :

La fonction « pivot » appelle les deux autres fonctions, et retourne 0 quand il n’y a plus de pivot. Une

boucle sur cette fonction tant qu’elle ne retourne pas 0 permet donc de résoudre un problème

donné en utilisant la méthode du simplex vue précédemment.

Nous avons également des fonctions secondaires :

struct Matrix_ {

int max; // 0 : minimum, 1 : maximum

double **tab; // matrice

int length;

int width;

int *row_sol_min; // contient les x et les y à permuter pour lire les

solutions

int *column_sol_max; // contient les x et les y à permuter pour lire

les solutions

int solution_type; // 0 : init value, 1 : no_solution, 2 :

unbounded feasible, 3 : solution_ok

};

int pivot(Matrix * matrix); // modifie la matrice en effectuant un pivot

complet, retourne 0 quand il n’y a plus de pivot

double find_pivot(Matrix * matrix, int * p_length, int * p_width); //

retourne la valeur du pivot et ses index à partir de la matrice

void rectangle_method(Matrix * matrix, int p_length, int p_width, int

length_to_calculate, int width_to_calculate); // methode du rectangle,

modifie la valeur du coefficient à calculer dans la matrice

void display_matrix(Matrix * matrix); // affiche la matrice dans le terminal

void save_to_file(Matrix * matrix, char * file_name); // sauvegarde la

matrice dans un fichier texte

void load_from_file(Matrix * matrix, char * file_name); // charge la matrice

à partir d'un fichier texte

void random_generator(int length_size, int width_size, int borne_inf, int

borne_sup, int min_max, char *filename); // génère aléatoirement une matrice

avec les paramètres donnés en argument

void print_solutions(Matrix * matrix); // affiche les solutions dans le

terminal

void save_solution_to_file(Matrix * matrix, char * file_name); // sauvegarde

les solutions dans le terminal

Page 15: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

14

Les fonctions « display_matrix » et « print_solutions » permettent d’afficher des informations sur le

terminal quand le programme s’exécute. Il est ainsi possible de voir l’évolution de la matrice après

chaque pivot.

Les fonctions « save_to_file », « load_from_file » et « save_solution_to_file » permettent d’interagir

avec un fichier texte et ainsi garder en mémoire un problème et sa solution, pour ensuite pouvoir la

comparer avec un autre solveur, comme nous le verrons dans la prochaine partie.

« random_generator » permet de générer un problème aléatoire en fonctions de paramètres comme

la taille du problème à générer, le type (maximisation ou minimisation) et les bornes inférieures et

supérieures des coefficients.

4. Utilisation du programme

Afin d’utiliser notre programme il faut veiller à créer le dossier « dossier_test_1 » dans le même

répertoire que l’exécutable.

Après exécution du programme, on trouve les fichiers problèmes et ceux des solutions associées

dans ce dossier.

Pour modifier les conditions de génération des fichiers problèmes ainsi que leur nombre, il faut

modifier les arguments de la fonction « random_generator » dans le code.

Page 16: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

15

Test de l’algorithme

Afin de vérifier le bon fonctionnement de notre algorithme, nous avons dû trouver un

programme de référence afin de comparer les résultats. Cela permet de s’assurer que nous

fournissons toujours les bons résultats avant de commencer le travail d’optimisation.

1. Choix du Solveur de référence

Il existe de nombreux solveur en ligne mais leur utilisation n’est pas forcement simple de

manière automatique. En effet le formatage des données en entrée n’est pas forcément le même

que celui de notre programme. Il fallait donc rentrer les valeurs du problème une par une dans les

solveurs en ligne. Nous nous sommes donc tournés vers des solveurs intégrés aux logiciels de calculs

à notre disposition. Les logiciels Matlab et Excel permettent de résoudre les problèmes de

programmation linéaire.

Matlab possède une fonction permettant de résoudre les problèmes du minimum. Il s’agit de la

fonction linprog. Excel dispose d’un module solveur qui permet de résoudre les problèmes du

maximum et du minimum. Le solveur d’Excel étant plus simple d’utilisation et permettant de

résoudre les deux types de problèmes (maximum et minimum), il a donc été choisi pour être la

référence lors de notre projet. De plus, Visual Basic permet de programmer Excel afin d’automatiser

des traitements et de ne pas avoir à rentrer et paramétrer le solveur à la main.

2. Première macro de vérification : solveur_un_pb.xlsm

2.1. Fonctionnement

La première macro Excel réalisée permet de résoudre un problème donné au format de notre

programme principal. Lors de l’exécution de la Macro, le fichier problème est demandé au format txt.

Ce fichier contient les informations suivantes :

Problème du maximum ou du minimum

Les inéquations

La fonction de minimisation ou de maximisation

Ensuite la macro fournit le résultat et l’affiche dans une feuille de calcul. On obtient une feuille telle

que celle présentée figure 11 :

Page 17: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

16

Figure 11 : Feuille résultat de solveur_un_pb.xlsm

On peut lire les résultats dans les cellules surlignées en jaune. La ligne quantité correspond aux

valeurs des inconnues à trouver. La cellule résultat indique la valeur de la fonction de maximisation

(ou minimisation pour un problème du minimum). La ligne Z correspond aux coefficients de la

fonction de maximisation (ou minimisation).

Cette macro a permis de vérifier le bon fonctionnement de notre algorithme sur certains exemples et

de le corriger si des écarts étaient constatés. Cependant, pour valider notre algorithme, cette macro

n’était pas suffisante car il faut automatiser la résolution des problèmes. Une autre macro a donc été

développée afin de résoudre plusieurs centaines de problèmes à la suite.

Il faut cependant noter que le solveur Excel ne peut pas résoudre des problèmes de dimensions trop

importantes. Il peut y avoir au plus 200 inconnues et 100 inégalités.

Figure 12 : Limite du solveur Excel

variable x1 x2 x3 x4 x5 x6

quantite 0 0 0,4 0 0 0,62

Z -10 -4 6 -6 -7 -10

Résultat -3,8

equation calc ligne contrainte

ligne1 -3 9 -2 -1 9 -10 -7 -7

ligne2 -3 -8 6 0 3 6 6,12 9

ligne3 -4 -1 10 -2 -1 0 4 4

Page 18: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

17

2.2. Code de la macro solveur_un_pb.xlsm

Cette macro est divisée en deux parties. La première partie consiste à préparer et remplir la

feuille de calcul. Il faut lire le fichier texte indiqué par l’utilisateur, remplir les cellules avec tous les

coefficients du fichier texte, calculer les équations dans les cellules de la colonne cellules calc ligne et

calculer la fonction de maximisation(ou minimisation) dans la cellule résultat.

La seconde partie de la macro consiste à exécuter le solveur Excel. Il suffit d’indiquer au solveur les

équations calculées dans la première partie de la macro.

Page 19: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

18

Ve rification a grande e chelle

Pour cette partie des problèmes du minimum et du maximum ont été testés. Les observations

faites sont valables pour les deux types de problèmes.

1. Macro solveur_plusieurs_pb.xlsm

1.1. Fonctionnement

La première macro Excel a été modifiée afin de pouvoir tester un nombre très important de

problèmes à la suite. Les principales modifications sont donc l’écriture des résultats dans des fichiers

textes afin de pouvoir comparer les solutions obtenues avec Excel et avec notre programme.

Cette macro doit être exécutée dans le dossier où se situent les problèmes à résoudre. Les problèmes

doivent être nommés de la façon suivante :

tab_random000

tab_random001

tab_random999

Cette macro peut résoudre au maximum 1000 problèmes à la suite. Lors de l’exécution on demande

à l’utilisateur le nombre de problèmes à résoudre. Pour chaque problème qui a été traité un fichier

texte est généré dans le même répertoire que la macro. Le nom des fichiers correspondent aux

noms des problèmes :

sol_excel_random000

sol_excel_random001

sol_excel_random999

Page 20: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

19

Figure 13 : Liste des fichiers du dossier de test

Si une solution est trouvée le fichier sol_excel_randomXXX.txt contient les différentes valeurs de X et

la valeur de la fonction de maximisation (ou minimisation obtenue). Si le solveur ne trouve pas de

solution, le fichier txt contient « No solution. ».

Figure 14 : Fichier solution généré par Excel

1.2. Code de la macro solveur_plusieurs_pb.xlsm

Il s’agit du même code que la macro « solveur_un_pb.xlsm » auquel a été ajouté une boucle sur

tous les fichiers problèmes. Pour chacun des fichiers problèmes, on génère un fichier txt avec les

solutions à la suite de l’exécution du solveur Excel.

Page 21: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

20

2. Macro de Comparaison

Une macro de comparaison des fichiers txt résultat a été réalisée pour comparer les solutions

générées par le solveur Excel et celui que nous avons développé. Le comparateur a été développé en

Visual Basic afin d’avoir un temps de développement réduit par rapport au C. En effet, le

comparateur n’a pas de contrainte de temps d’exécution donc il n’était pas nécessaire de le réaliser

en C.

Le principal problème de la comparaison est de gérer les arrondis car les deux solveurs peuvent

obtenir la même solution mais avec des arrondis différents. On ne peut donc pas utiliser un simple

comparateur de fichier.

Comme pour la macro du solveur, cette macro doit être lancée dans le répertoire des fichiers à

comparer. On demande à l’utilisateur le nombre de fichier à traiter. Les fichiers à comparer doivent

s’appeler pour les solutions d’Excel :

sol_excel_random000

sol_excel_random001

sol_excel_random999

Pour les solutions de notre programme :

sol _random000

sol _random001

sol _random999

Le résultat de la comparaison est écrit dans le fichier resultat_comparaison.txt. Les fichiers

différents sont listés dans resultat_comparaison.txt. Si tous les fichiers solutions sont

identiques, le fichier contient « Tout est OK ».

Figure 15 : Fichier de comparaison

Page 22: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

21

Pour que deux fichiers soient considérés comme identiques, il faut qu’ils contiennent le même

nombre de lignes. Ensuite il faut que les valeurs de chaque X et du résultat soient les mêmes avec

une précision de 6 chiffres après la virgule. Pour la comparaison toutes les valeurs sont arrondies à 6

décimales. Par exemple les deux fichiers suivants sont considérés comme égaux.

Figure 16 : Solution de notre solveur

Figure 17 : Solution du solveur Excel

3. Résultats des Tests

Une fois notre programme terminé et les macros réalisées nous avons pu lancer plusieurs

centaines de tests assez rapidement. En comparant les résultats nous avons pu nous assurer de la

robustesse de notre algorithme.

Nous avons pu observer que notre algorithme et le solveur d’Excel ne trouvent pas de solution

bornée dans les même cas et que lorsqu’une solution bornée est trouvée, les deux solveurs renvoient

la même solution.

Le seul cas où les deux solveurs ne renvoient pas la même solution bornée est le cas où cette solution

n’est pas unique. C’est-à-dire que toutes les contraintes sont respectées et que le résultat de la

fonction de maximisation (ou minimisation) est exactement le même dans les deux cas. Par exemple,

le problème suivant présente deux solutions équivalentes :

Page 23: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

22

𝑀𝐴𝑋 ∶ 2𝑥1 + 9𝑥2 + 4𝑥3 + 5𝑥4 + 4𝑥5 + 3𝑥6 + 0𝑥7 + 10𝑥8 + 10𝑥9

3𝑥1 + 4𝑥2 + 10𝑥3 + 1𝑥4 + 1𝑥5 + 5𝑥6 + 5𝑥7 + 3𝑥8 + 9𝑥9 <= 2

4𝑥1 + 4𝑥2 + 8𝑥3 + 8𝑥4 + 3𝑥5 + 1𝑥6 + 5𝑥7 + 3𝑥8 + 3𝑥9 <= 1

6𝑥1 + 1𝑥2 + 0𝑥3 + 9𝑥4 + 2𝑥5 + 7𝑥6 + 2𝑥7 + 7𝑥8 + 9𝑥9 <= 3

4𝑥1 + 8𝑥2 + 1𝑥3 + 4𝑥4 + 10𝑥5 + 7𝑥6 + 7𝑥7 + 3𝑥8 + 4𝑥9 <= 10

Figure 18 : Solution différentes mais équivalentes

Dans cet exemple les solutions de gauche et de droite sont différentes mais respectent toutes les

deux les contraintes tout en fournissant un résultat de 3.33333 pour la fonction de maximisation. Les

deux solutions sont donc valides.

Les cas où il n’existe pas de solution bornée sont les même pour les deux solveurs. Notre programme

différencie le cas où la solution n’est pas bornée (problèmes Unbounded feasible) et le cas où le

problème n’est pas solvable. Tandis que le solveur d’Excel ne permet pas cette distinction de manière

évidente. On n’a donc pas pu vérifier la robustesse de la distinction entre les problèmes Unbounded

feasible et les problèmes non solvables.

Pour conclure, les différentes macros ont permis de valider notre algorithme. On est donc sûr que les

solutions renvoyées par notre algorithme sont valides. Lors que notre programme ne renvoie pas de

solution, l’étape de vérification nous a assuré qu’on est bien, soit dans le cas d’un problème

Unbounded feasible, soit dans un cas d’un problème sans solution. Les remarques établies

précédemment sont valables à la fois pour les problèmes du maximum et du minimum.

Page 24: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

23

Performances

Une fois notre algorithme validé à l’aide du solveur Excel et du script de comparaison, il nous

a fallu mesurer les performances de notre algorithme afin d’en déterminer les parties critiques et

celles pouvant être optimisées. En effet, notre algorithme fait appel à des fonctions identiques qui

sont exécutées séquentiellement (multiples méthodes des rectangles). Ces dernières pourraient être

exécutées en parallèle afin d’accélérer le temps de résolution des problèmes.

Nous avons eu recours à deux types de mesures temporelles :

- La fonction clock(),

- Le timer RDTSC.

1. Fonction clock()

Dans un premier temps, nous avions besoin d’avoir une idée du temps d’exécution de notre

programme pour résoudre un problème. La fonction clock() incluse dans la librairie standard time.h

nous a permis d’avoir une estimation du temps nécessaire à la résolution d’un problème. Cette

fonction s’utilise de manière très simple : il suffit de stocker les valeurs renvoyées par l’appel de cette

fonction dans deux variables déclarées avant et après la portion de code que nous souhaitons

mesurer. En faisant la différence entre ces deux variables et en divisant le résultat obtenu par la

constante système correspondant à la fréquence du processeur (CLOCKS_PER_SEC) on obtient le

résultat du temps d’exécution en secondes.

Figure 19 : Utilisation de la fonction clock()

double time_start = clock();

/************************

Portion de code à mesurer

************************/

double time_stop = clock();

double delta_sec = (time_stop-time_start)/CLOCKS_PER_SEC;

printf("Temps : %lf s\n", delta_sec);

Page 25: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

24

Nous avons testé cette fonction sur différentes tailles de matrices pour avoir une idée des temps de

résolution.

i5 4200M (2,5 GHz) Temps d’exécution d’une matrice (s)

Matrice 30 X 30 < 0,01

Matrice 300 X 300 0,07

Matrice 3000 X 3000 30

Tableau 1 : Mesure du temps d'exécution en secondes

Nous remarquons que les temps de résolution augmentent de manière exponentielle avec la taille de

la matrice. Ceci était attendu car avec l’augmentation de la taille de la matrice, le nombre de

recherches de pivots et le nombre de méthodes des rectangles augmente fortement.

Cependant, ces temps ne sont pas précis. En effet, dès que la matrice est de petite taille, il est

courant de voir un temps de 0 secondes. Ce problème réside dans la fonction clock(). Cette dernière

n’est pas très précise. De plus lorsqu’on divise le delta par la fréquence du processeur on commet

une erreur car dans les PC actuels la fréquence du processeur s’adapte en fonction de la charge CPU.

Cette dernière est donc variable. Notre mesure est donc une mesure très approximative.

Notre but étant de mesurer des temps qui peuvent être très faibles (comme le temps d’exécution

d’une seule méthode du rectangle) cette fonction n’est pas adaptée. Elle ne nous permet que d’avoir

une idée du temps d’exécution global.

2. Timer TSC

Pour avoir à des mesures plus précises nous avons utilisé un timer présent dans tous les

processeurs à architecture x86 depuis le Pentium : le timer TSC (Time Stamp Counter). Notre

algorithme ayant été développé sur des machines utilisant des processeurs Intel, nous avons pu

utiliser ce timer. En revanche, ce dernier n’est pas disponible sur les cartes possédant des

processeurs à architecture ARM.

Une fonction assembleur permet de lire la valeur sur 64 bits du compteur. Cette fonction est

cependant différente selon le compilateur utilisé.

Pour un compilateur GNU comme MinGW utilisé dans Qt, on peut utiliser la fonction suivante :

Figure 20: Fonction RDTSC du compilateur GNU (Qt)

Tandis que pour le compilateur Windows MSVC, il faut plutôt utiliser la fonction suivante :

#include <unistd.h>

static __inline__ unsigned long long timer() { unsigned hi, lo;

__asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi));

return ( (unsigned long long) lo) | (((unsigned long long) hi) <<

32);

}

Page 26: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

25

Figure 21 : Fonction RDTSC du compilateur MSVC (Visual Studio)

Cette fonction renvoie un nombre de ticks d’horloge. De la même manière que précédemment, il

suffit donc d’encadrer la portion de code que nous souhaitons mesurer avec des appels de la

fonction timer().

Cela nous permet d’obtenir une mesure précise temporelle afin de pouvoir mesurer les gains lors de

l’optimisation. Les résultats des mesures sont donc, non pas en secondes, mais en ticks d’horloge ce

qui nous permet de savoir quelles parties du programmes sont gourmandes en ressources et

critiques.

Nous avons réalisé des mesures pour différentes tailles de matrices :

Tableau 2 : Mesures des ticks d’horloge pour chaque partie de l’algorithme

Matrice 30 X 30 Valeurs entre -10 et 30 Ticks

(moyenne) Temps d’exécution (ticks

d’horloge)

1 méthode du rectangle 60

4 752 804

Toutes les méthodes du rectangle

12000

Fonction find pivot() 1200

Matrice 300 X 300 Valeurs entre -10 et 30 Ticks

(moyenne) Temps d’exécution (ticks

d’horloge)

1 méthode du rectangle 70

162 799 282

Toutes les méthodes du rectangle

1050000

Fonction find pivot() 6500

Matrice 3000 X 3000

Valeurs entre -10 et 30 Ticks

(moyenne) Temps d’exécution (ticks

d’horloge)

1 méthode du rectangle 73

63 106 912 246

Toutes les méthodes du rectangle

113 000 000

Fonction find pivot() 72 560

// processor: x86, x64

#include <stdio.h>

#include <intrin.h>

#pragma intrinsic(__rdtsc)

unsigned long long timer()

{

unsigned __int64 i;

i = __rdtsc();

//printf_s("%I64d ticks\n", i);

return(i);

}

Page 27: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

26

Ce tableau nous a permis de déterminer quelle partie de notre algorithme était la plus gourmande en

ressources et donc quelle partie pouvait être optimisée.

On observe que les méthodes des rectangles sont les étapes les plus souvent effectuées. Cependant,

dans notre version après chaque exécution de la fonction qui trouve le pivot, toutes les méthodes

des rectangles sont faites séquentiellement. Compte-tenu de l’algorithme utilisé ces dernières

pourraient être exécutées en parallèle. Ceci est confirmé par le fait qu’une seule méthode du

rectangle ne demande que très peu de temps pour être exécutée.

Nous avons donc décidé d’optimiser notre algorithme pour améliorer son efficacité temporelle. Pour

cela, nous avons choisi d’exécuter les calculs sur plusieurs threads. Cette optimisation a été réalisée

avec l’aide de la librairie OpenMP qui permet de paralléliser des portions de codes.

Page 28: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

27

Optimisation

1. Codage

Comme nous l’avons vu précédemment, il n’est possible de paralléliser les calculs que pour

l’exécution des méthodes du rectangle. En effet, modifier une valeur de la matrice avant une autre

n’a pas d’importance dans notre algorithme. Cette parallélisation est réalisée avec une directive

OpenMP :

Figure 22 : Directive Pragma

Le nombre de threads que nous souhaitons créer est choisi grâce à la ligne :

omp_set_num_threads(X); // remplacer X par le nombre de threads

2. Tests

Afin de vérifier le bon fonctionnement de nos améliorations et de valider notre optimisation

nous avons dû effectuer une série de tests.

Pour cela, nous avons utilisé un PC équipé d’un processeur Intel i5 4200M possédant 2 cœurs

physiques donc 4 logiques. Dans ce cas le gain de performance maximal est de 4.

Cependant, en testant les temps d’exécution de l’algorithme en utilisant 1 thread ou 4 threads on

observe que les gains plafonnent à 2. Le tableau ci-après (tableau 3) donne les résultats pour

plusieurs configurations matérielles :

#pragma omp parallel for private(i,j ) //gain de 2 pour 4 threads

for (i = 0; i < matrix->length; i++){ // calcule les rectangles

if (i != p_length){

for (j = 0; j < matrix->width; j++){

if (matrix->tab[i][p_width] != 0 && j !=

p_width)

//timer1 = timer();

rectangle_method(matrix, p_length,

p_width, i, j);

//timer2 = timer();

//printf("rect %llu \n ", timer2 - timer1);

}

}

}

Page 29: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

28

Matrice 3000 X 3000, Valeurs [-10 ---- 30]

Architecture Temps d’exécution 1 thread (s) Temps d’exécution 4 thread (s) Gain

i5 4200M (2,5 GHz) 32,6 17,04 1,91

51,6 26,32 1,96

46,9 23,57 1,99

32,15 16,09 2,00

43,7 21,93 1,99

i7 3632QM (2,2 GHz)

27,81 13,5 2,06

28,64 14,2 2,02

20,36 11 1,85

23,61 12,7 1,86

38,31 20,5 1,87

Tableau 3 : Gains de performances

3. Accès mémoire

Nous avons mesuré en détail le temps d’exécution des différentes étapes d’une méthode des

rectangles. Nous avons ainsi relevé les temps donnés dans le tableau ci-dessous (tableau 4) :

Méthode du rectangle 30 X 30 300 X 300 3000 X 3000

Lecture 77 61 70

Calcul 23 20 18

Ecriture 20 18 20

Total 120 97 115

Tableau 4 : Accès mémoire

On remarque que les temps d’accès à la mémoire (lecture et écriture des données) représentent

environ 80% du temps d’exécution d’une méthode des rectangles. Le temps de calcul ne représente

quant à lui que 20% du temps.

Ceci semble être à l’origine d’un gain plus faible que prévu.

Page 30: Programmation Linéaire - kadionik.vvv.enseirb-matmeca.fr · 2 Introduction L’objectif de ce projet est de réaliser un solveur permettant de résoudre des problèmes de programmation

29

Conclusion

1. Analyse du travail

Durant ce projet nous avons dû à de nombreuses reprises revoir nos attentes et repenser

l’étalement du projet dans le temps. En effet, initialement, nous avions prévu de passer peu de

temps à comprendre et implémenter (coder) l’algorithme et de passer l’essentiel du temps à

optimiser et implanter l’algorithme sur différentes architectures matérielles.

Cependant, la phase de codage a été plus compliquée que prévu et nous avons donc passé beaucoup

de temps à débugger notre programme. De plus, il nous a fallu valider notre algorithme en vérifiant

sa fiabilité. Pour cela, nous avons utilisé un solveur Excel permettant de résoudre les problèmes

linéaires. L’implémentation des scripts de comparaison et de test nous a pris beaucoup de temps,

temps que nous n’avions pas pris en compte lors de la phase de planification du projet.

Figure 23 : Répartition du temps

2. Conclusion générale

Ce projet nous a permis de nous confronter à une problématique réelle d’un ingénieur. En effet,

de par sa complexité, son étalement dans le temps et les problèmes rencontrés, ce projet nous a

donné une idée plus précise de ce qui nous sera demandé en entreprise dans le futur. Ainsi, nous

avons vu que le cahier des charges a dû être modifié (phase d’implantation raccourcie). Nous avons

par ailleurs apprécié pouvoir mener un projet dans son intégralité, du cahier des charges à

l’implantation et aux tests sur cible.

9%

17%

28%

28%

11%

7%

Répartition du temps passé sur le projet

Compréhension del'algorithme

Codage de l'algorithme

Phase de Debuggage

Validation

Analyse des performances

Optimisation et implantationsur cible