int main (int argc, char **argv) { char const *vmconfig = NULL; // Check command line length (exactly two arguments are required). if ( argc != 3 ) { usage (argv[0]); return -1; } // Pick up VMC from command line. vmconfig = argv[1]; // Solve the model. int exitcode = 0; IloEnv env; try { // Create and read the model. IloModel model(env); IloCplex cplex(model); IloObjective obj; IloNumVarArray var(env); IloRangeArray rng(env); IloSOS1Array sos1(env); IloSOS2Array sos2(env); IloRangeArray lazy(env); IloRangeArray cuts(env); cplex.importModel(model, argv[2], obj, var, rng, sos1, sos2, lazy, cuts); cplex.extract(model); if ( lazy.getSize() > 0 ) cplex.addLazyConstraints (lazy); if ( cuts.getSize() > 0 ) cplex.addUserCuts (cuts); // Load the virtual machine configuration. // This will force solve() to use parallel distributed MIP. cplex.readVMConfig(vmconfig); // Install logging info callback. IloNum lastObjVal = (obj.getSense() == IloObjective::Minimize ) ? IloInfinity : -IloInfinity; cplex.use(loggingCallback(env, var, -100000, lastObjVal, cplex.getCplexTime(), cplex.getDetTime())); // Turn off CPLEX logging cplex.setParam(IloCplex::Param::MIP::Display, 0); // Solve the problem and display some results. if ( cplex.solve() ) env.out() << "Solution value = " << cplex.getObjValue() << endl; else env.out() << "No solution" << endl; env.out() << "Solution status = " << cplex.getStatus() << endl; // Cleanup. cplex.end(); model.end(); } catch (IloException& e) { cerr << "Concert exception caught: " << e << endl; exitcode = -1; } catch (...) { cerr << "Unknown exception caught" << endl; exitcode = -1; } env.end(); return exitcode; } // END main
/** Create the dual of a linear program. * The function can only dualize programs of the form * <code>Ax <= b, x >= 0</code>. The data in <code>primalVars</code> and * <code>dualRows</code> as well as in <code>primalRows</code> and * <code>dualVars</code> is in 1-to-1-correspondence. * @param primalObj Objective function of primal problem. * @param primalVars Variables in primal problem. * @param primalRows Rows in primal problem. * @param dualObj Objective function of dual will be stored here. * @param dualVars All dual variables will be stored here. * @param dualRows All dual rows will be stored here. */ void BendersOpt::makeDual(IloObjective const &primalObj, IloNumVarArray const &primalVars, IloRangeArray const &primalRows, IloObjective *dualObj, IloNumVarArray *dualVars, IloRangeArray *dualRows) { // To keep the code simple we only support problems // of the form Ax <= b, b >= 0 here. We leave it as a reader's // exercise to extend the function to something that can handle // any kind of linear model. for (IloInt j = 0; j < primalVars.getSize(); ++j) if ( primalVars[j].getLB() != 0 || primalVars[j].getUB() < IloInfinity ) { std::stringstream s; s << "Cannot dualize variable " << primalVars[j]; throw s.str(); } for (IloInt i = 0; i < primalRows.getSize(); ++i) if ( primalRows[i].getLB() > -IloInfinity || primalRows[i].getUB() >= IloInfinity ) { std::stringstream s; s << "Cannot dualize constraint " << primalRows[i]; std::cerr << s.str() << std::endl; throw s.str(); } // The dual of // min/max c^T x // Ax <= b // x >= 0 // is // max/min y^T b // y^T A <= c // y <= 0 // We scale y by -1 to get >= 0 IloEnv env = primalVars.getEnv(); IloObjective obj(env, 0.0, primalObj.getSense() == IloObjective::Minimize ? IloObjective::Maximize : IloObjective::Minimize); IloRangeArray rows(env); IloNumVarArray y(env); std::map<IloNumVar,IloInt,ExtractableLess<IloNumVar> > v2i; for (IloInt j = 0; j < primalVars.getSize(); ++j) { IloNumVar x = primalVars[j]; v2i.insert(std::map<IloNumVar,IloInt,ExtractableLess<IloNumVar> >::value_type(x, j)); rows.add(IloRange(env, -IloInfinity, 0, x.getName())); } for (IloExpr::LinearIterator it = primalObj.getLinearIterator(); it.ok(); ++it) rows[v2i[it.getVar()]].setUB(it.getCoef()); for (IloInt i = 0; i < primalRows.getSize(); ++i) { IloRange r = primalRows[i]; IloNumColumn col(env); col += obj(-r.getUB()); for (IloExpr::LinearIterator it = r.getLinearIterator(); it.ok(); ++it) col += rows[v2i[it.getVar()]](-it.getCoef()); y.add(IloNumVar(col, 0, IloInfinity, IloNumVar::Float, r.getName())); } *dualObj = obj; *dualVars = y; *dualRows = rows; }
/** Get the objective sense for this worker's objective. */ IloObjective::Sense getObjectiveSense() const { return obj.getSense(); }
int main (int argc, char **argv) { IloEnv env; try { IloModel model(env); IloCplex cplex(env); IloBool useLoggingCallback = IloFalse; IloBool useTimeLimitCallback = IloFalse; IloBool useAborter = IloFalse; if (( argc != 3 ) || ( strchr ("lat", argv[2][0]) == NULL ) ) { usage (argv[0]); throw(-1); } switch (argv[2][0]) { case 'l': useLoggingCallback = IloTrue; break; case 't': useTimeLimitCallback = IloTrue; break; case 'a': useAborter = IloTrue; break; default: break; } IloObjective obj; IloNumVarArray var(env); IloRangeArray rng(env); IloSOS1Array sos1(env); IloSOS2Array sos2(env); IloRangeArray lazy(env); IloRangeArray cuts(env); IloCplex::Aborter myAborter; cplex.importModel(model, argv[1], obj, var, rng, sos1, sos2, lazy, cuts); cplex.extract(model); if ( lazy.getSize() > 0 ) cplex.addLazyConstraints (lazy); if ( cuts.getSize() > 0 ) cplex.addUserCuts (cuts); if ( useLoggingCallback ) { // Set an overall node limit in case callback conditions // are not met. cplex.setParam(IloCplex::Param::MIP::Limits::Nodes, 5000); IloNum lastObjVal = (obj.getSense() == IloObjective::Minimize ) ? IloInfinity : -IloInfinity; cplex.use(loggingCallback(env, var, -100000, lastObjVal, cplex.getCplexTime(), cplex.getDetTime())); // Turn off CPLEX logging cplex.setParam(IloCplex::Param::MIP::Display, 0); } else if ( useTimeLimitCallback ) { cplex.use(timeLimitCallback(env, cplex, IloFalse, cplex.getCplexTime(), 1.0, 10.0)); } else if ( useAborter ) { myAborter = IloCplex::Aborter(env); cplex.use(myAborter); // Typically, you would pass the Aborter object to // another thread or pass it to an interrupt handler, // and monitor for some event to occur. When it does, // call the Aborter's abort method. // // To illustrate its use without creating a thread or // an interrupt handler, abort immediately by calling // abort before the solve. // myAborter.abort(); } cplex.solve(); env.out() << endl; env.out() << "Solution status = " << cplex.getStatus() << endl; env.out() << "CPLEX status = " << cplex.getCplexStatus() << endl; } catch (IloException& e) { cerr << "Concert exception caught: " << e << endl; } catch (...) { cerr << "Unknown exception caught" << endl; } env.end(); return 0; } // END main
/** 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; } }