void PartitionedColoringModel::branchAndBound() { int status; double inittime, endtime; status = CPXgettime(this->cplexEnvironment, &inittime); this->solve(); this->saveInitialSolution(); this->changeToBinaryVariables(); this->solve(); status = CPXgettime(this->cplexEnvironment, &endtime); this->saveAmountOfNodesVisited(); this->saveFinalSolution(); this->cplexResult.setTime(endtime - inittime); }
static int CPXPUBLIC timelimcallback (CPXCENVptr env, void *cbdata, int wherefrom, void *cbhandle) { int status = 0; TIMELIMINFOptr info = (TIMELIMINFOptr) cbhandle; int hasincumbent = 0; status = CPXgetcallbackinfo (env, cbdata, wherefrom, CPX_CALLBACK_INFO_MIP_FEAS, &hasincumbent); if ( status ) goto TERMINATE; if ( !info->aborted && hasincumbent ) { double gap; double timenow; status = CPXgetcallbackinfo (env, cbdata, wherefrom, CPX_CALLBACK_INFO_MIP_REL_GAP, &gap); if ( status ) goto TERMINATE; /* Turn the gap into a percentage */ gap *= 100.0; status = CPXgettime (env, &timenow); if ( status ) goto TERMINATE; if ( timenow - info->timestart > info->timelim && gap < info->acceptablegap ) { fprintf (stderr, "Good enough solution at time %.2fsec, gap = %g%%, quitting\n", timenow - info->timestart, gap); /* callback may be called again during the clean up phase after the abort has been issued, so remember that abort processing has already occurred. */ info->aborted = 1; /* nonzero status causes abort */ status = 1; } } TERMINATE: return (status); } /* END timelimcallback */
int main(int argc, char *argv[]) { if(argc < 3){ cerr << "Uso: input_file max_iteraciones" << endl; exit(1); } srand(time(NULL)); string archivo_entrada(argv[1]); int max_iteraciones = atoi(argv[2]); //----------------------- PARSEO DE ENTRADA pair <int, pair<vector<vector<bool> >*, vector<vector<bool> >* > > grafo = parsear_entrada(archivo_entrada); int cant_ejes = grafo.first; vector<vector<bool> > *adyacencias = grafo.second.first; // matriz de adyacencia vector<vector<bool> > *particion = grafo.second.second; // filas: subconjuntos de la particion. columnas: nodos. // Variables binarias: // * X_n_j = nodo n pintado con el color j? (son cant_nodos * cant_colores_disp variables) // * W_j = hay algun nodo pintado con el color j? (son cant_colores_disp variables) // => TOTAL: (cant_nodos * cant_colores_disp + cant_colores_disp) variables // // Orden de las variables: // X_0_0, X_0_1, ... , X_0_(cant_col_disp), X_1_0, ... , X_(cant_nodos)_(cant_col_disp), W_0, ... , W(cant_col_disp) int cant_nodos = adyacencias->size(); int cant_subconj_particion = particion->size(); //cant de subconjuntos de la particion int cant_colores_disp = particion->size(); // cant colores usados <= cant de subconjuntos de la particion int n = cant_nodos * cant_colores_disp + cant_colores_disp; // n = cant de variables //----------------------- CARGA DE LP // Genero el problema de cplex. int status; CPXENVptr env; // Puntero al entorno. CPXLPptr lp; // Puntero al LP // Creo el entorno. env = CPXopenCPLEX(&status); if (env == NULL) { cerr << "Error creando el entorno" << endl; exit(1); } // Creo el LP. lp = CPXcreateprob(env, &status, "Coloreo Particionado"); if (lp == NULL) { cerr << "Error creando el LP" << endl; exit(1); } //TUNNING //Para que haga Branch & Cut: CPXsetintparam(env, CPX_PARAM_MIPSEARCH, CPX_MIPSEARCH_TRADITIONAL); //Para que no se adicionen planos de corte: ( => Branch & Bound) CPXsetintparam(env,CPX_PARAM_EACHCUTLIM, 0); CPXsetintparam(env, CPX_PARAM_FRACCUTS, -1); //Para facilitar la comparación evitamos paralelismo: CPXsetintparam(env, CPX_PARAM_THREADS, 1); //Para desactivar preprocesamiento CPXsetintparam(env, CPX_PARAM_PRESLVND, -1); CPXsetintparam(env, CPX_PARAM_REPEATPRESOLVE, 0); CPXsetintparam(env, CPX_PARAM_RELAXPREIND, 0); CPXsetintparam(env, CPX_PARAM_REDUCE, 0); CPXsetintparam(env, CPX_PARAM_LANDPCUTS, -1); //Otros parámetros // Para desactivar la salida poner CPX_OFF. Para activar: CPX_ON. status = CPXsetintparam(env, CPX_PARAM_SCRIND, CPX_OFF); if (status) { cerr << "Problema seteando SCRIND" << endl; exit(1); } //Setea el tiempo limite de ejecucion. status = CPXsetdblparam(env, CPX_PARAM_TILIM, 3600); if (status) { cerr << "Problema seteando el tiempo limite" << endl; exit(1); } double *ub, *lb, *objfun; // Cota superior, cota inferior, coeficiente de la funcion objetivo. char *xctype, **colnames; // tipo de la variable (por ahora son siempre continuas), string con el nombre de la variable. ub = new double[n]; lb = new double[n]; objfun = new double[n]; xctype = new char[n]; colnames = new char*[n]; // Defino las variables X_n_j for (int i = 0; i < n - cant_colores_disp; i++) { ub[i] = 1; lb[i] = 0; objfun[i] = 0; // Estas var no figuran en la funcion objetivo xctype[i] = 'C'; colnames[i] = new char[10]; sprintf(colnames[i], "X_%d_%d", i / cant_colores_disp, i % cant_colores_disp); } // Defino las variables W_j for (int i = n - cant_colores_disp; i < n; i++) { ub[i] = 1; lb[i] = 0; objfun[i] = 1; xctype[i] = 'C'; colnames[i] = new char[10]; sprintf(colnames[i], "W_%d", i - (n - cant_colores_disp)); } // Agrego las columnas. status = CPXnewcols(env, lp, n, objfun, lb, ub, NULL, colnames); if (status) { cerr << "Problema agregando las variables CPXnewcols" << endl; exit(1); } // Libero las estructuras. for (int i = 0; i < n; i++) { delete[] colnames[i]; } delete[] ub; delete[] lb; delete[] objfun; delete[] xctype; delete[] colnames; // Restricciones: // (1) Nodos adyacentes tienen distinto color (cant_ejes * cant_colores_disp restricciones por <=) // (2) Cada nodo tiene a lo sumo un color (cant_nodos restricciones por <=) // (3) Solo un nodo de cada subconj. de la particion tiene color (cant. de subconj. de la particion restricciones por =) // (4) W_j = 1 sii "X_i_j = 1 para algún i" (cant_colores_disp restricciones por >=) // (5) W_j >= W_(j+1) (cant_colores_disp - 1 restricciones por >=) // => TOTAL: (cant_ejes * cant_colores_disp + cant_nodos + cant_subconj_particion + cant_colores_disp + cant_colores_disp - 1) restricciones int ccnt = 0; //numero nuevo de columnas en las restricciones. int rcnt = cant_ejes * cant_colores_disp + cant_nodos + cant_subconj_particion + cant_colores_disp + cant_colores_disp - 1; //cuantas restricciones se estan agregando. int nzcnt = 0; //# de coeficientes != 0 a ser agregados a la matriz. Solo se pasan los valores que no son cero. char sense[rcnt]; // Sentido de la desigualdad. 'G' es mayor o igual y 'E' para igualdad. for(unsigned int i = 0; i < cant_ejes * cant_colores_disp; i++) sense[i] = 'L'; for(unsigned int i = cant_ejes * cant_colores_disp; i < cant_ejes * cant_colores_disp + cant_nodos; i++) sense[i] = 'L'; for(unsigned int i = cant_ejes * cant_colores_disp + cant_nodos; i < cant_ejes * cant_colores_disp + cant_nodos + cant_subconj_particion; i++) sense[i] = 'E'; for(unsigned int i = cant_ejes * cant_colores_disp + cant_nodos + cant_subconj_particion; i < rcnt; i++) sense[i] = 'G'; double *rhs = new double[rcnt]; // Termino independiente de las restricciones. int *matbeg = new int[rcnt]; //Posicion en la que comienza cada restriccion en matind y matval. int *matind = new int[rcnt*n]; // Array con los indices de las variables con coeficientes != 0 en la desigualdad. double *matval = new double[rcnt*n]; // Array que en la posicion i tiene coeficiente ( != 0) de la variable cutind[i] en la restriccion. //El termino indep. de restr (1), (2) y (3) es 1 for(unsigned int i = 0; i < cant_ejes * cant_colores_disp + cant_nodos + cant_subconj_particion; i++) rhs[i] = 1; //El termino indep. de restr (4) y (5) es 0 for(unsigned int i = cant_ejes * cant_colores_disp + cant_nodos + cant_subconj_particion; i < rcnt; i++) rhs[i] = 0; unsigned int indice = 0; //numero de restriccion actual //Restricciones (1) for(unsigned int i = 0; i < cant_nodos; i++) //itero nodo 1 for(unsigned int j = i+1; j < cant_nodos; j++) //itero nodo 2 if((*adyacencias)[i][j]) for(unsigned int p = 0; p < cant_colores_disp; p++){ //itero color matbeg[indice] = nzcnt; indice++; //cargo una de las variables participantes de la restr. matind[nzcnt] = cant_colores_disp*i + p; //var1: X_nodo1_color matval[nzcnt] = 1; nzcnt++; //idem con la otra variable matind[nzcnt] = cant_colores_disp*j + p; //var2: X_nodo2_color matval[nzcnt] = 1; nzcnt++; } //Restricciones (2) for(unsigned int i = 0; i < cant_nodos; i++){ //itero nodo matbeg[indice] = nzcnt; indice++; for(unsigned int p = 0; p < cant_colores_disp; p++){ //itero color matind[nzcnt] = cant_colores_disp*i + p; //var: X_nodo_color matval[nzcnt] = 1; nzcnt++; } } //Restricciones (3) for(unsigned int v = 0; v < cant_subconj_particion; v++){ //itero subconjunto de la particion matbeg[indice] = nzcnt; indice++; for(unsigned int i = 0; i < cant_nodos; i++) //itero nodo if((*particion)[v][i]) for(unsigned int p = 0; p < cant_colores_disp; p++){ //itero color matind[nzcnt] = cant_colores_disp*i + p; //var: X_nodo_color matval[nzcnt] = 1; nzcnt++; } } //Restricciones (4) for(unsigned int p = 0; p < cant_colores_disp; p++){ //itero color matbeg[indice] = nzcnt; indice++; matind[nzcnt] = cant_nodos * cant_colores_disp + p; //var: W_color matval[nzcnt] = cant_nodos; nzcnt++; for(unsigned int i = 0; i < cant_nodos; i++){ //itero nodo matind[nzcnt] = cant_colores_disp*i + p; //var: X_nodo_color matval[nzcnt] = -1; nzcnt++; } } //Restricciones (5) for(unsigned int p = 0; p < cant_colores_disp - 1; p++){ //itero color matbeg[indice] = nzcnt; indice++; matind[nzcnt] = cant_nodos * cant_colores_disp + p; //var: W_color matval[nzcnt] = 1; nzcnt++; matind[nzcnt] = cant_nodos * cant_colores_disp + p + 1; //var: W_(color+1) matval[nzcnt] = -1; nzcnt++; } // Esta rutina agrega la restriccion al lp. status = CPXaddrows(env, lp, ccnt, rcnt, nzcnt, rhs, sense, matbeg, matind, matval, NULL, NULL); if (status) { cerr << "Problema agregando restricciones." << endl; exit(1); } delete[] rhs; delete[] matbeg; delete[] matind; delete[] matval; // Escribimos el problema a un archivo .lp status = CPXwriteprob(env, lp, "output.lp", NULL); if (status) { cerr << "Problema escribiendo modelo" << endl; exit(1); } //----------------------- PRIMER ITERACION DE RESOLUCIÓN DEL LP // Tomamos el tiempo de resolucion utilizando CPXgettime. double inittime, endtime, fractpart, intpart, opt_anterior, opt_actual; int cant_iteraciones = 0; status = CPXgettime(env, &inittime); bool criterio_de_corte, todas_enteras, hubo_plano = true; status = CPXlpopt(env, lp); if (status) { cerr << "Problema optimizando CPLEX" << endl; exit(1); } status = CPXgetobjval(env, lp, &opt_actual); if (status) { cerr << "Problema obteniendo valor de mejor solucion." << endl; exit(1); } cout << "Optimo Inicial: " << opt_actual << endl << endl; double *sol = new double[n]; status = CPXgetx(env, lp, sol, 0, n - 1); if (status) { cerr << "Problema obteniendo la solucion del LP." << endl; exit(1); } // Chequeo si la solución es entera for (int i = 0; i < n; i++){ fractpart = modf(sol[i] , &intpart); if (fractpart > TOL){ todas_enteras = false; break; } } criterio_de_corte = todas_enteras || max_iteraciones==0; //----------------------- INICIO CICLO DE RESOLUCIÓN DEL LP while(!criterio_de_corte){ opt_anterior = opt_actual; hubo_plano = agregar_restricciones_clique(adyacencias, sol, env, lp, cant_colores_disp, n); hubo_plano = agregar_restricciones_ciclos(adyacencias, sol, env, lp, cant_colores_disp, n) || hubo_plano; if(hubo_plano){ status = CPXlpopt(env, lp); if (status) { cerr << "Problema optimizando CPLEX" << endl; exit(1); } status = CPXgetx(env, lp, sol, 0, n - 1); if (status) { cerr << "Problema obteniendo la solucion del LP." << endl; exit(1); } for (int i = 0; i < n; i++){ fractpart = modf(sol[i] , &intpart); if (fractpart > TOL){ todas_enteras = false; break; } } } status = CPXgetobjval(env, lp, &opt_actual); if (status) { cerr << "Problema obteniendo valor de mejor solucion." << endl; exit(1); } cant_iteraciones++; criterio_de_corte = todas_enteras || (cant_iteraciones >= max_iteraciones) || !hubo_plano;// || abs(opt_actual - opt_anterior) < TOL; } status = CPXgettime(env, &endtime); //----------------------- FIN CICLO DE RESOLUCIÓN DEL LP int solstat; char statstring[510]; CPXCHARptr p; solstat = CPXgetstat(env, lp); p = CPXgetstatstring(env, solstat, statstring); string statstr(statstring); cout << endl << "Resultado de la optimizacion: " << statstring << endl; if(solstat!=CPX_STAT_OPTIMAL) exit(1); double objval; status = CPXgetobjval(env, lp, &objval); if (status) { cerr << "Problema obteniendo valor de mejor solucion." << endl; exit(1); } cout << "Optimo: " << objval << "\t(Time: " << (endtime - inittime) << " sec)" << endl; // Tomamos los valores de la solucion y los escribimos a un archivo. std::string outputfile = "output.sol"; ofstream solfile(outputfile.c_str()); // Tomamos los valores de todas las variables. Estan numeradas de 0 a n-1. status = CPXgetx(env, lp, sol, 0, n - 1); if (status) { cerr << "Problema obteniendo la solucion del LP." << endl; exit(1); } // Solo escribimos las variables distintas de cero (tolerancia, 1E-05). solfile << "Status de la solucion: " << statstr << endl; // Imprimo var X_n_j for (int i = 0; i < n - cant_colores_disp; i++) { if (sol[i] > TOL) { solfile << "X_" << i / cant_colores_disp << "_" << i % cant_colores_disp << " = " << sol[i] << endl; } } // Imprimo var W_j for (int i = n - cant_colores_disp; i < n; i++) { if (sol[i] > TOL) { solfile << "W_" << i - (n - cant_colores_disp) << " = " << sol[i] << endl; } } solfile.close(); delete [] sol; delete adyacencias; delete particion; return 0; }
int main (int argc, char *argv[]) { int uselogcallback = 0; LOGINFO myloginfo; int usetimelimcallback = 0; TIMELIMINFO mytimeliminfo; int useterminate = 0; volatile int terminator; CPXENVptr env = NULL; CPXLPptr lp = NULL; int solstat; int status = 0; /* Check the command line arguments */ if (( argc != 3 ) || ( strchr ("lta", argv[2][0]) == NULL ) ) { usage (argv[0]); goto TERMINATE; } switch (argv[2][0]) { case 'l': uselogcallback = 1; break; case 't': usetimelimcallback = 1; break; case 'a': useterminate = 1; break; default: break; } /* Initialize the CPLEX environment */ env = CPXopenCPLEX (&status); /* If an error occurs, the status value indicates the reason for failure. A call to CPXgeterrorstring will produce the text of the error message. Note that CPXopenCPLEX produces no output, so the only way to see the cause of the error is to use CPXgeterrorstring. For other CPLEX routines, the errors will be seen if the CPXPARAM_ScreenOutput indicator is set to CPX_ON. */ if ( env == NULL ) { char errmsg[CPXMESSAGEBUFSIZE]; fprintf (stderr, "Could not open CPLEX environment.\n"); CPXgeterrorstring (env, status, errmsg); fprintf (stderr, "%s", errmsg); goto TERMINATE; } /* Turn on output to the screen */ status = CPXsetintparam (env, CPXPARAM_ScreenOutput, CPX_ON); if ( status ) { fprintf (stderr, "Failure to turn on screen indicator, error %d.\n", status); goto TERMINATE; } /* Create the problem, using the filename as the problem name */ lp = CPXcreateprob (env, &status, argv[1]); /* A returned pointer of NULL may mean that not enough memory was available or there was some other problem. In the case of failure, an error message will have been written to the error channel from inside CPLEX. In this example, the setting of the parameter CPXPARAM_ScreenOutput causes the error message to appear on stdout. Note that most CPLEX routines return an error code to indicate the reason for failure. */ if ( lp == NULL ) { fprintf (stderr, "Failed to create LP.\n"); goto TERMINATE; } /* Now read the file, and copy the data into the created lp */ status = CPXreadcopyprob (env, lp, argv[1], NULL); if ( status ) { fprintf (stderr, "Failed to read and copy the problem data.\n"); goto TERMINATE; } if ( usetimelimcallback ) { double t; status = CPXgettime (env, &t); if ( status ) { fprintf (stderr, "Failed to initialize timer.\n"); goto TERMINATE; } mytimeliminfo.acceptablegap = 10.0; mytimeliminfo.aborted = 0; mytimeliminfo.timestart = t; mytimeliminfo.timelim = 1.0; status = CPXsetinfocallbackfunc (env, timelimcallback, &mytimeliminfo); if ( status ) { fprintf (stderr, "Failed to set time limit callback function.\n"); goto TERMINATE; } } else if ( uselogcallback ) { /* Set overall node limit in case callback conditions are not met */ status = CPXsetintparam (env, CPXPARAM_MIP_Limits_Nodes, 5000); if ( status ) goto TERMINATE; status = CPXgettime (env, &myloginfo.timestart); if ( status ) { fprintf (stderr, "Failed to query time.\n"); goto TERMINATE; } status = CPXgetdettime (env, &myloginfo.dettimestart); if ( status ) { fprintf (stderr, "Failed to query deterministic time.\n"); goto TERMINATE; } myloginfo.numcols = CPXgetnumcols (env, lp); myloginfo.lastincumbent = CPXgetobjsen (env, lp) * 1e+35; myloginfo.lastlog = -10000; status = CPXsetinfocallbackfunc (env, logcallback, &myloginfo); if ( status ) { fprintf (stderr, "Failed to set logging callback function.\n"); goto TERMINATE; } /* Turn off CPLEX logging */ status = CPXsetintparam (env, CPXPARAM_MIP_Display, 0); if ( status ) goto TERMINATE; } else if ( useterminate) { status = CPXsetterminate (env, &terminator); if ( status ) { fprintf (stderr, "Failed to set terminator.\n"); goto TERMINATE; } /* Typically, you would pass the terminator variable to another thread or pass it to an interrupt handler, and monitor for some event to occur. When it does, set terminator to a non-zero value. To illustrate its use without creating a thread or an interrupt handler, terminate immediately by setting terminator before the solve. */ terminator = 1; } /* Optimize the problem and obtain solution. */ status = CPXmipopt (env, lp); if ( status ) { fprintf (stderr, "Failed to optimize MIP.\n"); goto TERMINATE; } solstat = CPXgetstat (env, lp); printf ("Solution status %d.\n", solstat); TERMINATE: /* Free up the problem as allocated by CPXcreateprob, if necessary */ if ( lp != NULL ) { int xstatus = CPXfreeprob (env, &lp); if ( xstatus ) { fprintf (stderr, "CPXfreeprob failed, error code %d.\n", xstatus); status = xstatus; } } /* Free up the CPLEX environment, if necessary */ if ( env != NULL ) { int xstatus = CPXcloseCPLEX (&env); /* Note that CPXcloseCPLEX produces no output, so the only way to see the cause of the error is to use CPXgeterrorstring. For other CPLEX routines, the errors will be seen if the CPXPARAM_ScreenOutput indicator is set to CPX_ON. */ if ( status ) { char errmsg[CPXMESSAGEBUFSIZE]; fprintf (stderr, "Could not close CPLEX environment.\n"); CPXgeterrorstring (env, status, errmsg); fprintf (stderr, "%s", errmsg); status = xstatus; } } return (status); } /* END main */
static int CPXPUBLIC logcallback (CPXCENVptr env, void *cbdata, int wherefrom, void *cbhandle) { int status = 0; LOGINFOptr info = (LOGINFOptr) cbhandle; int hasincumbent = 0; int newincumbent = 0; int nodecnt; int nodesleft; double objval; double bound; double *x = NULL; status = CPXgetcallbackinfo (env, cbdata, wherefrom, CPX_CALLBACK_INFO_NODE_COUNT, &nodecnt); if ( status ) goto TERMINATE; status = CPXgetcallbackinfo (env, cbdata, wherefrom, CPX_CALLBACK_INFO_NODES_LEFT, &nodesleft); if ( status ) goto TERMINATE; status = CPXgetcallbackinfo (env, cbdata, wherefrom, CPX_CALLBACK_INFO_MIP_FEAS, &hasincumbent); if ( status ) goto TERMINATE; if ( hasincumbent ) { status = CPXgetcallbackinfo (env, cbdata, wherefrom, CPX_CALLBACK_INFO_BEST_INTEGER, &objval); if ( status ) goto TERMINATE; if ( fabs(info->lastincumbent - objval) > 1e-5*(1.0 + fabs(objval)) ) { newincumbent = 1; info->lastincumbent = objval; } } if ( nodecnt >= info->lastlog + 100 || newincumbent ) { double walltime; double dettime; status = CPXgetcallbackinfo (env, cbdata, wherefrom, CPX_CALLBACK_INFO_BEST_REMAINING, &bound); if ( status ) goto TERMINATE; if ( !newincumbent ) info->lastlog = nodecnt; status = CPXgettime (env, &walltime); if ( status ) goto TERMINATE; status = CPXgetdettime (env, &dettime); if ( status ) goto TERMINATE; printf ("Time = %.2f Dettime = %.2f Nodes = %d(%d) Best objective = %g", walltime - info->timestart, dettime - info->dettimestart, nodecnt, nodesleft, bound); if ( hasincumbent ) printf (" Incumbent objective = %g\n", objval); else printf ("\n"); } if ( newincumbent ) { int j; int numcols = info->numcols; x = (double *) malloc (numcols*sizeof(double)); if ( x == NULL ) { status = CPXERR_NO_MEMORY; goto TERMINATE; } status = CPXgetcallbackincumbent (env, cbdata, wherefrom, x, 0, numcols-1); if ( status ) goto TERMINATE; printf ("New incumbent values:\n"); for (j = 0; j < numcols; j++) { if ( fabs(x[j]) > 1e-6 ) { printf (" Column %d: %g\n", j, x[j]); } } } TERMINATE: free_and_null ((char **) &x); return (status); } /* END logcallback */
void PartitionedColoringModel::cutAndBranch() { int status; double inittime, endtime; status = CPXgettime(this->cplexEnvironment, &inittime); for(int w = 0; w < 10; w++) { this->solve(); this->getCurrentSolution(); int amountOfNewRestrictions = this->graph->amountOfNodes() * 2; // 1 para clique, 1 para agujero int amountOfNonZeroCoefficients = 0; char *sense = new char[amountOfNewRestrictions]; std::vector< std::set<Node*> > cliqueList; std::vector< std::vector<Node*> > cycleList; // Para cada color, obtengo los nodos que están "más pintados" de ese color. for(int j = 1; j <= this->graph->amountOfNodes(); j++) { int maxNode = -1; double maxColored = -1.0; for(int i = 1; i <= this->graph->amountOfNodes(); i++) { int variablePosition = this->xVariablePositionFromModelIndex(i, j); double howMuchIsColored = this->currentSolution[variablePosition]; if(maxNode == -1 || howMuchIsColored > maxNode) { maxNode = i; maxColored = howMuchIsColored; } } Node *node = this->graph->getNodeWith(maxNode); // Para ese nodo, busco una clique y la agrego como restricción. FindCliqueHeuristic findCliqueHeuristic(this->graph); std::set<Node*> clique = findCliqueHeuristic.findCliqueContainingThis(node); cliqueList.push_back(clique); amountOfNonZeroCoefficients += (clique.size() + 1); // Para ese nodo, busco un ciclo y lo agrego como restricciòn. FindCycleHeuristic findCycleHeuristic(this->graph); std::vector<Node*> cycle = findCycleHeuristic.getOddCycle(node->getId()); cycleList.push_back(cycle); amountOfNonZeroCoefficients += (cycle.size() + 1); } int *restrictionsIndex = new int[amountOfNewRestrictions]; int *coefficientsIndex = new int[amountOfNonZeroCoefficients]; double *coefficientsValues = new double[amountOfNonZeroCoefficients]; int ci = 0, rn = 0, j; for(j = 0; j < cliqueList.size(); j++) { //clique restrictionsIndex[rn] = ci; std::set<Node*>::iterator node; for(node = cliqueList.at(j).begin(); node != cliqueList.at(j).end(); ++node) { coefficientsIndex[ci] = this->xVariablePositionFromModelIndex((*node)->getId(), j + 1); coefficientsValues[ci] = 1.0; ci++; } coefficientsIndex[ci] = this->wVariablePositionFromModelIndex(j + 1); coefficientsValues[ci] = -1.0; ci++; sense[rn] = 'L'; rn++; //cycle restrictionsIndex[rn] = ci; std::vector<Node*>::iterator node1; for(node1 = cycleList.at(j).begin(); node1 != cycleList.at(j).end(); ++node1) { coefficientsIndex[ci] = this->xVariablePositionFromModelIndex((*node1)->getId(), j + 1); coefficientsValues[ci] = 1.0; ci++; } coefficientsIndex[ci] = this->wVariablePositionFromModelIndex(j + 1); coefficientsValues[ci] = -1.0 * this->graph->amountOfPartitions(); ci++; sense[rn] = 'L'; rn++; } status = CPXaddrows(this->cplexEnvironment, this->linearProblem, 0, amountOfNewRestrictions, amountOfNonZeroCoefficients, NULL, sense, restrictionsIndex, coefficientsIndex, coefficientsValues, NULL, NULL); delete [] sense; delete [] restrictionsIndex; delete [] coefficientsIndex; delete [] coefficientsValues; } this->solve(); this->getCurrentSolution(); this->saveInitialSolution(); this->changeToBinaryVariables(); this->solve(); status = CPXgettime(this->cplexEnvironment, &endtime); this->saveAmountOfNodesVisited(); this->saveFinalSolution(); this->cplexResult.setTime(endtime - inittime); }
int main(int argc, char **argv) { char ejes[100]; char labels[100]; char test[100]; archivoInput = argv[1]; randomness = argv[2]; porcentajeParticiones = atof(argv[3]); algoritmo = argv[4]; epsilonClique = atof(argv[5]); epsilonAgujero = atof(argv[6]); numeroDeModelo = atoi(argv[7]); RECORRIDO_ARBOL = atoi(argv[8]); VARIABLE_CORTE = atoi(argv[9]); semilla = atoi(argv[10]); srand(semilla); if(not freopen(archivoInput.c_str(), "r", stdin)){ cout << "No pude abrir archivo: " << archivoInput << endl; return 1; } sprintf(ejes, "ejes.out"); sprintf(labels, "labels.out"); if(randomness == "notrandom") { sprintf(test, "%s%s", argv[1], argv[2]); } else if (randomness == "random") { sprintf(test, "%s%s", argv[1], argv[3]); } else{ cout << "Paramtros mal introducidos" << endl; return 0; } read(randomness); // cada elemento de la particion conformado por un unico nodo // Le paso por parametro el algoritmo a implementar: bb = branch and bound, cb = cut and branch if(algoritmo != "bb" && algoritmo != "cb") { cout << "Error introduciendo parametro de algoritmo a ser aplicado " << endl; return 0; } // ============================================================================================== // Genero el problema de cplex. int status; // Creo el entorno. CPXENVptr env = CPXopenCPLEX(&status); // Puntero al entorno. CPXLPptr lp; // Puntero al LP if (env == NULL) { cerr << "Error creando el entorno" << endl; exit(1); } ///Iniciio el reloj CPXgettime(env, &inittime); // Creo el LP. lp = CPXcreateprob(env, &status, "instancia coloreo de grafo particionado"); if (lp == NULL) { cerr << "Error creando el LP" << endl; exit(1); } // Definimos las variables. En total, son P + N*P variables ( las W[j] y las X[i][j] ) int cantVariables = P + N*P; double *ub, *lb, *objfun; // Cota superior, cota inferior, coeficiente de la funcion objetivo. char *xctype, **colnames; // tipo de la variable , string con el nombre de la variable. ub = new double[cantVariables]; lb = new double[cantVariables]; objfun = new double[cantVariables]; xctype = new char[cantVariables]; colnames = new char*[cantVariables]; for (int i = 0; i < cantVariables; i++) { ub[i] = 1.0; // seteo upper y lower bounds de cada variable lb[i] = 0.0; if(i < P) { // agrego el costo en la funcion objetivo de cada variables objfun[i] = 1; // busco minimizar Sum(W_j) para j=0..P (la cantidad de colores utilizados). } else { objfun[i] = 0; // los X[i][j] no contribuyen a la funcion objetivo } xctype[i] = 'B'; // 'C' es continua, 'B' binaria, 'I' Entera. colnames[i] = new char[10]; } /* Defino el tipo de variable BoolVarMatrix, que sera utilizado en la resolucion * recordar: X_v_j = 1 sii el color j es asignado al vertice v * recordar: W_j = 1 si X_v_j = 1 para al menos un vertice v */ for(int j=0; j<P; j++) { sprintf(colnames[j], "W_%d", j); // cout << colnames[j] << endl; } for(int i=0; i<N; i++) { for(int j=0; j<P; j++) { sprintf(colnames[xijIndice(i,j)], "X_%d_%d", i, j); // cout << colnames[xijIndice(i,j)] << endl; } } // ========================== Agrego las columnas. =========================== // if(algoritmo == "cb"){ // si quiero resolver la relajacion, agregar los cortes y despues resolver el MIP, no agrego xctype status = CPXnewcols(env, lp, cantVariables, objfun, lb, ub, NULL, colnames); } else if (algoritmo == "bb"){ // si quiero hacer MIP, directamente, con brancha and bound, agrego xctype status = CPXnewcols(env, lp, cantVariables, objfun, lb, ub, xctype, colnames); } else { cout << "Error: parametro de algoritmo bb/cb mal introducido" << endl; return 0; } if (status) { cerr << "Problema agregando las variables CPXnewcols" << endl; exit(1); } // Libero las estructuras. for (int i = 0; i < cantVariables; i++) { delete[] colnames[i]; } delete[] ub; delete[] lb; delete[] objfun; delete[] xctype; delete[] colnames; // CPLEX por defecto minimiza. Le cambiamos el sentido a la funcion objetivo si se quiere maximizar. // CPXchgobjsen(env, lp, CPX_MAX); // ================================================================================================ // // ===================================== Restricciones ============================================ // // i) Asigno exactamente un color a exactamente un vertice de cada particion ( P restricciones ) // ii) Dos vertices adyacentes no pueden tener el mismo color ( E restricciones ) // iii) Los W_j estan bien armados, en funcion de X_v_j ( 2*P restricciones ) // ccnt = numero nuevo de columnas en las restricciones. // rcnt = cuantas restricciones se estan agregando. // nzcnt = # de coeficientes != 0 a ser agregados a la matriz. Solo se pasan los valores que no son cero. int ccnt = 0; int rcnt; if(numeroDeModelo == 0){ rcnt = P + (E*P)/2 + 2*P; // Cota maxima a la cantidad de restricciones } else{ rcnt = P + (E*P)/2 + N*P; } // (E/2 porque en la entrada se supone que en la entrada me pasan 2 veces cada eje) int nzcnt = 0; // al ppio es cero (para cada valor q agrego, lo voy a incrementar en 1) char sense[rcnt]; // Sentido de la desigualdad. 'G' es mayor o igual y 'E' para igualdad, 'L' menor o igual double *rhs = new double[rcnt]; // Termino independiente de las restricciones. int *matbeg = new int[rcnt]; //Posicion en la que comienza cada restriccion en matind y matval. int *matind = new int[rcnt*cantVariables]; // Array con los indices de las variables con coeficientes != 0 en la desigualdad. double *matval = new double[rcnt*cantVariables]; // Array que en la posicion i tiene coeficiente ( != 0) de la variable matind[i] en la restriccion. // CPLEX va a leer hasta la cantidad nzcnt que le pasemos. int cantRestricciones = 0; // r = numero de restriccion // i) P restricciones - exactamente un color a cada vertice (una restriccion por cada particion) for(int particion = 0; particion < P; particion++) { matbeg[cantRestricciones] = nzcnt; rhs[cantRestricciones] = 1; sense[cantRestricciones] = 'E'; for(int e = 0; e < S[particion].size(); e++) { for(int color = 0; color < P; color++) { matind[nzcnt] = xijIndice(S[particion][e], color); matval[nzcnt] = 1; nzcnt++; } } cantRestricciones++; } // ii) Cota superior de (E*P)/2 restricciones mas // Una para cada par de vecinos i j, para cada color pero solo cuando i < j, y estan en distinta particion for(int i = 0; i < N; i++) { for(int j = i + 1; j < N; j++) { if(M[i][j] == 1 and dameParticion(i) != dameParticion(j)){ for(int color = 0; color < P; color++) { matbeg[cantRestricciones] = nzcnt; rhs[cantRestricciones] = 1; sense[cantRestricciones] = 'L'; matind[nzcnt] = xijIndice(i,color); matval[nzcnt] = 1; nzcnt++; matind[nzcnt] = xijIndice(j,color); matval[nzcnt] = 1; nzcnt++; cantRestricciones++; } } } } if(numeroDeModelo == 0){ // iii) 2*P restricciones mas // - P * wj + sigma xij <= 0 for(int k=0; k<P; k++) { // para cada color matbeg[cantRestricciones] = nzcnt; rhs[cantRestricciones] = 0; sense[cantRestricciones] = 'L'; matind[nzcnt] = k; matval[nzcnt] = -1 * P; nzcnt++; for(int i=0; i<N; i++) { matind[nzcnt] = xijIndice(i,k); matval[nzcnt] = 1; nzcnt++; } cantRestricciones++; } // - wj + sigma xij >= 0 for(int k=0; k<P; k++) { matbeg[cantRestricciones] = nzcnt; rhs[cantRestricciones] = 0; sense[cantRestricciones] = 'G'; matind[nzcnt] = k; matval[nzcnt] = -1; nzcnt++; for(int i=0; i<N; i++) { matind[nzcnt] = xijIndice(i,k); matval[nzcnt] = 1; nzcnt++; } cantRestricciones++; } } else{ // iii) N*P restricciones mas // -wj + xij <= 0 for(int color = 0; color < P; color++) { for(int i = 0; i < N; i++) { matbeg[cantRestricciones] = nzcnt; rhs[cantRestricciones] = 0; sense[cantRestricciones] = 'L'; matind[nzcnt] = color; matval[nzcnt] = -1; nzcnt++; matind[nzcnt] = xijIndice(i, color); matval[nzcnt] = 1; nzcnt++; cantRestricciones++; } } } //Actualizo rcnt. rcnt = cantRestricciones; // =================================================================================================== // Agregamos las restricciones al lp. status = CPXaddrows(env, lp, ccnt, rcnt, nzcnt, rhs, sense, matbeg, matind, matval, NULL, NULL); if (status) { cerr << "Problema agregando restricciones." << endl; exit(1); } delete[] rhs; delete[] matbeg; delete[] matind; delete[] matval; // ============================================================================================== // // ================================== Optimizamos el problema. ================================== // // Seteo de algunos parametros. // Para desactivar la salida poner CPX_OFF. status = CPXsetintparam(env, CPX_PARAM_SCRIND, CPX_ON); if (status) { cerr << "Problema seteando SCRIND" << endl; exit(1); } // Setea el tiempo limite de ejecucion. status = CPXsetdblparam(env, CPX_PARAM_TILIM, TIEMPO_LIMITE); // setear limite de tiempo en 3600 !!!!!!! if (status) { cerr << "Problema seteando el tiempo limite" << endl; exit(1); } // Escribimos el problema a un archivo .lp. // status = CPXwriteprob(env, lp, "test.lp", NULL); if (status) { cerr << "Problema escribiendo modelo" << endl; exit(1); } // Seteamos algunos parametros para resolver con branch and bound CPXsetintparam(env, CPX_PARAM_MIPSEARCH, CPX_MIPSEARCH_TRADITIONAL); // Para facilitar la comparación evitamos paralelismo: CPXsetintparam(env, CPX_PARAM_THREADS, 1); //Para que no se adicionen planos de corte: CPXsetintparam(env,CPX_PARAM_EACHCUTLIM, 0); CPXsetintparam(env, CPX_PARAM_FRACCUTS, -1); CPXsetintparam(env, CPX_PARAM_LANDPCUTS, -1); // Para que no haga preprocesamientos CPXsetintparam(env, CPX_PARAM_PRESLVND, -1); CPXsetintparam(env, CPX_PARAM_REPEATPRESOLVE, 0); CPXsetintparam(env, CPX_PARAM_RELAXPREIND, 0); CPXsetintparam(env, CPX_PARAM_REDUCE, 0); // Recorrido del arbol CPXsetintparam(env, CPX_PARAM_NODESEL, RECORRIDO_ARBOL); // Seleccion de variable CPXsetintparam(env, CPX_PARAM_VARSEL, VARIABLE_CORTE); CPXgettime(env, &endtime); tiempoPreparar = endtime - inittime; inittime = endtime; // ========================================================================================================= // resuelvo con cut and branch (con los cortes definidos por nosotros) o con branch and bound (y sin cortes) // ========================================================================================================= if(algoritmo == "cb") { // while (algo) ... resolver el lp, chequear si la restr inducida por la clique actual es violada. Seguir //cout << "antes" << endl; for(int ciclocb=0; ciclocb<CANT_CICLOS_CB; ciclocb++) { status = CPXlpopt(env, lp); //cout << "despues" << endl; double objval; status = CPXgetobjval(env, lp, &objval); // Aca, deberia agregar los cortes requeridos, en funcion de "cliques" y "objval" // mostrameValores(env, lp); double *sol = new double[cantVariables]; CPXgetx(env, lp, sol, 0, cantVariables - 1); //CPXwriteprob (env, lp, "antesDeClique.lp", "LP"); // BUSCAR Y AGREGAR CLIQUE vector < vector<int> > agregados; for(int color=0; color<P; color++) { for(int i=0; i<CANT_RESTR_CLIQUES; i++) { bool iteracionRandom = (i!=0); vector<int> clique = dameClique(sol, color, iteracionRandom); sort(clique.begin(), clique.end()); bool incluido = find(agregados.begin(), agregados.end(), clique) != agregados.end(); if (not incluido and not clique.empty()) { agregados.push_back(clique); agregarRestriccionClique(env, lp, clique); cantidadCortesClique++; // cout << "AGREGO RESTRICCION DE CLIQUE de random " << iteracionRandom << " y de color #"<< color << ": "; // for(int j=0; j<clique.size(); j++) { // cout << clique[j] << " "; // } // cout << endl; } } } // BUSCAR Y AGREGAR AGUJERO agregados.clear(); for(int color=0; color<P; color++) { for(int i=0; i<CANT_RESTR_AGUJEROS; i++) { vector<int> agujero = dameAgujero(sol, color); bool incluido = find(agregados.begin(), agregados.end(), agujero) != agregados.end(); if (not incluido and not agujero.empty()) { agregados.push_back(agujero); agregarRestriccionAgujero(env, lp, agujero); cantidadCortesAgujero++; // cout << "AGREGO RESTRICCION DE AGUJERO de color #"<< color << ": "; // for(int j=0; j<agujero.size(); j++) { // cout << agujero[j] << " "; // } // cout << endl; } } } delete [] sol; } // CPXwriteprob (env, lp, "lpCB.lp", "LP"); ///Cuando salimos, pasamos a binaria y corremos un branch and bound char *ctype = new char[cantVariables]; for (int i = 0; i < cantVariables; i++) { ctype[i] = 'B'; } // cout << "Antes cambiar tipo" << endl; status = CPXcopyctype (env, lp, ctype); // cout << "Despues cambiar tipo" << endl; delete[] ctype; CPXgettime(env, &endtime); tiempoCutAndBranch = endtime - inittime; inittime = endtime; } ///Corremos el BB, ya sea porque esto es lo que queriamos originalemente, o porque terminamos con los planos de corte // cout << "ANTES" << endl; //CPXwriteprob (env, lp, "antesDeMip.lp", "LP"); CPXmipopt(env,lp); // cout << "DESPUES" << endl; CPXgettime(env, &endtime); tiempoBranchAndBound = endtime - inittime; // inittime = endtime; status = CPXgettime(env, &endtime); if (status) { cerr << "Problema optimizando CPLEX" << endl; exit(1); } // Chequeamos el estado de la solucion. int solstat; char statstring[510]; CPXCHARptr p; solstat = CPXgetstat(env, lp); p = CPXgetstatstring(env, solstat, statstring); string statstr(statstring); cout << endl << "Resultado de la optimizacion: " << statstring << endl; if(solstat!=CPXMIP_OPTIMAL && solstat!=CPXMIP_OPTIMAL_TOL && solstat!=CPXMIP_NODE_LIM_FEAS && solstat!=CPXMIP_TIME_LIM_FEAS){ cout << "No hay solucion" << endl; } else{ double objval; status = CPXgetobjval(env, lp, &objval); if (status) { cerr << "Problema obteniendo valor de mejor solucion." << endl; exit(1); } cout << "Datos de la resolucion: " << "\t" << objval << "\t" << tiempoPreparar + tiempoCutAndBranch + tiempoBranchAndBound << endl; cout << "Tiempo en preparar: " << "\t" << tiempoPreparar << endl; cout << "Tiempo en CB: " << "\t" << tiempoCutAndBranch << endl; cout << "Tiempo en BB: " << "\t" << tiempoBranchAndBound << endl; // Tomamos los valores de todas las variables. Estan numeradas de 0 a n-1. double *sol = new double[cantVariables]; status = CPXgetx(env, lp, sol, 0, cantVariables - 1); if (status) { cerr << "Problema obteniendo la solucion del LP." << endl; exit(1); } impresionModelo(env, lp); // Solo escribimos las variables distintas de cero (tolerancia, 1E-05). //solfile << "Status de la solucion: " << statstr << endl; // for(int j=0; j<P; j++) { // if(sol[j] > TOL) { // cout << "W_" << j << " = " << sol[j] << endl; // } // } // for(int i=0; i<N; i++) { // for(int j=0; j<P; j++) { // if(sol[P + P*i + j] > TOL) { // cout << "X_" << i << "_" << j << " = " << sol[P+P*i+j] << endl; // } // } // } //solfile.close(); // ==================== Devuelvo el grafo resultante coloreado, para graficar! ====================== // // ofstream streamEjes, streamLabels; //ofstream streamParticiones; // Tomamos los valores de la solucion y los escribimos a un archivo. // streamEjes.open(ejes); // for(int v1=0; v1<N; v1++) { // for(int v2=v1+1; v2<N; v2++) { // if (M[v1][v2] == 1) { // streamEjes << v1+1 << " " << v2+1 << endl; // } // } // } streamEjes.close(); // cout << ejes << endl; // streamLabels.open(labels); // bool estaColoreado; // for(int v=0; v<N; v++){ // estaColoreado = false; // for(int j=0; j<P; j++){ // if (sol[P + P*v + j] == 1) { // streamLabels << v+1 << " " << j+1 << endl; // estaColoreado = true; // } // } // if(not estaColoreado) { // streamLabels << v+1 << " " << 0 << endl; // } // } // streamLabels.close(); // delete [] sol; } return 0; }