#include "cplexmutable.h" #include #include #include #include // #define CPLEX_WITH_NAMES #define INFINI (std::numeric_limits::infinity()) using namespace std ; inline std::string operator+ (const std::string & prefix, int n) { std::ostringstream out; out << n ; return prefix + out.str(); } CPlexMutable::CPlexMutable(std::string nom, ObjectiveSense obj_sense, ProblemType type, bool internal_silent, bool silent, bool writeToFile, bool with_names) : CPlexModel(nom,obj_sense,type,internal_silent,silent,writeToFile,with_names) { init() ; } void CPlexMutable::init() { #ifndef NO_CPLEX int status = 0; /* If an error occurs, the status value indicates the reason for failure. A call to CPXgeterrorstring will produce the text of the error message. Note that CPXopenCPLEX produces no output, so the only way to see the cause of the error is to use CPXgeterrorstring. For other CPLEX routines, the errors will be seen if the CPX_PARAM_SCRIND indicator is set to CPX_ON. */ /* Initialize the CPLEX environment */ env = CPXopenCPLEX ( &status ); if ( env == NULL ) throw CPlexFailed("Could not open CPLEX environment.", env, status); /* Turn on/off output to stdout */ status = CPXsetintparam ( env, CPX_PARAM_SCRIND, (cpx_internal_silent ? CPX_OFF : CPX_ON) ); if ( status ) throw CPlexFailed("Failure to set screen indicator.", env, status); /* Create the problem. */ /* A returned pointer of NULL may mean that not enough memory was available or there was some other problem. In the case of failure, an error message will have been written to the error channel from inside CPLEX.*/ lp = CPXcreateprob ( env, &status, cpx_probname.c_str() ); if ( lp == NULL ) throw CPlexFailed("Failed to create LP.", env, status); status = CPXchgprobtype(env, lp, cpx_problemtype); if ( status ) throw CPlexFailed("Failure to set problem type.", env, status); #endif setOption( None ); } void CPlexMutable::reinit() { for (size_t i=0; i::iterator it=m_zoneHorizontale.begin(); it!=m_zoneHorizontale.end(); it++) { if (it->second > colonne) it->second -= taille ; } #ifndef NO_CPLEX int status = CPXdelcols(env, lp, colonne, colonne + taille - 1); if ( status ) throw CPlexFailed("Failed to remove a column.", env, status ); #endif } /** * récupération des valeurs trouvées pour les variables d'une zone horizontale * @param zoneH index de la zone * @return vecteur des valeurs des variables */ std::vector CPlexMutable::getResult(std::string zoneH) { // contrôle de l'index de zone if (m_zoneHorizontale.find(zoneH)==m_zoneHorizontale.end()) throw std::string("zone inexistante"); // calcul de la taille de la zone size_t taille = m_taille_zoneHorizontale[zoneH] ; // copie des résultats dans le vecteur de retour std::vector vars(taille); #ifndef NO_CPLEX int status = CPXgetx ( env, lp, &(vars[0]), m_zoneHorizontale[zoneH], m_zoneHorizontale[zoneH] + taille - 1 ); if ( status ) throw CPlexFailed("Failed to get optimal integer x_cplex.", env, status ); #endif return vars; } /** * récupération des valeurs trouvées pour les variables d'une zone horizontale * pour une solution faisant partie du bassin de solutions (après appel à populate) * @param zoneH index de la zone * @return vecteur des valeurs des variables */ std::vector CPlexMutable::getResult(int sol_id, std::string zoneH) { // contrôle de l'index de zone if (m_zoneHorizontale.find(zoneH)==m_zoneHorizontale.end()) throw std::string("zone inexistante"); // calcul de la taille de la zone size_t taille = m_taille_zoneHorizontale[zoneH] ; // copie des résultats dans le vecteur de retour std::vector vars(taille); #ifndef NO_CPLEX int status = CPXgetsolnpoolx ( env, lp, sol_id, &(vars[0]), m_zoneHorizontale[zoneH], m_zoneHorizontale[zoneH] + taille - 1 ); if ( status ) throw CPlexFailed("Failed to get optimal integer x_cplex.", env, status ); #endif return vars; } /** * récupèration de la valeur des coûts réduits d'une zone horizontale * @param zoneH index de la zone * @return vecteur des valeurs des coûts réduits */ std::vector CPlexMutable::getReducedCosts(std::string zoneH) { // contrôle de l'index de zone if (m_zoneHorizontale.find(zoneH)==m_zoneHorizontale.end()) throw string("zone inexistante"); // calcul de la taille de la zone size_t taille = m_taille_zoneHorizontale[zoneH] ; // copie des résultats dans le vecteur de retour std::vector cr(taille); #ifndef NO_CPLEX int status = CPXgetdj ( env, lp, &(cr[0]), m_zoneHorizontale[zoneH], m_zoneHorizontale[zoneH] + taille - 1 ); if ( status ) throw CPlexFailed("Failed to get reduced costs.", env, status ); #endif return cr; } /** * récupération des valeurs trouvées pour les variables duales d'une zone verticale * @param zoneV index de la zone * @return vecteur des valeurs des variables */ std::vector CPlexMutable::getDuals(std::string zoneV) { // contrôle de l'index de zone if (m_zoneVerticale.find(zoneV)==m_zoneVerticale.end()) throw string("zone inexistante"); // calcul de la taille de la zone size_t taille = m_taille_zoneVerticale[zoneV] ; // copie des résultats dans le vecteur de retour vector duals(taille); #ifndef NO_CPLEX int status = CPXgetpi ( env, lp, &(duals[0]), m_zoneVerticale[zoneV], m_zoneVerticale[zoneV] + taille - 1 ); if ( status ) throw CPlexFailed("Failed to get duals.", env, status ); #endif return duals; } /** * récupération des valeurs trouvées pour l'infaisabilité d'une zone verticale * @param zoneV index de la zone * @return vecteur des valeurs des variables */ std::vector< double > CPlexMutable::getInfeasibilities(string zoneV) { // contrôle de l'index de zone if (m_zoneVerticale.find(zoneV)==m_zoneVerticale.end()) throw string("zone inexistante"); // calcul de la taille de la zone size_t taille = m_taille_zoneVerticale[zoneV] ; // copie des résultats dans le vecteur de retour vector valeurs(taille); #ifndef NO_CPLEX int status = CPXgetrowinfeas ( env, lp, NULL, &(valeurs[0]), m_zoneVerticale[zoneV], m_zoneVerticale[zoneV] + taille - 1 ); if ( status ) throw CPlexFailed("Failed to get infeasibilities.", env, status ); #endif return valeurs; } /** * la solution est-elle "infeasible" */ bool CPlexMutable::getInfeasible() { return CPXgetstat ( env, lp ) == 3 ; } /** * résolution du problème par appel à cplex * @return valeur de la fonction objectif */ double CPlexMutable::resolution() { #ifndef NO_CPLEX int status = 0; /* Write a copy of the problem to a file. */ if (m_writeToFile) write_pb() ; /* Optimize the problem and obtain solution. */ switch (cpx_problemtype) { case MixedInteger : /* status = CPXsetintparam( env, CPX_PARAM_NODEFILEIND, 3); if ( status ) throw CPlexFailed("Failure to turn on writing nodes to file.", env, status);*/ status = CPXsetintparam( env, CPX_PARAM_NODESEL, 0); if ( status ) throw CPlexFailed("Failure to set node selection to depth first.", env, status); status = CPXmipopt ( env, lp ); break; case Linear : status = CPXlpopt ( env, lp ); // status = CPXsetintparam( env, CPX_PARAM_FEASOPTMODE, CPX_FEASOPT_MIN_SUM); // status = CPXfeasopt( env, lp, NULL,NULL,NULL,NULL); } if ( status ) throw CPlexFailed("Failed to optimize LP.", env, status ); if (!cpx_silent) { cout << "\nSolution status = " << CPXgetstat ( env, lp ) << " : " << statusstring(env,CPXgetstat ( env, lp )) << endl; } /* Get the objective value. */ status = CPXgetobjval ( env, lp, &cpx_objval ); if ( status ) throw CPlexFailed("No MIP objective value available.", env, status); if (!cpx_silent) cout << "Solution value = " << cpx_objval << endl << endl; /* écriture de la solution sur disque */ if (m_writeToFile) write_sol(); #endif return cpx_objval; } /** * résolution du problème par appel à cplex * et remplissage du bassin de solutions * @return valeur de la fonction objectif */ vector CPlexMutable::populate() { vector obj ; #ifndef NO_CPLEX int status = 0; /* Optimize the problem and obtain solution. */ switch (cpx_problemtype) { case MixedInteger : status = CPXpopulate ( env, lp ); break; case Linear : return obj; } if ( status ) throw CPlexFailed("Failed to populate solution pool.", env, status ); if (!cpx_silent) { cout << "\nSolution status = " << CPXgetstat ( env, lp ) << " : " << statusstring(env,CPXgetstat ( env, lp )) << endl; } /* Get the objective values */ int nb_sol = CPXgetsolnpoolnumsolns(env, lp) ; obj.resize(nb_sol, INFINI); for (int i=0; i::const_iterator it=m_zoneHorizontale.begin(); it!=m_zoneHorizontale.end(); it++) { ofs << "Variables : " << it->first << "\tDébut : " << it->second << "\tNombre de variables : " << m_taille_zoneHorizontale[it->first] << "\tFin : " << m_taille_zoneHorizontale[it->first] + it->second << endl ; for ( size_t i=0; ifirst]; i++) { ofs << "x" << it->second + i + 1 << "\t : " << it->first << "_" << i << std::endl ; } } for ( map::const_iterator it=m_zoneVerticale.begin(); it!=m_zoneVerticale.end(); it++) { ofs << "Contraintes : " << it->first << "\tDébut : " << it->second << "\tNombre de variables : " << m_taille_zoneVerticale[it->first] << "\tFin : " << m_taille_zoneVerticale[it->first] + it->second << endl ; for ( size_t i=0; ifirst]; i++) { ofs << "c" << it->second + i + 1 << "\t : " << it->first << "_" << i << std::endl ; } } } void CPlexMutable::write_sol() { int status ; /* Get variables values. */ /* The size of the problem should be obtained by asking CPLEX what the actual size is, rather than using what was passed to CPXcopylp. cur_numrows and cur_numcols store the current number of rows and columns, respectively. */ size_t cur_numcols = CPXgetnumcols ( env, lp ); ofstream ofs((cpx_probname+".sol").c_str()); for (size_t c=0; c