Plans Coupants et Branch-and-bound Pierre Bonami Optimisation Combinatoire, Masters II, ID et IF 18 décembre 2012
2 idées algorithmiques On considère un problème en nombres entiers z PLM = min{c T x : Ax b, x 0, x j Z, j = 1,...,p}. (PLM)
2 idées algorithmiques On considère un problème en nombres entiers z PLM = min{c T x : Ax b, x 0, x j Z, j = 1,...,p}. (PLM) x = (6, 1 2 ) Soit x l optimum de la relaxation continue z PL = min{c T x : Ax b, x 0}. (PL) 1. Si, j = 1,...,p, x j Z, x résoud (PLM) et z PL = z PLM. 2. Si on connait une solution ˆx de (PLM) de cout ẑ z PL, ˆx est optimale.
Branchement Si 1. et 2. ne sont pas vérifiés, ĵ {1,...,p} tel que x j Z). On crée deux nouveaux problèmes, où on ajoute respectivement les contraintes xĵ xĵ et xĵ xĵ x = (6, 1 2 )
Branchement Si 1. et 2. ne sont pas vérifiés, ĵ {1,...,p} tel que x j Z). On crée deux nouveaux problèmes, où on ajoute respectivement les contraintes xĵ xĵ et xĵ xĵ x 2 1 x = (6, 1 2 ) x 2 0
Branchement Si 1. et 2. ne sont pas vérifiés, ĵ {1,...,p} tel que x j Z). On crée deux nouveaux problèmes, où on ajoute respectivement les contraintes xĵ xĵ et xĵ xĵ x 2 1 x = (6, 1 2 ) x 2 0 Nécessairement, l optimum de (PLM) est dans un des deux sous-problèmes. On applique récursivement les règles 1. et 2.
Plans coupants Soit X = {Ax b, x 0, x j Z, j = 1,...,p}. Comme x minimize la relaxation continue et x X, on a x conv(x) (x est une solution de base de (PL)). Th. de Séparation si P est convexe et ˆx P, hyperplan α T x = β tel que α T x β x P et α Tˆx β. x = (6, 1 2 )
Plans coupants Soit X = {Ax b, x 0, x j Z, j = 1,...,p}. Comme x minimize la relaxation continue et x X, on a x conv(x) (x est une solution de base de (PL)). Th. de Séparation si P est convexe et ˆx P, hyperplan α T x = β tel que α T x β x P et α Tˆx β. x = (6, 1 2 ) 1. Problème de séparation : Trouver α T x = β séparant X et ˆx. 2. Ajouter α T x β à (PL) et répéter les étapes (re-résoudre PL, vérifier 1. et 2.,...).
Plans coupants Soit X = {Ax b, x 0, x j Z, j = 1,...,p}. Comme x minimize la relaxation continue et x X, on a x conv(x) (x est une solution de base de (PL)). Th. de Séparation si P est convexe et ˆx P, hyperplan α T x = β tel que α T x β x P et α Tˆx β. x = (6, 1 2 ) 1. Problème de séparation : Trouver α T x = β séparant X et ˆx. 2. Ajouter α T x β à (PL) et répéter les étapes (re-résoudre PL, vérifier 1. et 2.,...).
Setup pour branch-and-bound Pour simplifier, on considère le problème en variables 0-1 (la généralisation aux variables entières est évidente) z PLM 01 = min cx Ax b x 0 x i {0,1} i = 1,...,n (PLM-01) Pour sous ensembles de variables F 0, F 1 disjoints donnés. On définit LP(F 0,F 1 ) : z LP(F0,F 1 ) = min cx Ax b x 0 (LP(F 0,F 1 )) x i = 0, i F 0, x i = 1, i F 1
Algorithme branch-and-bound 0. 1. 2. 3. 4. 5. Initialisation. L {(, )}. ub =. x NULL. Fin? Si L =, la solution x est optimale. Selectionner un noeud. Choisir un problème N i = (F 0,F 1 ) dans L. Evaluer. Résoudre LP(F 0,F 1 ). Si le problème n est pas réalisable aller en 1, sinon soit ˆx i sa solution. Élaguer. Si cˆx i ub, aller en 1. Si ˆx i est entier : ub cˆx i, x ˆx i, enlever de L tous les problèmes avec cˆx j ub puis aller en 1. Sinon aller en 5. Diviser Choisir j tel que ˆx i j Z, ajouter à L les deux sous problème (F O {j},f 1 ) et (F O,F 1 {j}). Aller en 1.
Exemple max 9x 1 +5x 2 x 1 6 4x 1 +9x 2 35 x 1 3x 2 1 3x 1 +2x 2 19 x Z 2 +
Exemple max 9x 1 +5x 2 x 1 6 4x 1 +9x 2 35 x 1 3x 2 1 3x 1 +2x 2 19 x Z 2 +
Exemple max 9x 1 +5x 2 x 1 6 x 1 3x 2 1 3x 1 +2x 2 19 lb = 56,5 x 2 Z x Z 2 + ub = x = (6, 1 2 )
Exemple max 9x 1 +5x 2 x 1 6 x 1 3x 2 1 3x 1 +2x 2 19 lb = 56,5 x 2 Z x 2 0 x 2 1 x Z 2 + ub = x 2 1 x 2 0
Exemple lb = 56,5 max 9x 1 +5x 2 x 1 6 x 1 3x 2 1 3x 1 +2x 2 19 x Z 2 + x 2 0 x 2 1 lb = 56 x 1 Z ub = x = ( 17 3,1)
Exemple lb = 56,5 max 9x 1 +5x 2 x 1 6 x 1 3x 2 1 3x 1 +2x 2 19 x 2 0 x 2 1 lb = 56 x 1 Z x Z 2 + x 1 5 x 1 6 ub = x 1 5 x 1 6
Exemple lb = 56,5 max 9x 1 +5x 2 x 1 6 x 1 3x 2 1 3x 1 +2x 2 19 x 2 0 x 2 1 lb = 56 x Z 2 + x 1 5 x 1 6 ub = lb = 53.667 x 2 Z x = (5, 13 9 )
Exemple lb = 56,5 max 9x 1 +5x 2 x 1 6 x 2 0 x 2 1 x 1 3x 2 1 3x 1 +2x 2 19 lb = 56 x Z 2 + x 1 5 x 1 6 ub = lb = 53.667 x 2 Z x 2 2 x 2 1 x 2 2 x 2 1
Exemple lb = 56,5 max 9x 1 +5x 2 x 1 6 x 1 3x 2 1 3x 1 +2x 2 19 x Z 2 + x 2 0 x 2 1 x 1 5 lb = 56 x 1 6 ub = 51 lb = 53.667 x = (5,1) x 2 1 x 2 2 lb = 51 x Z n
Exemple max 9x 1 +5x 2 x 1 6 x 2 0 x 2 1 x 1 3x 2 1 3x 1 +2x 2 19 lb = 56 x Z 2 + x 1 5 x 1 6 ub = 51 lb = 53.667 x 2 2 x 2 1 x 2 2 x 1 5 lb = 51 x Z n lb =
Exemple max 9x 1 +5x 2 x 1 6 x 1 3x 2 1 3x 1 +2x 2 19 x Z 2 + x 2 0 x 2 1 x 1 5 lb = 56 x 1 6 ub = 51 lb = 53.667 lb = x 1 6 x 2 1 x 2 1 x 2 2 lb = 51 x Z n
Exemple max 9x 1 +5x 2 x 1 6 x 1 3x 2 1 3x 1 +2x 2 19 x Z 2 + x 2 0 x 2 1 x 1 5 lb = 56 x 1 6 ub = 51 lb = 53.667 x 2 0 x 2 1 x 2 2 lb = 51 x Z n
Exemple max 9x 1 +5x 2 x 1 6 x 1 3x 2 1 3x 1 +2x 2 19 x 2 0 lb = 54 x Z n x 2 1 lb = 56 x Z 2 + ub = 54 x 1 5 lb = 53.667 x 1 6 x 2 1 x 2 2 x = (6,0) x 2 0 lb = 51 x Z n
Rendre le branch-and-bound efficace L algorithme a un temps de calcul exponentiel. En pratique l algorithme peut être rendu relativement efficace grâce à un certain nombre de choix : Avoir une bonne formulation. Trouver des solutions réalisables de manière heuristique (tabou, local search,...) pour faire baisser la borne supérieure rapidement. Bien Choisir la variable de branchement. Bien choisir l ordre dans lequel les sous problèmes sont explorés. Pour faire tous ces choix, aucune garantie théorique valable ne peut être donnée en générale... Raisonnement heuristique : essayer d avoir les meilleures bornes de manière à élaguer le plus tôt possible.
Parties de l algorithmes pouvant être changées 0. Initialisation. L {(, )}. C =, ub =. x NULL. 1. Fin? Si L =, la solution x est optimale. 2. Selectionner un noeud. Choisir un problème N i = (F 0,F 1 ) dans L. 3. Evaluer. Résoudre LP(C,F 0,F 1 ). Si le problème n est pas réalisable aller en 1, sinon soit ˆx i sa solution. 4. Élaguer. Si cˆx i ub, aller en 1. Si ˆx i est entier : ub cˆx i, enlever de L tous les problèmes avec cˆx j ub puis aller en 1. Sinon aller en 5. 5. Diviser Choisir j tel que ˆx i j Z, ajouter à L les deux sous problème (F O {j},f 1 ) et (F O,F 1 {j}). Aller en 1.
Exemple bis (en explorant la branche gauche d abord) max 9x 1 +5x 2 x 1 6 4x 1 +9x 2 35 x 1 3x 2 1 3x 1 +2x 2 19 x Z 2 +
Exemple bis (en explorant la branche gauche d abord) max 9x 1 +5x 2 x 1 6 4x 1 +9x 2 35 x 1 3x 2 1 3x 1 +2x 2 19 x Z 2 +
Exemple bis (en explorant la branche gauche d abord) max 9x 1 +5x 2 x 1 6 x 1 3x 2 1 3x 1 +2x 2 19 x Z 2 + lb = 56,5 x 2 Z ub = x = (6, 1 2 )
Exemple bis (en explorant la branche gauche d abord) max 9x 1 +5x 2 x 1 6 x 1 3x 2 1 3x 1 +2x 2 19 x Z 2 + lb = 56,5 x 2 Z x 2 0 x 2 1 ub = x 2 1 x 2 1
Exemple bis (en explorant la branche gauche d abord) lb = 56,5 max 9x 1 +5x 2 x 1 6 x 1 3x 2 1 3x 1 +2x 2 19 x 2 0 x 2 1 lb = 54 x Z n x Z 2 + ub = 54 x = (6,0)
Exemple bis (en explorant la branche gauche d abord) lb = 56,5 max 9x 1 +5x 2 x 1 6 x 1 3x 2 1 3x 1 +2x 2 19 x Z 2 + x 2 0 lb = 54 x Z n x 2 1 lb = 56 x 1 Z ub = 54
Exemple bis (en explorant la branche gauche d abord) lb = 56,5 max 9x 1 +5x 2 x 1 6 x 1 3x 2 1 3x 1 +2x 2 19 x Z 2 + x 2 0 lb = 54 x Z n x 2 1 lb = 56 x 1 Z ub = 54 x 1 5 x 1 6
Exemple bis (en explorant la branche gauche d abord) lb = 56,5 max 9x 1 +5x 2 x 1 6 x 1 3x 2 1 3x 1 +2x 2 19 x 2 0 lb = 54 x Z n x 2 1 lb = 56 x Z 2 + x 1 5 x 1 6 ub = 54
Exemple bis (en explorant la branche gauche d abord) lb = 56,5 max 9x 1 +5x 2 x 1 6 x 1 3x 2 1 3x 1 +2x 2 19 x 2 0 lb = 54 x Z n x 2 1 lb = 56 x Z 2 + ub = 54 x 1 5 x 1 6 lb = 53.667
Exemple bis (en explorant la branche gauche d abord) max 9x 1 +5x 2 x 1 6 x 1 3x 2 1 3x 1 +2x 2 19 x 2 0 lb = 54 x Z n x 2 1 lb = 56 x Z 2 + ub = 54 x 1 5 x 1 6 lb = 53.667
Exemple bis (en explorant la branche gauche d abord) max 9x 1 +5x 2 x 1 6 x 1 3x 2 1 3x 1 +2x 2 19 x Z 2 + ub = 54 x 2 0 lb = 54 x Z n x 2 1 x 1 5 lb = 56 x 1 6 lb =
Choisir un problème Le but est à la fois de trouver rapidement des bonnes solutions (pour faciliter l élaguage) et de ne pas explorer des nœuds de coût trop mauvais. Profondeur d abord : minimise l espace mémoire, mais peut être très lent si une bonne solution n est pas trouvée vite. En choissant le nœud qui donne la meilleure borne (best-bound) : minimise le nombre de nœud, mais peut demander beaucoup d espace mémoire. Une bonne approche est de combiner les deux : on plonge dans l arbre jusqu à une feuille et on remonte au nœud qui donne la meilleure borne.
Choix de la variable de branchement Le but est de choisir la variable qui donnera le plus petit arbre. Soit ˆx i la solution du nœud. On note f j = ˆx j i ˆxi j la partie fractionnaire de cette solution. 1. Choisir la variable la plus fractionnaire : ĵ maximisant : min{f j,1 f j } (pas très bon). 2. Pseudo-coûts. 3. Strong branching.
Pseudo-Coûts Idée Au cours de la recherche, on va brancher plusieurs fois sur la même variables. Collectons des statistiques sur l effet de brancher sur chaque variable, au fur et à mesure de l algorithme. À chaque nœud utilisons ces statistiques pour faire le choix. Implémentation ψ + j /ψ j changement moyen de l objectif quand on branche sur la variable j à droite ou à gauce. Après chaque branchement on met à jour ψ + j ou ψ j. A chaque nœud on utilise ψ + j et ψ j pour prédire le changement : ψ j = min{f i j ψ i,(1 f i j )ψ + j }+2max{f i j ψ i,(1 f i j )ψ + j }
Strong-branching À chaque nœud essayons plusieurs candidats en simulant le branchement :
Strong-branching À chaque nœud essayons plusieurs candidats en simulant le branchement : x 1 x 1 x 1 x 1 x 1
Strong-branching À chaque nœud essayons plusieurs candidats en simulant le branchement : x 1,x 2,... x 2 x 2 x 2 x 2
Strong-branching À chaque nœud essayons plusieurs candidats en simulant le branchement : x 1,x 2,... x i x i x i x i Si pour un j les deux descendants sont irréalisables : élaguage.
Strong-branching À chaque nœud essayons plusieurs candidats en simulant le branchement : x 1,x 2,... x i x i x i x i Si pour un j les deux descendants sont irréalisables : élaguage. Si pour un j une des deux descendants est irréalisable fixe la variable.
Strong-branching À chaque nœud essayons plusieurs candidats en simulant le branchement : x 1,x 2,... x i x i x i x i Si pour un j les deux descendants sont irréalisables : élaguage. Si pour un j une des deux descendants est irréalisable fixe la variable. Choisis la variable j avec deux descendants réalisables et le meilleur potentiel.
Peut être combiné avec les pseudo-coûts On fait strong-branching η fois pour chaque variable ensuite on utilise les pseudo-coûts. Strong-branching À chaque nœud essayons plusieurs candidats en simulant le branchement : x 1,x 2,... x i x i x i x i Si pour un j les deux descendants sont irréalisables : élaguage. Si pour un j une des deux descendants est irréalisable fixe la variable. Choisis la variable j avec deux descendants réalisables et le meilleur potentiel.
Algorithme de Plans Coupants PLNE Soit P =: {x R n + : Ax b} et X := P {x : x i Z, i = 1,...,p}. On considère le problème : min c T x x X 0. Initialisation. C R \. 1. Relaxation Résoudre min{c T x : x P C}. Soit x la solution. Aller en 2. 2. Fin? Si x i Z, i = 1...,p, FIN, sinon Aller en 3. 3. Séparation Trouver α,β tel que α T x < β et α T x β pour tout x X. C {α T x β}. Aller en 1.
Branch-and-cut Combinaison de l algorithme de plans coupants et du branch-and-bound. Dans la boucle de traitement des nœuds, on insère la possibilité de renforcer la formulation avec des coupes.
0. Initialisation. L {(, )}. C =, ub =. x NULL. 1. Fin? Si L =, la solution x est optimale. 2. Selectionner un noeud. Choisir un problème N i = (F 0,F 1 ) dans L. 3. Evaluer. Résoudre LP(C,F 0,F 1 ). Si le problème n est pas réalisable aller en 1, sinon soit ˆx i sa solution. 4. Élaguer. Si cˆx i ub, aller en 1. Si ˆx i est entier : ub cˆx i, enlever de L tous les problèmes avec cˆx j ub puis aller en 1. Sinon aller en 5. 5. Couper ou Diviser? Choisir soit de générer des coupes soit de diviser, aller en 6 ou 7 selon le choix. 6. Couper Résoudre le problème de séparation pour ˆx i de manière à générer une ou plusieurs coupes. Aller en 3. 7. Diviser Choisir j tel que ˆx i j Z, ajouter à L les deux sous problème (F O {j},f 1 ) et (F O,F 1 {j}). Aller en 1.
Deuxième partie II Usage d un solveur de PLNE : GLPK
Solveurs de PLNE Plusieurs logiciels proposent des implémentations de l algorithme de branch-and-cut pour la PLNE. Parmi les meilleurs 1. IBM CPLEX, Commercial, 2. FICO XPRESS, Commercial, 3. GuRoBi, Commercial, 4. SCIP, Académique, gratuits pour les universités, 5. COIN-OR Cbc, Open source https://projects.coin-or.org/cbc. GLPK est un solveur open-source (GPL) un peu moins évolué mais dont les interfaces sont similaires aux principaux solveurs. Interfaces Différentes interfaces vers les solveurs : Fichiers textes : formats MPS et LP. Modeleurs : pour prototyper rapidement un modèle. Languages de programmation (C et C++) : plus rapide et permet d adapter l algorithme à une application.
Interfaces des solveurs solveur C C++ 1 CLI 2 Python Modeleurs CPLEX x x x x Ampl, Aims, OPL, GAMS XPRESS x x 3 x - Mosel, GAMS GuRoBi x - 4 - x Aims, Ampl, GAMS SCIP x x - Zimpl Cbc x x - GnuMP, Ampl, GAMS Glpk x x - GnuMp 1. Aussi Java et ṄET 2. Command Line Interface : ligne de commande 3. Aussi Java et ṄET 4..NET
Glpk Fait partie du projet GNU. Développé en Russie par Andrew Makhorin (Moscow Aviation Institute). Code source en C. Implémente une méthode de Simplexe, un branch-and-cut et un language de modélisation. Disponible dans la plupart des distributions linux. Un package est disponible pour Windows. Sous MacOS X, disponible dans MacPorts. Code propre et bien documenté.
Modélisation avec GnuMP Permet le prototypage rapide d un modèle. Le modèle est dans un fichier.mod Les données dans un fichier.dat Le language de moélisation est basé sur la notion d ensembles. Les modèles peuvent ensuite être résolu avec le programme glpsol. Exemple pour le problème de localisation d entrepots : avec les fichiers... glpsol -m UFL.mod -d UFL.dat
UFL.mod param n;#dépots param m;#clients set N:=1..n;#dépots set M:=1..m;#clients param f{j in N}; param c{i in M, j in N}; var x{i in M, j in N} >=0; var y{j in N} binary; minimize cost: sum{i in M, j in N} c[i,j] * x[i,j] + sum{j in N} f[j] * y[j]; s.t. affectation{i in M} : sum{j in N} x[i,j] = 1; cout_fixe{i in M, j in N} : x[i,j] <= y[j]; end
UFL.dat param n := 60;#dépots param m := 100; #clients param: f := 1 83 2 86... 60 81 ; param: c := 1 1 15 1 2 15... 100 60 23 ; end;
API C pour GLPK Les fonctions sont dans le fichier glpk.h (à inclure) Toutes les fonctions commencent par le préfixe glp. Principale difficulté : Les tableaux sont numérotés à partir de 1.
Initialization La principale structure de données glp prob. Création d un problème : glp_prob * glp_create_prob(); Nommer le problème : glp_set_prob_name(glp_prob lp*,const char * nom); Nommer l objectif : glp_set_obj_name(glp_prob*lp, const char * nom); Choix de la direction d optimisation (sens = GLP MIN/GLP MAX) glp_set_obj_dir(glp_prob *lp,int sens); Spécification du nombre de contraintes : glp_add_rows(glp_prob *lp, int n_rows); Spécification du nombre de variables : glp_add_cols(glp_prob *lp, int n_cols); Libération de la mémoire : glp_delete_prob(glp_prob *lp);
Spécification des variables Nom de la variable (j 1) : glp_set_col_name(glp_prob *lp, int j, const char *nom); Spécifie les bornes : glp_set_col_bnds(glp_prob *lp, int j, int type, double inf, double sup); où type est GLP LO variable avec borne inf seulement, GLP UP var. avec une borne sup, GLP DB bornes inf et sup, GLP FR non bornée. Spécifie le coût glp_set_obj_coef(glp_prob *lp, int j, double c); Type de la variable glp_set_col_kind(glp_prob *lp, int j, int type); (où type est GLP CV pour continue, GLP IV pour entière, et GLP BV pour binaire)
Écriture des contraintes Pour écrire la contrainte i du problème de la forme ax{,,=}b (on compte i à partir de 1). Spécification du nom de la contrainte : glp_set_row_name(glp_prob *lp, int i, const char * name); Spécification des bornes : glp_set_row_bnds(glp_prob *lp, int i, int sense, double b, double b); 1. GLP FX est pour une contrainte ax = b. 2. GLP UP pour une contrainte ax b. 3. GLP LO pour une contrainte ax b. Spécification du membre de gauche. On stocke les indices non-nuls dans le tableau row idx et les valeurs dans row val : glp_set_mat_row(glp_prob *lp, int i, int n, int [] row_idx, double [] row_val);
Exemple d écriture d une contrainte Pour écrire la contrainte 2x 1 +10x 4 +5x 10 1 : row idx = n/u 5 1 4 10 row val = n/u 2 10 5 glp_set_row_bnds(lp, i, GLP_LO, 1, 1); glp_set_mat_row(lp, i, 3, row_idx, row_val); 5. l élément 0 du tableau n est pas utilisé
Optimiser, récupérer les résultats Ecrit le problème dans un fichier LP glp_write_lp(glp_prob *lp, NULL, const char * nom); Résoud la relaxation continue glp_simplex(glp_prob *lp, NULL); Initializations des paramètres pour la résolution en nombres entiers glp_iocp param; glp_init_iocp(¶m); Résolution d un PLM glp_intopt(glp_prob *lp, glp_iocp * param); Réecupération de la valeur objective du PLM double glp_mip_obj_val(glp_prob *lp); Récupération de la valeur d une variable double glp_mip_col_val(glp_prob *lp, int j);
Exemple : UFL Écriture d un problème. Optimisation Résultats On considère la version avec demandes non-unitaires du problème de localisation d entrepots (formulation faible) : n m n min c ij x ij + y j f j j=1 i=1 tel que n x ij = d i j=1 m m x ij = ( d i )y j i=1 y j {0,1} x ij [0,d i ] i=1 j=1 i = 1,...,m j = 1,...,n j = 1,...,n i = 1,...,m,j = 1,...,n.
Troisième partie III Fonctionnalités avancées de GLPK
Fonctions callback GLPK implémente un algorithme de branch-and-cut pour la programmation en nombres entiers. Une implémentation de coupes de Gomory est incluse. L utilisateur peut ajouter des méthodes supplémentaires adaptées à son application pour améliorer l efficacité du solveur. Pour ce faire, le mécanisme adopté est celui d une fonction callback. La fonction callback doit être écrite par l utilisateur est sera appelée par GLPK pendant l optimisation dans plusieurs endroit du branch-and-cut.
0. Initialisation. L {(, )}. C =, ub =. x NULL. 1. Fin? Si L =, la solution x est optimale. 2. Selectionner un noeud. Choisir un problème N i = (F 0,F 1 ) dans L. 3. Evaluer. Résoudre LP(C,F 0,F 1 ). Si le problème n est pas réalisable aller en 1, sinon soit ˆx i sa solution. 4. Élaguer. Si cˆx i ub, aller en 1. Si ˆx i est entier : ub cˆx i, enlever de L tous les problèmes avec cˆx j ub puis aller en 1. Sinon aller en 5. 5. Couper ou Diviser? Choisir soit de générer des coupes soit de diviser, aller en 6 ou 7 selon le choix. 6. Couper Résoudre le problème de séparation pour ˆx i de manière à générer une ou plusieurs coupes. Aller en 3. 7. Heuristique Essayer de trouver une solution réalisable de manière heuristique. 8. Diviser Choisir j tel que ˆx j i. Créer sous-problèmes, aller en 1.
Définition de la fonction callback La fonction callback doit être définie comme ayant deux arguments : ma_fonction(glp_tree * tree, void * info); glp tree est une structure GLPK stockant les informations sur l optimisation. info peut-être utilisé par l utilisateur pour passer des données externes. Le nom de la fonction callback doit ensuite être donnée à GLPK dans le champ cb func de la structure glp iocp. On peut passer les données externes dans cb info.
Exemple On définit une calback : generateur(glp_tree * tree, void * info); On crée une instance de la structure glp iocp à laquelle on passe le nom de la fonction : glp_prob * lp = glp_create_prob(); glp_iocp param; glp_init_iocp(¶m); param.cb_func = generateur; /* eventuellement*/ parma.cb_info = mes_donnees; Pour optimiser le problème, on appelle la fonction int opt avec lp et param comme paramètres : glp_intopt(lp, ¶m);
Routines de bases pouvant être appelées dans la callback int ios reason(glp tree *) : Indique l endroit d où la callback a été appelée en retournant : GLP ISELECT selection de sous-problème; GLP IPREPRO preprocessing; GLP IHEUR heuristique; GLP ICUTGEN génération de coupe; GLP IBRANCH variable de branchement; glp prob *glp ios get prob(glp tree *tree) : retourne le sous-problème (programme linéaire en cours de traitement). Au travers du pointeur retourné, on peut accéder aux données du problème, la solution courante,...
Exemple On veut faire un générateur de coupe. void generateur(glp_tree * tree, void * info){ int reason = glp_ios_reason(tree); if(reason!= GLP_ICUTGEN)/* quitte si autre que icutgen*/ return; glp_prob * prob = glp_ios_get_prob(tree); int n = glp_get_num_cols(prob);/*nombre de variables*/ int m = glp_get_num_rows(prob);/*nombre de contraintes*/... return; }
Principales Routines spécifique Si GLP ISELECT, spécifie à GLPK le prochain problème comme celui de numéro p : void glp_ios_select_node(glp_tree *tree, int p); Si GLP IHEUR, spécifie à GLPK une nouvelle solution entière x : int glp_ios_heur_sol(glp_tree *tree, const double x[]); Si GLP IBRANCH : int glp_ios_can_branch(glp_tree *tree, int j); indique on peut brancher sur la variable j (elle n est pas fixée). void glp_ios_branch_upon(glp_tree *tree, int j, int sel); Spécifie à GLPK de brancher sur la variable j et d explorer en premier le nœud de gauche (sel = GLP DN BRNCH), de droite (sel = GLP UP BRNCH), de choisir lui même (sel = GLP NO BRNCH).
Routines spécifique (suite) Si GLP ICUTGEN : int glp_ios_add_row(glp_tree *tree, const char *name, int klass, int flags, int len, const int ind[], const double val[], int type, double rhs); Ajoute une coupe. name donne un nom à la coupe (peut être NULL. klass : un nombre entre 101 et 200. flags : non utilisé. len : nombre d éléments non-nuls dans la contrainte. ind[] : indices des éléments non-nuls. val[] : valeurs des éléments non-nuls. type : GLP LO si la contrainte est, GLP UP si la contrainte est. rhs : membre de droite.
Exemple de génération de coupe Génère l inegalité x i +x j +x k 1 ind[1] = i, val[1] = 1.0; ind[2] = j, val[2] = 1.0; ind[3] = k, val[3] = 1.0; glp_ios_add_row(tree, NULL, 101, 0, 3, ind, val, GLP_UP, 1.0);
Exemple : UFL Ajout des coupes x ij d i y j pour tout i = 1,...,m, j = 1,...,n.