#include "cplexmodel.h" #ifndef NO_CPLEX #include #else #include #endif #include #include #include #include #include using namespace std; /** * CPlexFailed : exception levée par un appel à cplex */ CPlexFailed::CPlexFailed(string msg, void * env, int cpx_status) : string("Erreur CPlex : " + msg + "\n\tmessage : " + CPlexModel::errorstring(env,cpx_status)) { } CPlexFailed::CPlexFailed() { append("Erreur CPlex"); } /** * constructeur */ CPlexModel::CPlexModel(std::string nom, ObjectiveSense obj_sense, ProblemType type, bool internal_silent, bool silent, bool writeToFile, bool with_names) { env = NULL; lp = NULL; m_taille_Z = 0 ; m_taille_solvedZ= 0 ; cpx_numrows = 0 ; cpx_numcols = 0 ; cpx_solvedcols = 0 ; m_debut_zoneH = 0 ; m_debut_zoneV = 0 ; cpx_internal_silent = internal_silent ; cpx_silent = silent ; m_writeToFile = writeToFile ; m_with_names = with_names ; cpx_probname = nom ; cpx_objsense = (obj_sense==Maximisation ? CPX_MAX : CPX_MIN) ; cpx_problemtype = type ; } void CPlexModel::set_name(string nom) { cpx_probname = nom; } CPlexModel::~CPlexModel() { for (size_t i=0; i::iterator it=m_zoneHorizontale.begin(); it!=m_zoneHorizontale.end(); it++) { if (it->second > colonne) it->second -= taille ; } } /** * remplissage de la matrice Z au format cplex */ void CPlexModel::setProblemData() { cpx_matbeg.resize(cpx_numcols - cpx_solvedcols); cpx_matcnt.resize(cpx_numcols - cpx_solvedcols); cpx_matind.resize(m_taille_Z - m_taille_solvedZ); cpx_matval.resize(m_taille_Z - m_taille_solvedZ); size_t deb = 0 ; for (size_t c = cpx_solvedcols; (signed)c::iterator it=m_Z[c].begin(); it!=m_Z[c].end(); it++, deb++) { cpx_matind[deb] = it->first ; cpx_matval[deb] = it->second ; } } } /** * résolution du problème par appel à cplex * @return valeur de la fonction objectif */ double CPlexModel::resolution() { // nouvelle résolution après ajout de colonnes if (env!=NULL) { return newcolumns_resolution(); } #ifndef NO_CPLEX int status = 0; /* Allocate memory and fill in the data for the problem. */ this->setProblemData (); /* 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 */ if (env == NULL) 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.*/ if (lp == NULL) lp = CPXcreateprob ( env, &status, cpx_probname.c_str() ); if ( lp == NULL ) throw CPlexFailed("Failed to create LP.", env, status); /* Now copy the problem data into the lp */ transferProblemData() ; /* Finally, write a copy of the problem to a file. */ if (m_writeToFile) { status = CPXwriteprob ( env, lp, (cpx_probname+".lp").c_str(), NULL ); if ( status ) throw CPlexFailed("Failed to write LP to disk.", env, status ); } /* 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 ); } 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; /* 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 ); cpx_vars = vector(cur_numcols,0); status = CPXgetx ( env, lp, &(cpx_vars[0]), 0, cur_numcols - 1 ); if ( status ) throw CPlexFailed("Failed to get optimal integer x_cplex.", env, status ); if (m_writeToFile) { ofstream ofs((cpx_probname+".sol").c_str()); for (size_t c=0; c(cur_numrows,0); //status = CPXgetmipslack ( env, lp, &(cpx_slack[0]), 0, cur_numrows - 1 ); //if ( status ) // throw CPlexFailed("Failed to get optimal slack values.\n" ); /* Get dual 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. */ if (cpx_problemtype == Linear) { size_t cur_numrows = CPXgetnumrows ( env, lp ); cpx_duals = vector(cur_numrows,0); status = CPXgetpi ( env, lp, &(cpx_duals[0]), 0, cur_numrows - 1 ); if ( status ) throw CPlexFailed("Failed to get cpx_duals.", env, status ); } #endif cpx_solvedcols = cpx_numcols ; m_taille_solvedZ = m_taille_Z ; /* returns the objective value */ FreeCplex(); return cpx_objval; } void CPlexModel::transferProblemData() { int status = 0 ; if (not m_with_names) status = CPXcopylp ( env, lp, cpx_numcols, cpx_numrows, cpx_objsense, &(m_coeff_objectif[0]), &(m_rhs[0]), &(m_comp[0]), &(cpx_matbeg[0]), &(cpx_matcnt[0]), &(cpx_matind[0]), &(cpx_matval[0]), &(m_min[0]), &(m_max[0]), &(m_range[0]) ); else status = CPXcopylpwnames ( env, lp, cpx_numcols, cpx_numrows, cpx_objsense, &(m_coeff_objectif[0]), &(m_rhs[0]), &(m_comp[0]), &(cpx_matbeg[0]), &(cpx_matcnt[0]), &(cpx_matind[0]), &(cpx_matval[0]), &(m_min[0]), &(m_max[0]), &(m_range[0]), &(m_noms_variables[0]), &(m_noms_contraintes[0]) ); if ( status ) throw CPlexFailed("Failed to copy problem data.", env, status ); /* Now copy the ctype array */ if (cpx_problemtype != Linear) { status = CPXcopyctype ( env, lp, &(m_type[0]) ); if ( status ) throw CPlexFailed("Failed to copy constraints types.", env, status ); } } double CPlexModel::newcolumns_resolution() { #ifndef NO_CPLEX int status = 0; /* Allocate memory and fill in the data for the problem. */ this->setProblemData (); /* Now copy the problem data into the lp */ status = CPXaddcols ( env, lp, cpx_numcols - cpx_solvedcols, m_taille_Z - m_taille_solvedZ, &(m_coeff_objectif[cpx_solvedcols]), &(cpx_matbeg[0]), &(cpx_matind[0]), &(cpx_matval[0]), &(m_min[cpx_solvedcols]), &(m_max[cpx_solvedcols]), NULL ); if ( status ) throw CPlexFailed("Failed to copy problem data.", env, status ); /* Now copy the ctype array */ if (cpx_problemtype != Linear) { vector indices; for ( int index=cpx_solvedcols; index(cur_numrows,0); //status = CPXgetmipslack ( env, lp, &(cpx_slack[0]), 0, cur_numrows - 1 ); //if ( status ) // throw CPlexFailed("Failed to get optimal slack values.\n" ); if (cpx_problemtype == Linear) { size_t cur_numrows = CPXgetnumrows ( env, lp ); cpx_duals = vector(cur_numrows,0); status = CPXgetpi ( env, lp, &(cpx_duals[0]), 0, cur_numrows - 1 ); if ( status ) throw CPlexFailed("Failed to get cpx_duals.", env, status ); } #endif cpx_solvedcols = cpx_numcols ; m_taille_solvedZ = m_taille_Z ; /* returns the objective value */ return cpx_objval; } /** * 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 */ vector CPlexModel::getResult(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 vector vars(taille); copy( cpx_vars.begin() + m_zoneHorizontale[zoneH], cpx_vars.begin() + m_zoneHorizontale[zoneH] + taille, vars.begin() ); return vars; } /// récupère la valeur des coûts réduites d'une zone horizontale std::vector CPlexModel::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 vector cr(taille); copy( cpx_cr.begin() + m_zoneHorizontale[zoneH], cpx_cr.begin() + m_zoneHorizontale[zoneH] + taille, cr.begin() ); 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 CPlexModel::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); copy( cpx_duals.begin() + m_zoneVerticale[zoneV], cpx_duals.begin() + m_zoneVerticale[zoneV] + taille, duals.begin() ); return duals; } vector< string > CPlexModel::getZones() const { vector zones; for (auto const& element : m_zoneVerticale) { zones.push_back(element.first); } return zones; } /// messages string CPlexModel::errorstring(void * env, int cpx_status) { #ifndef NO_CPLEX char m[1024]; const char * s = CPXgeterrorstring ( (CPXENVptr) env, cpx_status, m ); if (s!=NULL) return s ; #endif return ""; } string CPlexModel::statusstring(void * env, int cpx_status) { #ifndef NO_CPLEX char m[1024]; const char * s = CPXgetstatstring ( (CPXENVptr) env, cpx_status, m ); if (s!=NULL) return s ; #endif return ""; }