int setCplexParam(IloCplex& cplex, IloEnv& env, int time_limit){ //Set cplex parameter cplex.setParam(IloCplex::TiLim, time_limit); cplex.setParam(IloCplex::Threads, 2); cplex.setOut(env.getNullStream()); cplex.setParam(IloCplex::PreLinear, 0); return 0; }
// This routine set up the IloCplex algorithm to solve the worker LP, and // creates the worker LP (i.e., the dual of flow constraints and // capacity constraints of the flow MILP) // // Modeling variables: // forall k in V0, i in V: // u(k,i) = dual variable associated with flow constraint (k,i) // // forall k in V0, forall (i,j) in A: // v(k,i,j) = dual variable associated with capacity constraint (k,i,j) // // Objective: // minimize sum(k in V0) sum((i,j) in A) x(i,j) * v(k,i,j) // - sum(k in V0) u(k,0) + sum(k in V0) u(k,k) // // Constraints: // forall k in V0, forall (i,j) in A: u(k,i) - u(k,j) <= v(k,i,j) // // Nonnegativity on variables v(k,i,j) // forall k in V0, forall (i,j) in A: v(k,i,j) >= 0 // void createWorkerLP(IloCplex cplex, IloNumVarArray v, IloNumVarArray u, IloObjective obj, IloInt numNodes) { IloInt i, j, k; IloEnv env = cplex.getEnv(); IloModel mod(env, "atsp_worker"); // Set up IloCplex algorithm to solve the worker LP cplex.extract(mod); cplex.setOut(env.getNullStream()); // Turn off the presolve reductions and set the CPLEX optimizer // to solve the worker LP with primal simplex method. cplex.setParam(IloCplex::Reduce, 0); cplex.setParam(IloCplex::RootAlg, IloCplex::Primal); // Create variables v(k,i,j) forall k in V0, (i,j) in A // For simplicity, also dummy variables v(k,i,i) are created. // Those variables are fixed to 0 and do not partecipate to // the constraints. IloInt numArcs = numNodes * numNodes; IloInt vNumVars = (numNodes-1) * numArcs; IloNumVarArray vTemp(env, vNumVars, 0, IloInfinity); for (k = 1; k < numNodes; ++k) { for (i = 0; i < numNodes; ++i) { vTemp[(k-1)*numArcs + i *numNodes + i].setBounds(0, 0); } } v.clear(); v.add(vTemp); vTemp.end(); mod.add(v); // Set names for variables v(k,i,j) for (k = 1; k < numNodes; ++k) { for(i = 0; i < numNodes; ++i) { for(j = 0; j < numNodes; ++j) { char varName[100]; sprintf(varName, "v.%d.%d.%d", (int) k, (int) i, (int) j); v[(k-1)*numArcs + i*numNodes + j].setName(varName); } } } // Associate indices to variables v(k,i,j) IloIntArray vIndex(env, vNumVars); for (j = 0; j < vNumVars; ++j) { vIndex[j] = j; v[j].setObject(&vIndex[j]); } // Create variables u(k,i) forall k in V0, i in V IloInt uNumVars = (numNodes-1) * numNodes; IloNumVarArray uTemp(env, uNumVars, -IloInfinity, IloInfinity); u.clear(); u.add(uTemp); uTemp.end(); mod.add(u); // Set names for variables u(k,i) for (k = 1; k < numNodes; ++k) { for(i = 0; i < numNodes; ++i) { char varName[100]; sprintf(varName, "u.%d.%d", (int) k, (int) i); u[(k-1)*numNodes + i].setName(varName); } } // Associate indices to variables u(k,i) IloIntArray uIndex(env, uNumVars); for (j = 0; j < uNumVars; ++j) { uIndex[j] = vNumVars + j; u[j].setObject(&uIndex[j]); } // Initial objective function is empty obj.setSense(IloObjective::Minimize); mod.add(obj); // Add constraints: // forall k in V0, forall (i,j) in A: u(k,i) - u(k,j) <= v(k,i,j) for (k = 1; k < numNodes; ++k) { for(i = 0; i < numNodes; ++i) { for(j = 0; j < numNodes; ++j) { if ( i != j ) { IloExpr expr(env); expr -= v[(k-1)*numArcs + i*(numNodes) + j]; expr += u[(k-1)*numNodes + i]; expr -= u[(k-1)*numNodes + j]; mod.add(expr <= 0); expr.end(); } } } } }// END createWorkerLP
/** Create a new worker. * The constructor mainly does the following: * - create an IloCplex instance that refers to a remote worker, * - load the model in <code>modelfile</code>, * - setup parameters depending on this worker's index, * - start an asynchronous solve. * If anything fails then an exception will be thrown. * @param env The environment used for instantiating Ilo* objects. * @param i The index of the worker to be created. This also * determines the parameter settings to use in this worker. * @param s A pointer to the global solve state. * @param transport The transport name for the IloCplex constructor. * @param argc The argument count for the IloCplex constructor. * @param argv The array of transport arguments for the IloCplex * constructor. * @param modelfile Name of the model to be loaded into the worker. * @param output The output mode. * @param objdiff The minimal difference between so that two * consecutive objective function values are considered * different. */ Worker(IloEnv env, int i, SolveState *s, char const *transport, int argc, char const **argv, char const *modelfile, OUTPUT output, double objdiff) : idx(i), state(s), model(env), cplex(0), handle(0), primal(IloInfinity), dual(-IloInfinity), obj(env), x(env), rng(env), infoHandler(this), outb(idx), outs(&outb) { try { // Create remote object, setup output and load the model. cplex = IloCplex(model, transport, argc, argv); switch (output) { case OUTPUT_SILENT: // Disable output on the output and warning stream. cplex.setOut(env.getNullStream()); cplex.setWarning(env.getNullStream()); break; case OUTPUT_PREFIXED: // Redirect output to our custom stream. cplex.setOut(outs); cplex.setWarning(outs); break; case OUTPUT_LOG: // Nothing to do here. By default output is enabled. break; } cplex.importModel(model, modelfile, obj, x, rng); if ( obj.getSense() == IloObjective::Minimize ) { primal = -IloInfinity; dual = IloInfinity; } // We set the thread count for each solver to 1 so that we do not // run into problems if multiple solves are performed on the same // machine. cplex.setParam(IloCplex::Param::Threads, 1); // Each worker runs with a different random seed. This way we // get different paths through the tree even if the other // parameter settings are the same. cplex.setParam(IloCplex::Param::RandomSeed, idx); // Apply parameter settings. for (class ParamValue const *vals = settings[idx % NUMSETTINGS].values; vals->isValid(); ++vals) vals->apply(cplex); // Install callback and set objective change. int status = cplex.userfunction (USERACTION_ADDCALLBACK, 0, NULL, 0, 0, NULL); if ( status ) throw status; IloCplex::Serializer s; s.add(objdiff); status = cplex.userfunction (USERACTION_CHANGEOBJDIFF, s.getRawLength(), s.getRawData(), 0, 0, NULL); if ( status ) throw status; // Register the handler that will process info messages sent // from the worker. cplex.setRemoteInfoHandler(&infoHandler); // Everything is setup. Launch the asynchronous solve. handle = cplex.solve(true); } catch (...) { // In case of an exception we need to take some special // cleanup actions. Note that if we get here then the // solve cannot have been started and we don't need to // kill or join the asynchronous solve. if ( cplex.getImpl() ) cplex.end(); rng.end(); x.end(); obj.end(); model.end(); throw; } }