/* prüft, die Länge der Tour, dabei ist * sol ein Array, dass die Werte der Kanten enthält (angeordnet als LU Dreieck), * visited ist ein Hilfsarray, dass sich merkt, welche Punkte schon besucht wurden * tol ist die numerische Toleranz (vgl. andere Bsp. für Lazy Constraints) * */ int getTourLen(IloNumArray sol, IloNumArray visited, IloNum tol, tour_t *tour, bool mip) { int j; const int n = sol.getSize(); const int N = sqrt(n); int last = -1; int length = 0; int current = 0; visited.clear(); visited.add(n, 0.0); // mit 0 initialisieren // Problemgröße von 0? Das sollte nicht passieren if(n == 0) { printf(ERROR "argghh! zero! zero length LP representation!\n"); return (N+1); } // bis ich wieder da ankomme, wo ich gewesen bin while(visited[current] == 0) { length++; visited[current] = length; // notiere Position auf der Stadt // suche die nächste Stadt in der Waagerechten des UL Dreiecks for(j=0; j<current; j++) if(j != last && sol[current*N + j] >= 1.0-tol) break; // wenn ich nicht abgebrochen habe -> nicht gefunden // suche die nächste Stadt in der Senkrechten des UL Dreiecks if(j == current) for(j = current+1; j < N; j++) if(j != last && sol[j*N + current] >= 1.0-tol) break; // es gibt keinen Nachbarn ?! Das sollte nicht passieren. if(j == N) { if(mip) printf(ERROR "argghh! separated point! no neighbors! everybody panic!\n"); return (N+1); } // gehe zur nächsten Stadt last = current; current = j; if(tour != NULL) tour->push_back(current); } // Länge der getroffenen Subtour return length; }
IloNum sumArray(IloNumArray redCosts) { // delcare loop counter: IloInt m; // default/starting value: 0. IloNum arrSum = 0.0; // loop over the array members for (m = 0; m < redCosts.getSize(); m++) { // add member by member arrSum += redCosts[m]; } // return minimum return arrSum; } // END of sumArray
IloNum minMemberValue(IloNumArray redCosts) { // delcare loop counter: IloInt m; // default/starting minimum: 0. IloNum currentMin = 0.0; // loop over the array members for (m = 0; m < redCosts.getSize(); m++) { // see if current members improves minimum if (redCosts[m] < currentMin) { currentMin = redCosts[m]; } } // return minimum return currentMin; } // END of minMemberValue
bool getCut( IloNumArray& vals, IloNumVarArray& vars, CutMode cutmode, int set, IloCplex::ControlCallbackI::IntegerFeasibilityArray feas, IloRange& cut, int** graph, int* old_winner ){ int n = vals.getSize()/2; bool marked[n]; for( int i = 0; i < n; ++i ) marked[i] = false; int winner; int count_marked = 0; list<int> indices; int acc[n][n];//mudar para lista adjacencia memset(acc, 0, sizeof(acc)); static int cont=0; for( int i = 0; i < n; ++i ){ if(feas[i+n*set] == IloCplex::ControlCallbackI::Infeasible) marked[i] = false; else{ marked[i]=true; count_marked++; } } //int cont=0; int cnt=0; while( count_marked < n ){ //choose the star node cnt++; winner = -1; for( int i = 0; i < n; ++i ){ if(old_winner[i+n*set])continue; if( !marked[i] ){ if( winner == -1 ){ winner = i; } else if( cutmode == CLQ2B && fabs(vals[i+n*set]-0.5) < fabs(vals[winner+n*set]-0.5) && vals[i+n*set] > 0 && vals[i+n*set] < 1 ){ winner = i; } else if( cutmode == CLQ2A && vals[i+n*set] > vals[winner+n*set] && vals[i+n*set] < 1 ){ winner = i; } } } if(winner==-1)return false; //?? old_winner[winner+n*set]=1; ++count_marked; marked[winner] = true; indices.push_back( winner+n*set ); for( int i = 0; i < n; ++i ){ if( !graph[i][winner] ){ if( !marked[i] ){ marked[i] = true; ++count_marked; } } } } list<int>::iterator it = indices.begin(); float sum = 0; while( it != indices.end() ){ sum += vals[*it]; ++it; } for(list<int>::iterator it1 = indices.begin(); it1!= indices.end(); it1++){ for(list<int>::iterator it2 = indices.begin(); it2!= indices.end(); it2++){ int v1 = *it1; int v2 = *it2; if(v1==v2)continue; v1 -= n*set; v2 -= n*set; if(!graph[v1][v2] || !graph[v2][v1]){ puts("ERRO NAO CLICK"); printf("%d %d\n", v1, v2); exit(-1); } } } if(sum > 1+0.000001 ){ it = indices.begin(); while( it != indices.end() ){ cut.setLinearCoef( vars[*it], 1 ); //printf("x[%d] ", *it); ++it; } //printf(" <= 1\n"); return true; } return false; }
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; }