void Create2DArray(IloModel model, BoolVarMatrix m){ IloEnv env = model.getEnv(); for(int i = 0; i < m.getSize(); i++){ m[i]=IloBoolVarArray(env); } return; }
DataVarBoolTriMatrix::DataVarBoolTriMatrix(string name, IloEnv env,int n, int m, int K){ this->Matrix = IloArray< IloArray<IloBoolVarArray> > (env,n); for(int i = 0; i < n; i++){ this->Matrix[i] = IloArray<IloBoolVarArray>(env,m); for(int j = 0; j < m; j++){ this->Matrix[i][j] = IloBoolVarArray(env,K); for(int k = 0; k < K; k++){ string var_name = name; var_name += "("; var_name += U::to_s(i+1); var_name += ","; var_name += U::to_s(j+1); var_name += ","; var_name += U::to_s(k); var_name += ")"; this->Matrix[i][j][k] = IloBoolVar(env,var_name.c_str()); } } } this->n = n; this->m = m; this->k = K; }
/* * $v_i \in \{0, 1\}$ variables denote whether node i is active. */ static IloBoolVarArray createVarArrayVs(IloEnv env, u_int n_nodes) { IloBoolVarArray vs = IloBoolVarArray(env, n_nodes); for (u_int i = 0; i < n_nodes; i++) { vs[i] = IloBoolVar(env, Tools::indicesToString("v", i).c_str()); } return vs; }
void Create3DArray(IloModel model, BoolVar3DMatrix R, int size){ IloEnv env = model.getEnv(); for(int p = 0; p < R.getSize(); p++) R[p] = BoolVarMatrix(env, E); for(int p = 0; p < R.getSize(); p++){ for(int e = 0; e < size; e++) R[p][e]=IloBoolVarArray(env); } return; }
/* $x_{ij} \in \{0, 1\}$ variables denote whether edge (i, j) is active. */ static IloBoolVarArray createVarArrayXs(IloEnv env, vector<Instance::Edge> edges, u_int n_edges) { IloBoolVarArray xs = IloBoolVarArray(env, n_edges); for (u_int k = 0; k < n_edges; k++) { const u_int i = edges[k].v1; const u_int j = edges[k].v2; xs[k] = IloBoolVar(env, Tools::indicesToString("x", i, j).c_str()); } return xs; }
DataVarBoolMatrix::DataVarBoolMatrix(string name, IloEnv env,int n, int m){ this->Matrix = IloArray<IloBoolVarArray> (env,n); for(int i = 0; i < n; i++){ this->Matrix[i] = IloBoolVarArray(env,m); for(int j = 0; j < m; j++){ string var_name = name;//attribut à nom de la forme x(i,j) à la variable var_name += "("; var_name += U::to_s(i+1); var_name += ","; var_name += U::to_s(j+1); var_name += ")"; this->Matrix[i][j] = IloBoolVar(env,var_name.c_str()); } } this->name = name; this->n = n; this->m = m; }
void kMST_ILP::addTreeConstraints() { edges = IloBoolVarArray(env, instance.n_edges * 2); // edges in one direction and in other // "to"-edges on lower indices for (unsigned int i=0; i<instance.n_edges; i++) { edges[i] = IloBoolVar(env, Tools::indicesToString("edge " , instance.edges[i].v1, instance.edges[i].v2, instance.edges[i].weight).c_str() ); //cerr << "init: edge " << i << " from " << instance.edges[i].v1 << " to " << instance.edges[i].v2 << endl; } // edges in other direction for (unsigned int i=instance.n_edges; i<instance.n_edges*2; i++) { Instance::Edge edgeInst = instance.edges[ i % instance.n_edges ]; edges[i] = IloBoolVar(env, Tools::indicesToString("edge " , edgeInst.v2, edgeInst.v1, edgeInst.weight).c_str() ); //cerr << "init: edge " << i << " from " << instance.edges[i%instance.n_edges].v2 << " to " << instance.edges[i%instance.n_edges].v1 << endl; } // edges in one direction forbid edges in other direction for (unsigned int i=0; i<instance.n_edges; i++) { model.add( edges[i] + edges[i + instance.n_edges] <= 1 ); } // exactly k nodes, so k-1 actual edges plus one to the pseudo node 0 model.add(IloSum(edges) == k); // no 2 incoming edges per vertex for (unsigned int i=0; i < instance.n_nodes; i++ ){ IloExpr incomingSum(env); { vector<u_int> incomingEdgeIds; getIncomingEdgeIds(incomingEdgeIds, i); for (unsigned int i=0; i < incomingEdgeIds.size(); i++ ){ incomingSum += edges[incomingEdgeIds[i]]; } } model.add(incomingSum <= 1); incomingSum.end(); } // only 1 outgoing node from 0 { IloExpr outgoingSum(env); bool hasOutgoing = false; { vector<u_int> outgoingEdges; getOutgoingEdgeIds(outgoingEdges, 0); for (unsigned int i=0; i<outgoingEdges.size(); i++) { hasOutgoing = true; outgoingSum += edges[outgoingEdges[i]]; } } if (hasOutgoing) { // only true for special input files model.add(outgoingSum == 1); } outgoingSum.end(); } // no incoming to 0 { vector<u_int> incomingEdges; getIncomingEdgeIds(incomingEdges, 0); for (unsigned int i=0; i<incomingEdges.size(); i++) { model.add( edges[incomingEdges[i]] == 0) ; } } }
ILOSTLBEGIN int main (int argc, char* argv[]) { //get instance fileName: const char* fileName; if(argc>1)//we passed the filename in arg fileName=argv[1]; else fileName = "instances/instances_eleves/projet_5_8_1.dat"; //DONNEES DE L INSTANCE typedef IloArray<IloNumArray> DataMatrix; IloEnv env; instance_Cplex instance ; getData(fileName,env,instance); cout << "Données récupérées!\n"; int& n(instance.n); int& m(instance.m); try { IloModel model(env); BoolVarMatrix x(env,m); for(int i=0;i<m;i++) x[i]=IloBoolVarArray(env,n); NumVarMatrix u(env,m); for(int i=0;i<m;i++) u[i]=IloNumVarArray(env,n); NumVarMatrix v(env,m); for(int i=0;i<m;i++) v[i]=IloNumVarArray(env,n); IloRangeArray constraintSet(env); IloNumVar y(env); IloNumVar z(env); cout << "Variables créées!\n"; setdata(model,env, instance, x,u,v,y,z, constraintSet); cout << " Modèle et contraintes définies!\n"; IloCplex cplex(model); cplex.solve(); IloInt solutionUnConnex; solutionUnConnex=cplex.getObjValue(); DataMatrix xUnconnex(env,m) ; //Solution optimale non connexe for(int i=0;i<m;i++){ xUnconnex[i]=IloNumArray(env,n); cplex.getValues(xUnconnex[i], x[i]); } std::string Method ="MinimizeEdges"; //connexityTree"; if(Method=="connexityTree"){ //We solve a first time the model without the connexity constraints, to get a good max bound of the height max : the value of the solution/2, then we add the connexity constraints : IloInt hMax; if(argc>2){ // we gave the hmax in argument/ istringstream (argv[2])>>hMax; if(hMax==0) hMax=solutionUnConnex/2+1; } //else we use our upper bound else hMax=solutionUnConnex/2+1;//(n*m/2+n/2); bool useCallBack=false; if(argc>3 && *argv[3]=='1') useCallBack= true; solveTreeConnexityConstraints(cplex,model,env,instance,x,u,v,y,z,useCallBack,hMax); }
Variables *kMST_ILP::modelMCF() { MCFVariables *v = new MCFVariables(); /***** generic part ***/ const vector<Instance::Edge> edges = directed_edges(instance.edges); const u_int n_edges = edges.size(); /* $x_{ij} \in \{0, 1\}$ variables denote whether edge (i, j) is active. */ v->xs = createVarArrayXs(env, edges, n_edges); /* $v_i \in \{0, 1\}$ variables denote whether node i is active. */ v->vs = createVarArrayVs(env, instance.n_nodes); /* add objective function */ addObjectiveFunction(env, model, v->xs, edges, n_edges); /* There are exactly k - 1 edges not counting edges from the artificial root node 0. */ addConstraint_k_minus_one_active_edges(env,model,v->xs,edges,n_edges,this->k); /* Exactly one node is chosen as the tree root. */ addConstraint_one_active_outgoing_arc_for_node_zero(env,model,v->xs,edges,n_edges); /* No edge leads back to the artificial root node 0. */ addConstraint_no_active_incoming_arc_for_node_zero(env,model,v->xs,edges,n_edges); IloExprArray e_in_degree = createExprArray_in_degree(env, edges, n_edges, v->xs, instance); IloExprArray e_out_degree = createExprArray_out_degree(env, edges, n_edges, v->xs, instance); /* Inactive nodes have no outgoing active edges, active ones at most k - 1. TODO: A tighter bound is to take the sum of incoming goods - 1.*/ addConstraint_bound_on_outgoing_arcs(model,v->vs,e_out_degree,instance,this->k); /* Active nodes have at least one active arc.*/ addConstraint_active_node_at_least_one_active_arc(model,v->vs,e_in_degree, e_out_degree,instance); /* Exactly one incoming edge for an active node and none for an inactive node (omitting artificial root). */ addConstraint_in_degree_one_for_active_node_zero_for_inactive(model,v->vs,e_in_degree,instance); //note: position matters. Tried worse positions than this one /* $\sum_{i > 0} v_i = k$. Ensure that exactly k nodes are active. */ addConstraint_k_nodes_active(env, model, v->vs, instance, this->k); e_in_degree.endElements(); e_out_degree.endElements(); /***** MCF specific part ***/ /* $f^k_{ij} \in \{0, 1\}$ variables denote the flow on edge (i, j) for commodity k. */ for (u_int i = 0; i < instance.n_nodes; i++) { v->fss.push_back(IloBoolVarArray(env, n_edges)); } for (u_int k = 0; k < n_edges; k++) { const u_int i = edges[k].v1; const u_int j = edges[k].v2; for (u_int l = 0; l < (u_int) instance.n_nodes; l++) { v->fss[l][k] = IloBoolVar(env, Tools::indicesToString("f", l, i, j).c_str()); } } /* * Each commodity l is generated once by the artificial root node if node l is active, not at all otherwise: * $\forall l \in \{1, \ldots, n\}: \sum_{j:j>0,(0,j) \in A} f^l_{0j} == v_l$ */ for (u_int c = 1; c < instance.n_nodes; c++){ IloExpr e_one_commodity(env); for (u_int m = 0; m < n_edges; m++) { const u_int i = edges[m].v1; const u_int j = edges[m].v2; if (i == 0 && j > 0){ e_one_commodity += v->fss[c][m]; } } model.add(e_one_commodity == v->vs[c]); e_one_commodity.end(); } /* * The artifical root generates k commodities: * $\forall l \in \{0,\ldots,n\}\sum_{j:j>0,(0,j) \in A} f^l_{0j} = k$. */ IloExpr e_root_generates_k(env); for (u_int c = 0; c < instance.n_nodes; c++){ for (u_int m = 0; m < n_edges; m++) { const u_int i = edges[m].v1; const u_int j = edges[m].v2; if (i == 0 && j > 0){ e_root_generates_k += v->fss[c][m]; } } } model.add(e_root_generates_k == this->k); e_root_generates_k.end(); /* * No commodity is generated for the artificial root: * $\forall i, j: f^0_{ij} = 0$. */ for (u_int m = 0; m < n_edges; m++) { model.add(v->fss[0][m] == 0); } /* * Transmitted commodities end up at the target node: * $\forall l>0: \sum_i f^l_{il} = \sum_j f^l_{0j}$. (here: = v_l) */ for (u_int c = 1; c < (u_int) instance.n_nodes; c++){ IloExpr e_commodity_reaches_target(env); for (u_int m = 0; m < n_edges; m++) { const u_int i = edges[m].v1; const u_int j = edges[m].v2; if (i != c && j == c){ e_commodity_reaches_target += v->fss[c][m]; } } model.add(e_commodity_reaches_target == v->vs[c]); e_commodity_reaches_target.end(); } /* * Once reached, the commodity never leaves the target node: * $\forall l>0: \sum_j f^l_{lj} = 0$. */ for (u_int c = 1; c < (u_int) instance.n_nodes; c++){ IloExpr e_commodity_stays_at_target(env); for (u_int m = 0; m < n_edges; m++) { const u_int i = edges[m].v1; const u_int j = edges[m].v2; if (i == c && j != c){ e_commodity_stays_at_target += v->fss[c][m]; } } model.add(e_commodity_stays_at_target == 0); e_commodity_stays_at_target.end(); } /* * Flow is conserved when not at target node. * $\forall j, l s.t. j \neq l: \sum_i f^l_{ij} = \sum_i f^l_{ji}$. */ for (u_int c = 0; c < (u_int) instance.n_nodes; c++){ IloExprArray e_in_flow(env, instance.n_nodes); IloExprArray e_out_flow(env, instance.n_nodes); for (u_int m = 0; m < instance.n_nodes; m++){ e_in_flow[m] = IloExpr(env); e_out_flow[m] = IloExpr(env); } for (u_int m = 0; m < n_edges; m++) { const u_int i = edges[m].v1; const u_int j = edges[m].v2; e_out_flow[i] += v->fss[c][m]; e_in_flow[j] += v->fss[c][m]; } for (u_int m = 1; m < instance.n_nodes; m++){ if (m != c) { model.add(e_in_flow[m] == e_out_flow[m]); } } e_in_flow.endElements(); e_out_flow.endElements(); } /* * Commodities may only be transmitted on active edges: * $\forall l, i, j: f^l_{ij} \leq x_{ij}$. */ for (u_int c = 0; c < (u_int) instance.n_nodes; c++){ for (u_int m = 0; m < n_edges; m++) { model.add(v->fss[c][m] <= v->xs[m]); } } /* * For each commodity l , the total flow is <= k if node l is active, 0 otherwise * (works well for all before g05, k=n/2 which is a bit slower with this) */ for (u_int c = 1; c < (u_int) instance.n_nodes; c++){ IloExpr e_total_flow(env); for (u_int m = 0; m < n_edges; m++) { e_total_flow += v->fss[c][m]; } model.add(e_total_flow <= this->k * v->vs[c]); e_total_flow.end(); } return v; }