ILOHEURISTICCALLBACK1(Rounddown, IloNumVarArray, vars) { IntegerFeasibilityArray feas; IloNumArray obj; IloNumArray x; try { feas = IntegerFeasibilityArray(getEnv()); obj = IloNumArray(getEnv()); x = IloNumArray(getEnv()); getFeasibilities(feas, vars); getObjCoefs (obj , vars); getValues (x , vars); IloNum objval = getObjValue(); IloInt cols = vars.getSize(); for (IloInt j = 0; j < cols; j++) { // Set the fractional variable to zero and update the objective value if ( feas[j] == Infeasible ) { objval -= x[j] * obj[j]; x[j] = 0.0; } } setSolution(vars, x, objval); } catch (...) { feas.end(); obj.end(); x.end(); throw; } feas.end(); obj.end(); x.end(); }
ILOBRANCHCALLBACK1(MyBranch, IloNumVarArray, vars) { if ( getBranchType() != BranchOnVariable ) return; // Branch on var with largest objective coefficient // among those with largest infeasibility IloNumArray x; IloNumArray obj; IntegerFeasibilityArray feas; try { x = IloNumArray(getEnv()); obj = IloNumArray(getEnv()); feas = IntegerFeasibilityArray(getEnv()); getValues(x, vars); getObjCoefs(obj, vars); getFeasibilities(feas, vars); IloInt bestj = -1; IloNum maxinf = 0.0; IloNum maxobj = 0.0; IloInt cols = vars.getSize(); for (IloInt j = 0; j < cols; j++) { if ( feas[j] == Infeasible ) { IloNum xj_inf = x[j] - IloFloor (x[j]); if ( xj_inf > 0.5 ) xj_inf = 1.0 - xj_inf; if ( xj_inf >= maxinf && (xj_inf > maxinf || IloAbs (obj[j]) >= maxobj) ) { bestj = j; maxinf = xj_inf; maxobj = IloAbs (obj[j]); } } } if ( bestj >= 0 ) { makeBranch(vars[bestj], x[bestj], IloCplex::BranchUp, getObjValue()); makeBranch(vars[bestj], x[bestj], IloCplex::BranchDown, getObjValue()); } } catch (...) { x.end(); obj.end(); feas.end(); throw; } x.end(); obj.end(); feas.end(); }
ILOCPLEXGOAL1(MyBranchGoal, IloNumVarArray, vars) { IloNumArray x; IloNumArray obj; IntegerFeasibilityArray feas; x = IloNumArray(getEnv()); obj = IloNumArray(getEnv()); feas = IntegerFeasibilityArray(getEnv()); getValues(x, vars); getObjCoefs(obj, vars); getFeasibilities(feas, vars); IloInt bestj = -1; IloNum maxinf = 0.0; IloNum maxobj = 0.0; IloInt cols = vars.getSize(); for (IloInt j = 0; j < cols; j++) { if ( feas[j] == Infeasible ) { IloNum xj_inf = x[j] - IloFloor (x[j]); if ( xj_inf > 0.5 ) xj_inf = 1.0 - xj_inf; if ( xj_inf >= maxinf && (xj_inf > maxinf || IloAbs (obj[j]) >= maxobj) ) { bestj = j; maxinf = xj_inf; maxobj = IloAbs (obj[j]); } } } IloCplex::Goal res; if ( bestj >= 0 ) { res = AndGoal(OrGoal(vars[bestj] >= IloFloor(x[bestj])+1, vars[bestj] <= IloFloor(x[bestj])), this); } x.end(); obj.end(); feas.end(); return res; }
int main(int argc, char **argv) { char const *modelfile = NULL; int jobs = 0; char const **machine = 0; #if defined(USE_MPI) int numprocs, rank; // Initialize MPI. // We must have at least three processors (master and 2 workers) and // the master must have rank 0. MPI_Init(&argc, &argv); MPI_Comm_size (MPI_COMM_WORLD, &numprocs); if ( numprocs < 3 ) { fprintf (stderr, "Invalid number of processors (%d)\n", numprocs); abort (); } MPI_Comm_rank (MPI_COMM_WORLD, &rank); if ( rank != 0 ) { fprintf (stderr, "Master must have rank 0!\n"); MPI_Finalize (); abort (); } machine = new char const*[numprocs]; for (int i = 0; i < numprocs; ++i) machine[i] = "mpimachine"; jobs = numprocs - 1; #elif defined(USE_PROCESS) // The default binary is CPLEX but that can be overwritten // by command line arguments. char const *bin = "cplex"; machine = new char const *[argc]; #elif defined(USE_TCPIP) machine = new char const *[argc]; #else # error "No transport type selected" #endif // Parse the command line. Worker::OUTPUT output = Worker::OUTPUT_SILENT; double absgap = 1e-6; for (int i = 1; i < argc; ++i) { if ( strncmp (argv[i], "-model=", 7) == 0 ) modelfile = argv[i] + 7; #if defined(USE_MPI) // no MPI specific commands supported #elif defined(USE_PROCESS) // For process transport // - machine=<command> specifies the name of a machine to which // we connect (via ssh) // -bin=<binary> specifies the binary to execute (default is "cplex") else if ( strncmp (argv[i], "-machine=", 9) == 0 ) machine[jobs++] = argv[i] + 9; else if ( strncmp (argv[i], "-bin=", 5) == 0 ) bin = argv[i] + 5; #elif defined(USE_TCPIP) // For TCP/IP process // -address=<host>:<port> specifies a worker address to which to // connect else if ( strncmp (argv[i], "-address=", 9) == 0 ) machine[jobs++] = argv[i]; #endif // Further arguments // -absgap=<gap> stop if that absolute gap is reached // -output-prefixed prefix all worker output by the worker number // -output-log output worker log messages else if ( strncmp (argv[i], "-absgap=", 8) == 0 ) absgap = strtod (argv[i] + 8, NULL); else if ( strcmp (argv[i], "-output-prefixed") == 0 ) output = Worker::OUTPUT_PREFIXED; else if ( strcmp (argv[i], "-output-log") == 0 ) output = Worker::OUTPUT_LOG; } // Validate arguments. if ( !modelfile ) throw "No model file specified with -model=<modelfile>"; if ( jobs < 1 ) throw "Invalid job count"; // Find the place at which to find the shared object that implements // the user function. On Windows the path to the current directory is // likely to contain blanks, so better quote it. char cwd[MAX_PATH_LEN]; char usrfunc[MAX_PATH_LEN]; getcwd (cwd, sizeof (cwd)); usrfunc[0] = 0; #ifdef _WIN32 strcat (usrfunc, "-libpath=\""); strcat (usrfunc, cwd); strcat (usrfunc, "\""); #else strcat (usrfunc, "-libpath="); strcat (usrfunc, cwd); #endif IloEnv env; SolveState state; // Initialize the workers. // The main thing to do here is to set up the connection arguments // for the IloCplex constructor. Once we have them we just instantiate // the Worker class. The constructor for this class will also start // an asynchronous solve immediately. Worker **workers = new Worker*[jobs]; for (int i = 0; i < jobs; ++i) { char const *transport = 0; char const *args[16]; int nextarg = 0; #if defined(USE_MPI) char rankbuf[256]; sprintf (rankbuf, "-remoterank=%d", i + 1); transport = "mpitransport"; args[nextarg++] = rankbuf; #elif defined(USE_PROCESS) char logbuf[1024]; transport = "processtransport"; // If the machine is not "localhost" then use ssh to connect to // this machine. Otherwise just fork a process on the local // machine. if ( machine[i] != NULL && strcmp (machine[i], "localhost") != 0 ) { args[nextarg++] = "/usr/bin/ssh"; args[nextarg++] = machine[i]; } args[nextarg++] = bin; args[nextarg++] = "-worker=process"; if ( machine[i] != NULL ) args[nextarg++] = "-stdio"; else args[nextarg++] = "-namedpipes=."; args[nextarg++] = usrfunc; args[nextarg++] = "-userfunction=iloparmipopt_userfunction=REGISTER_USERFUNCTION"; sprintf (logbuf, "-logfile=server%d.log", i); args[nextarg++] = logbuf; #elif defined(USE_TCPIP) transport = "tcpiptransport"; args[nextarg++] = machine[i]; #endif std::cout << "Initializing worker for " << machine[i] << std::endl; try { workers[i] = new Worker(env, i, &state, transport, nextarg, args, modelfile, output, 1e-5); } catch (...) { while (--i >= 0) delete workers[i]; delete[] workers; throw; } } delete[] machine; try { // At this point all workers have been started and are // solving the problem. We just wait until either the first // worker has finished or if the best known global primal and dual // bounds are close enough. IloObjective::Sense const objsen = workers[0]->getObjectiveSense(); int active = jobs; int frequency = 10000; // Print current bounds every two seconds. while (active > 0) { // Check if we should stop all solves. // We stop them if the absolute mipgap is reached. if ( state.primal.valid && state.dual.valid && ((objsen == IloObjective::Minimize && state.dual.bound + absgap >= state.primal.bound) || (objsen == IloObjective::Maximize && state.dual.bound - absgap <= state.primal.bound)) ) { std::cout << "Stopping criterion reached. Stopping all pending solves." << std::endl; for (int i = 0; i < jobs; ++i) workers[i]->kill(); break; } if ( --frequency == 0 ) { std::cout << "dual=" << state.dual.bound << ", " << "primal=" << state.primal.bound << std::endl; frequency = 10000; } // Loop over all solvers and test if they are still running. for (int i = 0; i < jobs; ++i) { if ( !workers[i]->isRunning() ) { // The job is finished. We have a solution, so kill all // others. --active; std::cout << "First job (" << i << ") is finished, killing the rest" << std::endl; for (int j = 0; j < jobs; ++j) { if ( j != i ) { workers[j]->kill(); --active; } } break; } } // Sleep a little so that we do not poll the workers like crazy. millisleep (10); } // All workers have finished or have been killed. Join them. // For each worker we print its status, its dettime and its bounds. for (int i = 0; i < jobs; ++i) { double obj = -IloInfinity; bool const result = workers[i]->join(); if ( !result ) { // No feasible solution found (yet) on this machine. // Just set objective function to a very big value obj = (objsen == IloObjective::Minimize) ? IloInfinity : -IloInfinity; } else { obj = workers[i]->getObjective(); } std::cout << "Job " << i << ": " << obj << ", stat " << workers[i]->getStatus() << std::endl << "\t" << workers[i]->getDetTime() << ", " << workers[i]->getDual() << ", " << workers[i]->getPrimal() << std::endl; } // Fetch the x vector from the solver that produced the best // primal bound. int const bestidx = state.primal.idx; if ( bestidx < 0 ) { std::cout << "No solution (model infeasible)" << std::endl; } else { IloNumArray x = workers[bestidx]->getX(); std::cout << "Optimal solution:" << std::endl; for (IloInt c = 0; c < x.getSize(); ++c) std::cout << "x[" << c << "]: " << x[c] << std::endl; x.end(); } // Release the workers. for (int i = jobs - 1; i >= 0; --i) delete workers[i]; delete[] workers; env.end(); } catch (...) { // In case of any error we still need to delete the workers. // This is to make sure that we properly disconnect from the // remote workers. The destructor of a worker will automatically // kill and join the worker if that was not already done. for (int i = jobs - 1; i >= 0; --i) delete workers[i]; delete[] workers; throw; } #ifdef USE_MPI MPI_Finalize (); #endif return 0; }
ILOBRANCHCALLBACK1(SOSbranch, IloSOS1Array, sos) { IloNumArray x; IloNumVarArray var; try { IloInt i; x = IloNumArray(getEnv()); var = IloNumVarArray(getEnv()); IloNum bestx = EPS; IloInt besti = -1; IloInt bestj = -1; IloInt num = sos.getSize(); for (i = 0; i < num; i++) { if ( getFeasibility(sos[i]) == Infeasible ) { var.clear(); sos[i].getVariables(var); getValues(x, var); IloInt n = var.getSize(); for (IloInt j = 0; j < n; j++) { IloNum inf = IloAbs(x[j] - IloRound(x[j])); if ( inf > bestx ) { bestx = inf; besti = i; bestj = j; } } } } if ( besti >= 0 ) { IloCplex::BranchDirectionArray dir; IloNumArray val; try { dir = IloCplex::BranchDirectionArray(getEnv()); val = IloNumArray(getEnv()); var.clear(); sos[besti].getVariables(var); IloInt n = var.getSize(); for (IloInt j = 0; j < n; j++) { if ( j != bestj ) { dir.add(IloCplex::BranchDown); val.add(0.0); } else { dir.add(IloCplex::BranchUp); val.add(1.0); } } makeBranch(var, val, dir, getObjValue()); makeBranch(var[bestj], 0.0, IloCplex::BranchDown, getObjValue()); } catch (...) { dir.end(); val.end(); throw; } dir.end(); val.end(); } } catch (...) { var.end(); x.end(); throw; } var.end(); x.end(); }