diff --git a/src/CALLBACK/sirius_callback.h b/src/CALLBACK/sirius_callback.h new file mode 100644 index 0000000..6c7984d --- /dev/null +++ b/src/CALLBACK/sirius_callback.h @@ -0,0 +1,19 @@ +#ifdef __cplusplus +extern "C" +{ +#endif +#pragma once + + typedef enum SIRIUS_LOGLEVEL + { + SIRIUS_TRACE, + SIRIUS_DEBUG, + SIRIUS_INFO, + SIRIUS_WARN, + SIRIUS_ERROR, + SIRIUS_FATAL + } SIRIUS_LOGLEVEL; + typedef int (*callback_function)(void *caller, const char *sMsg, int nLen, SIRIUS_LOGLEVEL log_level); +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c6e1e9a..b1e9dbd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,9 +16,9 @@ MESSAGE("CMAKE_SOURCE_DIR : ${CMAKE_SOURCE_DIR}") SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}) SET( LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}) -INCLUDE_DIRECTORIES(. ALLOCATEUR BRANCH_AND_BOUND POINT_INTERIEUR PRESOLVE SIMPLEXE SIMPLEXE/LU PNE SRS) +INCLUDE_DIRECTORIES(. CALLBACK ALLOCATEUR BRANCH_AND_BOUND POINT_INTERIEUR PRESOLVE SIMPLEXE SIMPLEXE/LU PNE SRS) -FILE(GLOB HEADERS ALLOCATEUR/*.h PRESOLVE/*.h BRANCH_AND_BOUND/*.h POINT_INTERIEUR/*.h SIMPLEXE/*.h SIMPLEXE/LU/*.h ./PNE/*.h ./SRS/*.h) +FILE(GLOB HEADERS ./CALLBACK/*.h ALLOCATEUR/*.h PRESOLVE/*.h BRANCH_AND_BOUND/*.h POINT_INTERIEUR/*.h SIMPLEXE/*.h SIMPLEXE/LU/*.h ./PNE/*.h ./SRS/*.h ) FILE(GLOB ALLOCATEUR_FILES ALLOCATEUR/*.c ALLOCATEUR/*.h) FILE(GLOB PRESOLVE_FILES PRESOLVE/*.c PRESOLVE/*.h) @@ -28,6 +28,7 @@ FILE(GLOB SIMPLEXE_FILES SIMPLEXE/*.c SIMPLEXE/*.h) FILE(GLOB LU_FILES SIMPLEXE/LU/*.c SIMPLEXE/LU/*.h) FILE(GLOB PNE_FILES PNE/*.c PNE/*.h) FILE(GLOB SRS_FILES SRS/*.c SRS/*.h) +FILE(GLOB CALLBACK_FILES CALLBACK/*.h ) GET_FILENAME_COMPONENT(FULL_PATH_TEST_CPP ${CMAKE_CURRENT_SOURCE_DIR}/PNE/pne_standalone.c ABSOLUTE) MESSAGE("REMOVING FROM SOURCE ${FULL_PATH_TEST_CPP}") @@ -35,8 +36,8 @@ MESSAGE("REMOVING FROM SOURCE ${FULL_PATH_TEST_CPP}") LIST(REMOVE_ITEM PNE_FILES ${FULL_PATH_TEST_CPP}) # MESSAGE("-- PNE_FILES : ${PNE_FILES}") -ADD_LIBRARY(sirius_solver_static STATIC ${ALLOCATEUR_FILES} ${PRESOLVE_FILES} ${BRANCH_AND_BOUND_FILES} ${POINT_INTERIEUR_FILES} ${SIMPLEXE_FILES} ${LU_FILES} ${PNE_FILES} ${SRS_FILES}) -ADD_LIBRARY(sirius_solver SHARED ${ALLOCATEUR_FILES} ${PRESOLVE_FILES} ${BRANCH_AND_BOUND_FILES} ${POINT_INTERIEUR_FILES} ${SIMPLEXE_FILES} ${LU_FILES} ${PNE_FILES} ${SRS_FILES}) +ADD_LIBRARY(sirius_solver_static STATIC ${CALLBACK_FILES} ${ALLOCATEUR_FILES} ${PRESOLVE_FILES} ${BRANCH_AND_BOUND_FILES} ${POINT_INTERIEUR_FILES} ${SIMPLEXE_FILES} ${LU_FILES} ${PNE_FILES} ${SRS_FILES} ) +ADD_LIBRARY(sirius_solver SHARED ${CALLBACK_FILES} ${ALLOCATEUR_FILES} ${PRESOLVE_FILES} ${BRANCH_AND_BOUND_FILES} ${POINT_INTERIEUR_FILES} ${SIMPLEXE_FILES} ${LU_FILES} ${PNE_FILES} ${SRS_FILES} ) #ADD_EXECUTABLE(PNE_STANDALONE PNE/pne_standalone.c ) #ADD_EXECUTABLE(NEWSPX_STANDALONE SPX_STANDALONE/spx_standalone.c ) #ADD_EXECUTABLE(TEST_API TEST_API/main.c ) @@ -58,6 +59,7 @@ SET_TARGET_PROPERTIES(sirius_solver PROPERTIES PUBLIC_HEADER "${HEADERS}") SET_TARGET_PROPERTIES(sirius_solver_static PROPERTIES C_STANDARD 11) SET_TARGET_PROPERTIES(sirius_solver PROPERTIES C_STANDARD 11) target_include_directories(sirius_solver PUBLIC + $ $ $ $) diff --git a/src/PNE/mps_define.h b/src/PNE/mps_define.h index 6dea33f..4314d21 100644 --- a/src/PNE/mps_define.h +++ b/src/PNE/mps_define.h @@ -68,4 +68,6 @@ int * FirstNomVar; int * NomVarSuivant; double objective_offset; +void *callback; + } PROBLEME_MPS; diff --git a/src/PNE/pne_definition_arguments.h b/src/PNE/pne_definition_arguments.h index 94a215c..14f8984 100644 --- a/src/PNE/pne_definition_arguments.h +++ b/src/PNE/pne_definition_arguments.h @@ -78,7 +78,7 @@ typedef struct { La matrice des contrainte est decrite par les 4 vecteurs qui suivent. Elle doit etre decrite par ligne. -> Les coefficients de la matrice des contraintes doivent etre donnes dans un vecteur double precision. -> En parallele du vecteur des coefficient, il faut donner l'indice colonne du coefficient. - -> Pour chaque ligne (ou premier membre de la contrainte) il faut donner sont indice d�but dans le vecteur + -> Pour chaque ligne (ou premier membre de la contrainte) il faut donner sont indice d�but dans le vecteur double precision qui contient les coefficients de la contraintes, et le nombre de coefficients non nuls. */ int * IndicesDebutDeLigne ; /* Pour chaque ligne, indice debut de la ligne dans le @@ -104,7 +104,7 @@ La matrice des contrainte est decrite par les 4 vecteurs qui suivent. Elle doit */ /* Options */ char AlgorithmeDeResolution; /* Doit valoir SIMPLEXE ou POINT_INTERIEUR */ - /* Attention, le choix POINT_INTERIEUR ne peut �tre utilise que dans le cas + /* Attention, le choix POINT_INTERIEUR ne peut �tre utilise que dans le cas d'un probleme ne comportant pas de varaibles entieres */ char AffichageDesTraces; /* Peut valoir OUI_PNE ou NON_PNE */ char SortirLesDonneesDuProbleme; /* Peut valoir OUI_PNE ou NON_PNE. @@ -115,25 +115,27 @@ La matrice des contrainte est decrite par les 4 vecteurs qui suivent. Elle doit solution optimale n'a pas ete trouvee. Attention, cette grandeur n'est prise en compte que si le probleme contient des variables entieres */ /* Mettre 0 si le temps est illimite */ - int NombreMaxDeSolutionsEntieres; /* Lorsque le nombre de solutions entieres est egal � la valeur de ce + int NombreMaxDeSolutionsEntieres; /* Lorsque le nombre de solutions entieres est egal � la valeur de ce parametre, le solveur s'arrete et donne la meilleure solution rencontree. Remarque: mettre une valeur strictement negative pour que ce parametre n'ai pas - de r�le. + de r�le. */ - double ToleranceDOptimalite; /* Si l'�cart relatif entre le cout de la solution entiere trouvee et le plus petit minorant - est inf�rieur � ToleranceDOptimalite, le solveur s'arrete et consid�re que la solution + double ToleranceDOptimalite; /* Si l'�cart relatif entre le cout de la solution entiere trouvee et le plus petit minorant + est inf�rieur � ToleranceDOptimalite, le solveur s'arrete et consid�re que la solution entiere trouvee est la solution optimale. - Convention: ToleranceDOptimalite doit etre exprim� en %. + Convention: ToleranceDOptimalite doit etre exprim� en %. Conseil : mettre 0 %. */ char CoupesLiftAndProject; /* Utile que s'il y a des variables entieres dans le probleme. Peut valoir OUI_PNE ou NON_PNE. Lorsque cette option vaut OUI_PNE - le calcul des coupes de type lift and project est activ�. - - Choix conseill�: NON_PNE car le calcul de ce type de coupe peut �tre + le calcul des coupes de type lift and project est activ�. + - Choix conseill�: NON_PNE car le calcul de ce type de coupe peut �tre couteux. - Mettre OUI_PNE si le probleme est difficile a resoudre. */ double objective_offset; + void *callback; + } PROBLEME_A_RESOUDRE; diff --git a/src/SIMPLEXE/spx_define.h b/src/SIMPLEXE/spx_define.h index 4d17c67..7b1f1ac 100644 --- a/src/SIMPLEXE/spx_define.h +++ b/src/SIMPLEXE/spx_define.h @@ -299,7 +299,7 @@ double Cout; /* Valeur du cout de la solution */ double CoutMax; /* Valeur du cout au dessus de laquelle on arrete les calculs (utilite: branch and bound) */ int UtiliserCoutMax; /* Vaut OUI_SPX si on desire faire le test par rapport a CoutMax, et NON_SPX si on ne veut pas utiliser cette possibilite */ -double PartieFixeDuCout; /* Partie du cout qui est due aux variables dont la valeur est fixe. C'est calcul� en +double PartieFixeDuCout; /* Partie du cout qui est due aux variables dont la valeur est fixe. C'est calcul� en entree du solveur */ char LeSteepestEdgeEstInitilise; @@ -436,6 +436,7 @@ char ExplorationRapideEnCours; /* OUI_SPX ou NON_SPX */ double A1; /*------------------------------------------*/ +void *callback; } PROBLEME_SPX; diff --git a/src/SIMPLEXE/spx_definition_arguments.h b/src/SIMPLEXE/spx_definition_arguments.h index 1838bbb..6430fc6 100644 --- a/src/SIMPLEXE/spx_definition_arguments.h +++ b/src/SIMPLEXE/spx_definition_arguments.h @@ -29,23 +29,23 @@ il contient la definition de la structure C exploitee par la fonction. Apres avoir renseigne les champs, le module utilisateur appelle la fonction SPX_Simplexe avec, pour argument d'appel: - - un pointeur � un objet de type PROBLEME_SIMPLEXE: il permet de renseigner les donnees - du probleme � r�soudre - - un pointeur � un objet de type PROBLEME_SPX. Lorsque la valeur de ce pointeur vaut NULL, + - un pointeur � un objet de type PROBLEME_SIMPLEXE: il permet de renseigner les donnees + du probleme � r�soudre + - un pointeur � un objet de type PROBLEME_SPX. Lorsque la valeur de ce pointeur vaut NULL, SPX_Simplexe alloue un nouvel objet de type PROBLEME_SPX sur lequel il travaillera. - Dans le cas contraire SPX_Simplexe travaillera sur l'objet de type PROBLEME_SPX pass� + Dans le cas contraire SPX_Simplexe travaillera sur l'objet de type PROBLEME_SPX pass� par l'appelant. - SPX_Simplexe renvoie un pointeur � un objet de type PROBLEME_SPX, ce pointeur - correspond � l'objet sur lequel SPX_Simplexe vient de faire ses calculs. + SPX_Simplexe renvoie un pointeur � un objet de type PROBLEME_SPX, ce pointeur + correspond � l'objet sur lequel SPX_Simplexe vient de faire ses calculs. - L'appelant peut de cette fa�on travailler sur plusieurs instances de problemes qu'il + L'appelant peut de cette fa�on travailler sur plusieurs instances de problemes qu'il souhaite faire resoudre par le simplexe. Exemple d'utilisation : PROBLEME_SIMPLEXE Mon_Probleme; <- definition d'une structure "Mon_Probleme" de type PROBLEME_SIMPLEXE - void * ProblemeSpx; <- Utiliser void * comme type de pointeur permet � l'appelant d'ignorer la + void * ProblemeSpx; <- Utiliser void * comme type de pointeur permet � l'appelant d'ignorer la composition de la structure PROBLEME_SPX, qu'il n'a d'ailleurs pas besoin de connaitre. ....... @@ -62,12 +62,12 @@ typedef struct { int Contexte; /* Contexte dans lequel le simplexe est utilise. Cet argument peut prendre 3 valeurs: - BRANCH_AND_BOUND_OU_CUT: le simplexe est appel� dans un contexte de Branch And Bound + BRANCH_AND_BOUND_OU_CUT: le simplexe est appel� dans un contexte de Branch And Bound ou de Branch And Cut - BRANCH_AND_BOUND_OU_CUT_NOEUD: le simplexe est appel� dans un contexte de Branch And Bound + BRANCH_AND_BOUND_OU_CUT_NOEUD: le simplexe est appel� dans un contexte de Branch And Bound ou de Branch And Cut mais on ne reinitialise pas le probleme - SIMPLEXE_SEUL: le simplexe est appel� hors d'un contexte de Branch and Bound ou de - Branch And Cut (dans ce cas, certaines sauvegardes particuli�res ne sont + SIMPLEXE_SEUL: le simplexe est appel� hors d'un contexte de Branch and Bound ou de + Branch And Cut (dans ce cas, certaines sauvegardes particuli�res ne sont pas faites) */ int NombreMaxDIterations; /* Si < 0 , le simplexe prendre sa valeur par defaut */ double DureeMaxDuCalcul; /* Exprime en secondes (attention c'est du double). @@ -102,23 +102,23 @@ typedef struct { SPX_PRIMAL s'il veut utiliser l'algorithme primal SPX_DUAL s'il veut utiliser l'algorithme dual */ /* Guidage de l'algorithme */ - int TypeDePricing; /* Le pricing est l'�tape du calcul dans laquelle on choisit la variable sortante + int TypeDePricing; /* Le pricing est l'�tape du calcul dans laquelle on choisit la variable sortante dans l'algorithme dual (ou la variale entrante dans l'algorithme primal). Deux choix sont possibles: - * PRICING_DANTZIG: c'est la m�thode basique, elle est rapide mais dans certains - cas conduit � faire beaucoup d'it�rations pour trouver l'optimum. - * PRICING_STEEPEST_EDGE: m�thode �labor�e (Forrest-Goldfarb), elle demande plus de - calculs mais permet de r�duite significativement le nombre d'it�rations. Il est - recommander de l'utiliser pour les probl�mes difficiles. */ + * PRICING_DANTZIG: c'est la m�thode basique, elle est rapide mais dans certains + cas conduit � faire beaucoup d'it�rations pour trouver l'optimum. + * PRICING_STEEPEST_EDGE: m�thode �labor�e (Forrest-Goldfarb), elle demande plus de + calculs mais permet de r�duite significativement le nombre d'it�rations. Il est + recommander de l'utiliser pour les probl�mes difficiles. */ int FaireDuScaling; /* Vaut OUI_SPX ou NON_SPX. Si l'utilisateur positionne la valeur a OUI_SPX, - le simplexe fait un scaling du probleme d�s le d�but de la r�solution. - Le scaling a pour but d'am�liorer le conditionnement du probl�me. Il est - recommand� de l'utiliser lorsque les coefficients de la matrice des contraintes - sont tr�s diff�rents les un des autres (rapport > 100) */ + le simplexe fait un scaling du probleme d�s le d�but de la r�solution. + Le scaling a pour but d'am�liorer le conditionnement du probl�me. Il est + recommand� de l'utiliser lorsque les coefficients de la matrice des contraintes + sont tr�s diff�rents les un des autres (rapport > 100) */ int StrategieAntiDegenerescence; /* Vaut AGRESSIF ou PEU_AGRESSIF. - * AGRESSIF: le controle est fait � chaque iterations. + * AGRESSIF: le controle est fait � chaque iterations. * PEU_AGRESSIF: le controle est fait moins souvent. - -> Choix recommand�: AGRESSIF + -> Choix recommand�: AGRESSIF */ /* En Entree ou en Sortie */ int BaseDeDepartFournie; /* Vaut OUI_SPX ou NON_SPX */ @@ -144,15 +144,15 @@ typedef struct { a "SPX_LibererProbleme" */ double CoutMax; /* En entree: cette information n'est utilisee que si l'algorithme choisi est l'algorithme dual. On sait qu'a chaque iteration de l'algorithme dual, le cout courant est un minorant du cout optimal. - Il est donc possible de comparer ce cout � un Cout Max, seuil au dessus duquel on convient d'arreter les + Il est donc possible de comparer ce cout � un Cout Max, seuil au dessus duquel on convient d'arreter les calculs (l'algorithme sort alors avec le verdict "pas de solution"). Quelle en est l'utilite (mais il peut y en avoir d'autres) ? Dans un contexte de branch and bound, des que l'on dispose d'une solution entiere, toutes les resolutions de - probleme relax� menant a un cout superieur a ce cout sont a rejeter. Donc, si l'on se rend compte au cours de + probleme relax� menant a un cout superieur a ce cout sont a rejeter. Donc, si l'on se rend compte au cours de l'algorithme dual, que la resolution du probleme relaxe va mener a un cout trop grand il est inutile de poursuivre les calculs. Ceci permet de gagner du temps de calcul. - ATTENTION: comme l'algorithme dual peut etre utilis� en tant que solveur (c'est � dire + ATTENTION: comme l'algorithme dual peut etre utilis� en tant que solveur (c'est � dire --------- en dehors d'un contexte de branch and bound) ou bien pour resoudre un probleme dont on de souhaite pas donner de Cout Max parce qu'on ne le connait pas, l'information "CoutMax" n'est utilisee par l'algorithme dual que si l'indicateur "UtiliserCoutMax" (argument suivant) @@ -172,8 +172,9 @@ typedef struct { double * CoutsReduits; /* Couts reduits des variables hors-base, longueur nombre de variables passees en entree du probleme. Contient la valeur 0 si la variable est basique */ /* Traces */ - char AffichageDesTraces; /* Vaut OUI_SPX ou NON_SPX */ - + char AffichageDesTraces; /* Vaut OUI_SPX ou NON_SPX */ + void *callback; + } PROBLEME_SIMPLEXE; /*******************************************************************************************/ diff --git a/src/SRS/srs_problem.c b/src/SRS/srs_problem.c index f97387a..9f10a00 100644 --- a/src/SRS/srs_problem.c +++ b/src/SRS/srs_problem.c @@ -8,6 +8,7 @@ #include #include #include +#include "sirius_callback.h" #include "srs_api.h" #include "pne_constantes_externes.h" #include "pne_fonctions.h" @@ -172,7 +173,8 @@ SRS_PROBLEM * SRScreateprob() { //MPS initProblemMpsPointer(problem_srs); - + problem_srs->callback = SRSdefault_callback; + return problem_srs; } @@ -806,7 +808,30 @@ int SRSgetbestbound(SRS_PROBLEM * problem_srs, double * bestBoundVal) { return -1; } +int SRSdefault_callback(void *caller, const char *sMsg, int nLen, SIRIUS_LOGLEVEL log_level) +{ + if (nLen <= 0) + { + return 0; + } + if (log_level == SIRIUS_ERROR) + { + fprintf(stderr, sMsg); + } + else + { + printf("%s", sMsg); + } +} +int SRSsetdefaultcbmessage(SRS_PROBLEM *problem_srs, callback_function the_callback_function, void *caller, SIRIUS_LOGLEVEL log_level) +{ + problem_srs->callback = SRSdefault_callback; +} +int SRSsetcbmessage(SRS_PROBLEM *problem_srs, callback_function the_callback_function, void *caller, SIRIUS_LOGLEVEL log_level) +{ + problem_srs->callback = the_callback_function; +} # ifdef __cplusplus } diff --git a/src/SRS/srs_problem.h b/src/SRS/srs_problem.h index 8e4c6d2..6f8ce8f 100644 --- a/src/SRS/srs_problem.h +++ b/src/SRS/srs_problem.h @@ -34,6 +34,7 @@ typedef struct SRS_PROBLEM { int presolve; int scaling; double maxTime; + void *callback; } SRS_PROBLEM; # ifdef __cplusplus diff --git a/src/SRS/srs_problem_functions.h b/src/SRS/srs_problem_functions.h index b3f9d43..7047f44 100644 --- a/src/SRS/srs_problem_functions.h +++ b/src/SRS/srs_problem_functions.h @@ -75,7 +75,8 @@ int SRSwritempsprob(PROBLEME_MPS * problem_mps, const char * fileName); int SRSfreempsprob(PROBLEME_MPS * problem_mps); int SPXcopy_problem(PROBLEME_MPS * problem_mps, PROBLEME_SIMPLEXE * problem_simplexe); int SRScopy_from_problem_simplexe(SRS_PROBLEM * problem_srs, PROBLEME_SIMPLEXE * problem_simplexe); - +int SRSdefault_callback(void *caller, const char *sMsg, int nLen, SIRIUS_LOGLEVEL log_level); +int SRSsetcbmessage(SRS_PROBLEM *problem_srs, callback_function the_callback_function, void *caller, SIRIUS_LOGLEVEL log_level); # ifdef __cplusplus } # endif