J'essaie de résoudre un modèle LP dans CPLEX en utilisant C++ et Concert Technology. Je souhaite implémenter des contraintes (les contraintes d'élimination de sous -tours, pour être plus spécifiques) qui doivent interroger la valeur de deux de mes variables dans la solution actuelle: La variable array xvar indique les arêtes, yvar représente le nœuds. J'implémente ces contraintes en résolvant n (= nombre de nœuds) Min-Cut-Problems sur un graphe modifié, qui est construit en ajoutant une source artificielle et un puits artificiel et les relie à chaque nœud du graphe original. D'après ce que j'ai lu jusqu'à présent, ai-je besoin d'une contrainte paresseuse ou d'un rappel ou rien de tout cela?C++ cplex d'accès solution actuelle pour ajouter une contrainte
C'est là que je crée le modèle et l'obtenir résolu, accéder aux valeurs des variables dans la solution etc:
// Step 2: Construct the necessary CPLEX objects and the LP model
IloCplex solver(env);
std::cout<< "Original Graph g: " <<std::endl;
std::cout<< net.g() <<std::endl;
MCFModel model(env, net);
// Step 3: Load the model into cplex and solve
solver.extract(model);
solver.solve();
// Step 4: Extract the solution from the solver
if(solver.getStatus() != IloAlgorithm::Optimal) throw "Could not solve to optimality!";
IloNumArray xsol (env, net.g().nEdges());
IloNumArray ysol (env, net.g().nNodes());
IloNumArray rsol (env, net.g().nGroups());
IloNumArray wisol (env, net.g().nGroups());
IloNum ksol;
NumMatrix wsol (env, net.g().nGroups());
for(IloInt i = 0; i < net.g().nGroups(); i++){
wsol[i] = IloNumArray(env, net.g().nGroups());
}
solver.getValues(xsol, model.xvar());
solver.getValues(ysol, model.yvar());
solver.getValues(rsol, model.rvar());
solver.getValues(wisol, model.wivar());
ksol=solver.getValue(model.kvar());
for (IloInt i = 0; i < net.g().nGroups(); i++){
wsol[i] = wisol;
}
// Step 5: Print the solution.
La contrainte, j'ai besoin les valeurs actuelles des variables XVAR et Yvar pour, est créé ici:
//build subset constraint y(S) -x(E(S))>= y_i
void MCFModel::buildSubsetCons(){
IloExpr lhs(m_env);
IloCplex cplex(m_env);
IloNumArray xtemp (m_env, m_net.g().nEdges());
IloNumArray ytemp (m_env, m_net.g().nNodes());
std::vector<Edge> mg_twin;
std::vector<int> mg_weights;
int mg_s;
int mg_t;
SGraph mgraph;
std::vector<int> f;
int nOrigEdges = m_net.g().nEdges();
int nOrigNodes = m_net.g().nNodes();
cplex.getValues(xtemp, m_xvar);
cplex.getValues(ytemp, m_yvar);
mgraph = m_net.g().mod_graph();
mg_s = mgraph.nNodes()-1;
mg_t = mgraph.nNodes();
std::cout<<"modified graph:"<<std::endl;
std::cout<<mgraph<<std::endl;
// fill the weight of original edges with 1/2*x_e
foreach_edge(e, m_net.g()){
mg_weights.push_back((xtemp[e->idx()])/2);
}
// fill the weight of the edges from artificial source with zero
for(int i=0; i<m_net.g().nNodes(); i++){
mg_weights.push_back(0);
}
// fill the weight of the edges to artificial sink with f(i)
// first step: calculate f(i):
//f.resize(m_net.g().nNodes());
foreach_node(i, m_net.g()){
foreach_adj_edge(e, i, m_net.g()){
f[i] = f[i] + xtemp[e->idx()];
}
f[i] = (-1)*f[i]/2;
f[i] = f[i] + ytemp[i];
}
// second step: fill the weights vector with it
for(int i=0; i<m_net.g().nNodes(); i++){
mg_weights.push_back(f[i]);
}
// calculate the big M = abs(sum_(i in N) f(i))
int M;
foreach_node(i, m_net.g()){
M = M + abs(f[i]);
}
// Build the twin vector of the not artificial edges for mgraph
mg_twin.resize(2*nOrigEdges + 2*nOrigNodes);
for(int i=0; i < nOrigEdges ; ++i){
mg_twin[i] = mgraph.edges()[nOrigEdges + i];
mg_twin[nOrigEdges + i] = mgraph.edges()[i];
}
//Start the PreflowPush for every node in the original graph
foreach_node(v, m_net.g()){
// "contract" the edge between s and v
// this equals to higher the weights of the edge (s,v) to a big value M
// weight of the edge from v to s lies in mg_weights[edges of original graph + index of node v]
mg_weights[m_net.g().nEdges() + v] = M;
//Start PreflowPush for v
PreflowPush<int> pp(mgraph, mg_twin, mg_weights, mg_s, mg_t);
std::cout << "Flowvalue modified graph: " << pp.minCut() << std::endl;
}
}
pp objet est de résoudre le Min-Cut-problème sur le graphique modifié MGraph avec une source artificielle et un évier. Le graphique d'origine est dans m_net.g().
Quand je compile et exécute, je reçois l'erreur suivante:
terminate called after throwing an instance of 'IloCplex::Exception'
Aborted
Il me semble qu'il est impossible d'accéder aux valeurs de XVAR et Yvar comme ça? J'apprécie n'importe quelle aide puisque je suis tout à fait perdu comment faire ceci. Merci beaucoup !!
Je l'ai en fait avec un Lazyconstraintcallback et un Usercutcallback, Obe peut simplement accéder aux valeurs actuelles d'une solution via getValue()/getValues () dans le rappel! Et merci beaucoup pour votre indice avec le .end() pour le conteneur coupé, j'avais des problèmes de mémoire avant! :-) – cplexstudent
J'ai implémenté lazyconstraint- et usercutcallback et j'ai commencé à tester certains exemples générés aléatoirement. Il y a un exemple qui ne se termine pas, il me semble qu'il est bloqué dans une boucle infinie car à un certain point le nombre d'itérations n'augmente plus et il y a toujours les mêmes inégalités violées qui sont trouvées par usercutcallback. Tous mes objets IloNumVarArrays sont déclarés en tant que nombres entiers, mais lorsque j'arrête le processus d'optimisation dans la boucle infinie, il y a des entrées des tableaux qui sont fractionnaires et non entières. Est-ce seulement possible? – cplexstudent
Vous devez placer un point d'arrêt dans le rappel et vous assurer que TOUT est fait comme prévu. Est très facile de mettre un mauvais itérateur (vous pourriez prendre position avant/après), ou d'oublier quelque chose. Il y a tellement de place pour l'erreur ... Et tout ce qui est là-dedans fera que CPLEX deviendra fou et fera toutes sortes de trucs insensés. – Jacko