2016-10-14 1 views
1

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 !!

Répondre

0

Deux choses ...

I. Je vous suggère fortement d'utiliser un try-catch pour mieux comprendre les exceptions CPLEX. Vous pourriez peut-être comprendre la nature de l'exception comme ceci. En fait, je vous suggère un réglage try-catch-catch, en quelque sorte:

try { 
//... YOUR CODE ...// 
} 
catch(IloException& e) { 
    cerr << "CPLEX found the following exception: " << e << endl; 
    e.end(); 
} 
catch(...) { 
    cerr << "The following unknown exception was found: " << endl; 
} 

II. La seule façon d'interagir avec CPLEX pendant le processus d'optimisation est via un rappel, et, dans le cas des contraintes d'élimination de sous-site (SECs), vous devrez séparer les SEC entiers et fractionnaires.

II.1 ENTIER: Le premier est le plus facile, une routine O(n) pourrait vous aider à identifier tous les composants connectés d'une solution de noeud, vous pouvez ajouter les coupes suivantes pour éviter ce SEC particulier d'apparaître dans autres noeuds Vous pouvez appliquer vos coupes localement, c'est-à-dire uniquement sur le sous-arbre actuel, en utilisant la fonction addLocal(), ou globalement, c'est-à-dire sur l'arborescence Branche et coupe entière, en utilisant la fonction add(). Dans tous les cas, n'oubliez pas d'ajouter .end() pour terminer le récipient coupé. Sinon, vous aurez de graves problèmes de fuite de mémoire, faites-moi confiance avec ça, lol. Ce rappel doit être un fait par un rappel Constraint Lazy (ILOLAZYCONSTRAINTCALLBACK)

II.2 FRACTIONNEL: Le second est de loin plus complexe. Le moyen le plus simple de le faire fonctionner est d'utiliser la bibliothèque CVRPSEP du professeur Lysgaard.C'est aujourd'hui le moyen le plus efficace de calculer les réductions de capacité, les multistar, les multistar généralisés, les capacités encadrées, les coupes renforcées en peigne et hypotour. De plus, il est plutôt facile de lier avec un code existant. Le lien doit également être intégré dans le processus de la solution, par conséquent, un rappel est également requis. Dans ce cas, il s'agit d'un rappel de coupure utilisateur (ILOUSERCUTCALLBACK).

On est heureux d'être de service Y

+0

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

+0

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

+0

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