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; }
void MC_readproblem(MC_tm& tm) { int i, j, k; MC_problem &mc = tm.mc; std::ifstream file(tm.tm_par.entry(MC_tm_par::InputFile).c_str()); if (! file) { throw BCP_fatal_error("Can't open input file!\n"); } char line[1000]; double rescale = 1; for (int lose = tm.tm_par.entry(MC_tm_par::DigitsToLose); lose > 0; --lose) { rescale *= 10.0; } file.getline(line, 999); int len = strlen(line); if (strncmp(line, "DESC: ggrid", CoinMin(len, 11)) == 0) { // Ising problem generated by ggrid. Parse the info. mc.ising_problem = true; printf("Ising problem detected.\n"); file.getline(line, 999); sscanf(line, "DESC: scaling: %lf", &mc.scaling_factor); mc.scaling_factor /= rescale; } while (strncmp(line, "DESC:", CoinMin(len, 5)) == 0) { file.getline(line, 999); } sscanf(line, "%i%i", &mc.num_nodes, &mc.num_edges); const int n = mc.num_nodes; const int m = mc.num_edges; // this will be definitely enough, even for new edges to connect // disconnected components. mc.edges = new MC_graph_edge[m + n]; std::map<intpair, int> edge_map; double cost; intpair ip; for (i = 0, k = 0; i < m; ++i) { file.getline(line, 999); sscanf(line, "%i%i%lf", &ip.first, &ip.second, &cost); if (ip.first < 0 || ip.first >= n || ip.second < 0 || ip.second >= n || (ip.first == ip.second)) { char errmsg[200]; sprintf(errmsg, " bad endnodes %i %i\n", ip.first, ip.second); throw BCP_fatal_error(errmsg); } if (ip.first > ip.second) std::swap(ip.first, ip.second); const std::map<intpair, int>::const_iterator em = edge_map.find(ip); if (em != edge_map.end()) { printf("Warning: edge (%i,%i) appears once again.\n", ip.first, ip.second); printf(" Collapsing the parallel edges.\n"); mc.edges[em->second].cost += cost; } else { edge_map[ip] = k; mc.edges[k].tail = ip.first; mc.edges[k].head = ip.second; mc.edges[k++].cost = cost; } } mc.num_edges = k; file.close(); // throw out the 0 cost edges if it's not an ising problem. For ising // problems it's worth to keep the 0 cost edges because then the structure // is preserved. if (! mc.ising_problem) { for (i = 0, k = 0; i < mc.num_edges; ++i) { if (mc.edges[i].cost == 0.0) { printf("Warning: Discarded edge (%i,%i) as it has final cost 0.\n", mc.edges[i].tail, mc.edges[i].head); } else { mc.edges[k].tail = mc.edges[i].tail; mc.edges[k].head = mc.edges[i].head; mc.edges[k++].cost = mc.edges[i].cost; } } mc.num_edges = k; // Check connectivity int * components = new int[mc.num_nodes]; const int comp_num = mc.num_nodes - MC_components(mc.num_nodes, mc.num_edges, mc.edges, components); if (comp_num > 1) { printf("There are %i components in the graph. Adding 0 cost edges.\n", comp_num); std::set<int> seen; seen.insert(components[0]); for (i = 0; i < mc.num_nodes; ++i) { if (seen.find(components[i]) == seen.end()) { // not seen component. connect it mc.edges[mc.num_edges].tail = 0; mc.edges[mc.num_edges].head = i; mc.edges[mc.num_edges++].cost = 0; seen.insert(components[i]); } } } delete[] components; } // rescale the edges for (i = 0; i < mc.num_edges; ++i) { const double c = mc.edges[i].cost; mc.edges[i].cost = floor(c / rescale + 0.5); } // Negate the cost of the edges (minimizing!) and compute their sum mc.sum_edge_weight = 0; for (i = 0; i < mc.num_edges; ++i) { const double c = - mc.edges[i].cost; mc.edges[i].cost = c; mc.sum_edge_weight += c; } mc.create_adj_lists(); if (mc.ising_problem) { const int grid = static_cast<int>(sqrt(mc.num_nodes + 1.0)); const int num_grid_nodes = grid * grid; const int num_grid_edges = 2 * num_grid_nodes; const int vertical = num_grid_nodes; { // enumerate the 4-cycles mc.ising_four_cycles = new int[num_grid_nodes * 4]; int * cycle = mc.ising_four_cycles; for (i = 0; i < grid; ++i) { for (j = 0; j < grid; ++j) { // (i,j) -> (i,j+1) cycle[0] = i*grid + j; // (i,j+1) -> (i+1,j+1) cycle[1] = vertical + i*grid + ((j+1) % grid); // (i+1,j) -> (i+1,j+1) cycle[2] = ((i+1) % grid) * grid + j; // (i,j) -> (i+1,j) cycle[3] = vertical + i*grid + j; cycle += 4; } } } const bool has_extra_node = (mc.num_nodes != num_grid_nodes); if (has_extra_node) { // enumerate the triangles mc.ising_triangles = new int[2 * num_grid_nodes * 3]; int * triangle = mc.ising_triangles; for (i = 0; i < grid; ++i) { for (j = 0; j < grid; ++j) { // (i,j) -> (i,j+1) -> extra_node -> triangle[0] = i*grid + j; triangle[1] = num_grid_edges + i*grid + j; triangle[2] = num_grid_edges + i*grid + ((j+1) % grid); if (triangle[1] > triangle[2]) std::swap(triangle[1], triangle[2]); triangle += 3; // (i,j) -> (i+1,j) -> extra_node -> triangle[0] = vertical + i*grid + j; triangle[1] = num_grid_edges + i*grid + j; triangle[2] = num_grid_edges + ((i+1) % grid) * grid + j; if (triangle[1] > triangle[2]) std::swap(triangle[1], triangle[2]); triangle += 3; } } } mc.num_structure_type = 5; mc.num_switch_structures = new int[mc.num_structure_type]; mc.switch_structures = new MC_switch_structure*[mc.num_structure_type]; // three-node connected structures { mc.num_switch_structures[0] = num_grid_nodes * 6; mc.switch_structures[0] = new MC_switch_structure[num_grid_nodes * 6]; MC_switch_structure * next_struct = mc.switch_structures[0]; int nodes[3]; // enumerate the outgoing edges of three long chains for (i = 0; i < grid; ++i) { for (j = 0; j < grid; ++j) { //------------------------------------------------------------------- // the three nodes: (i-1,j), (i,j), (i+1,j) // | // | nodes[0] = ((i+grid-1)%grid) * grid + j; nodes[1] = i * grid + j; nodes[2] = ((i+1)%grid) * grid + j; MC_fill_structure(mc, *next_struct, 3, nodes); if (next_struct->num_neighbors != 8 + (has_extra_node ? 3 : 0)) abort(); ++next_struct; //------------------------------------------------------------------- // the three nodes: (i,j-1), (i,j), (i,j+1) // -- nodes[0] = i * grid + ((j+grid-1)%grid); nodes[1] = i * grid + j; nodes[2] = i * grid + ((j+1)%grid); MC_fill_structure(mc, *next_struct, 3, nodes); if (next_struct->num_neighbors != 8 + (has_extra_node ? 3 : 0)) abort(); ++next_struct; //------------------------------------------------------------------- // the three nodes: (i-1,j), (i,j), (i,j+1) // |_ nodes[0] = ((i+grid-1)%grid) * grid + j; nodes[1] = i * grid + j; nodes[2] = i * grid + ((j+1)%grid); MC_fill_structure(mc, *next_struct, 3, nodes); if (next_struct->num_neighbors != 8 + (has_extra_node ? 3 : 0)) abort(); ++next_struct; //------------------------------------------------------------------- // (i,j+1), (i,j), (i+1,j) // _ // | nodes[0] = i * grid + ((j+1)%grid); nodes[1] = i * grid + j; nodes[2] = ((i+1)%grid) * grid + j; MC_fill_structure(mc, *next_struct, 3, nodes); if (next_struct->num_neighbors != 8 + (has_extra_node ? 3 : 0)) abort(); ++next_struct; //------------------------------------------------------------------- // the three nodes: (i+1,j), (i,j), (i,j-1) // _ // | nodes[0] = ((i+1)%grid) * grid + j; nodes[1] = i * grid + j; nodes[2] = i * grid + ((j+grid-1)%grid); MC_fill_structure(mc, *next_struct, 3, nodes); if (next_struct->num_neighbors != 8 + (has_extra_node ? 3 : 0)) abort(); ++next_struct; //------------------------------------------------------------------- // the three nodes: (i,j-1), (i,j), (i-1,j) // _| nodes[0] = i * grid + ((j+grid-1)%grid); nodes[1] = i * grid + j; nodes[2] = ((i+grid-1)%grid) * grid + j; MC_fill_structure(mc, *next_struct, 3, nodes); if (next_struct->num_neighbors != 8 + (has_extra_node ? 3 : 0)) abort(); ++next_struct; } } } //========================================================================= // different four-node connected structures // first { mc.num_switch_structures[1] = 4 * num_grid_nodes; mc.switch_structures[1] = new MC_switch_structure[4 * num_grid_nodes]; MC_switch_structure * next_struct = mc.switch_structures[1]; int nodes[4]; // List the outgoing edges from every square for (i = 0; i < grid; ++i) { for (j = 0; j < grid; ++j) { // _|_ nodes[0] = i * grid + j; nodes[1] = i * grid + ((j-1+grid)%grid); nodes[2] = ((i-1+grid)%grid) * grid + j; nodes[3] = i * grid + ((j+1)%grid); MC_fill_structure(mc, *next_struct, 4, nodes); if (next_struct->num_neighbors != 10 + (has_extra_node ? 4 : 0)) abort(); ++next_struct; // |_ // | nodes[0] = i * grid + j; nodes[1] = ((i-1+grid)%grid) * grid + j; nodes[2] = i * grid + ((j+1)%grid); nodes[3] = ((i+1)%grid) * grid + j; MC_fill_structure(mc, *next_struct, 4, nodes); if (next_struct->num_neighbors != 10 + (has_extra_node ? 4 : 0)) abort(); ++next_struct; // _ _ // | nodes[0] = i * grid + j; nodes[1] = i * grid + ((j+1)%grid); nodes[2] = ((i+1)%grid) * grid + j; nodes[3] = i * grid + ((j-1+grid)%grid); MC_fill_structure(mc, *next_struct, 4, nodes); if (next_struct->num_neighbors != 10 + (has_extra_node ? 4 : 0)) abort(); ++next_struct; // _| // | nodes[0] = i * grid + j; nodes[1] = ((i+1)%grid) * grid + j; nodes[2] = i * grid + ((j-1+grid)%grid); nodes[3] = ((i-1+grid)%grid) * grid + j; MC_fill_structure(mc, *next_struct, 4, nodes); if (next_struct->num_neighbors != 10 + (has_extra_node ? 4 : 0)) abort(); ++next_struct; } } } //------------------------------------------------------------------------- // second { mc.num_switch_structures[2] = 4 * num_grid_nodes; mc.switch_structures[2] = new MC_switch_structure[4 * num_grid_nodes]; MC_switch_structure * next_struct = mc.switch_structures[2]; int nodes[4]; for (i = 0; i < grid; ++i) { for (j = 0; j < grid; ++j) { // _ // _| nodes[0] = i * grid + j; nodes[1] = i * grid + ((j+1)%grid); nodes[2] = ((i-1+grid)%grid) * grid + ((j+1)%grid); nodes[3] = ((i-1+grid)%grid) * grid + ((j+2)%grid); MC_fill_structure(mc, *next_struct, 4, nodes); if (next_struct->num_neighbors != 10 + (has_extra_node ? 4 : 0)) abort(); ++next_struct; // _ // |_ nodes[0] = i * grid + j; nodes[1] = i * grid + ((j+1)%grid); nodes[2] = ((i+1)%grid) * grid + ((j+1)%grid); nodes[3] = ((i+1)%grid) * grid + ((j+2)%grid); MC_fill_structure(mc, *next_struct, 4, nodes); if (next_struct->num_neighbors != 10 + (has_extra_node ? 4 : 0)) abort(); ++next_struct; // |_ // | nodes[0] = i * grid + j; nodes[1] = ((i+1)%grid) * grid + j; nodes[2] = ((i+1)%grid) * grid + ((j+1)%grid); nodes[3] = ((i+2)%grid) * grid + ((j+1)%grid); MC_fill_structure(mc, *next_struct, 4, nodes); if (next_struct->num_neighbors != 10 + (has_extra_node ? 4 : 0)) abort(); ++next_struct; // _| // | nodes[0] = i * grid + j; nodes[1] = ((i+1)%grid) * grid + j; nodes[2] = ((i+1)%grid) * grid + ((j-1+grid)%grid); nodes[3] = ((i+2)%grid) * grid + ((j-1+grid)%grid); MC_fill_structure(mc, *next_struct, 4, nodes); if (next_struct->num_neighbors != 10 + (has_extra_node ? 4 : 0)) abort(); ++next_struct; } } } //------------------------------------------------------------------------- // third { mc.num_switch_structures[3] = num_grid_nodes; mc.switch_structures[3] = new MC_switch_structure[num_grid_nodes]; MC_switch_structure * next_struct = mc.switch_structures[3]; int nodes[4]; for (i = 0; i < grid; ++i) { for (j = 0; j < grid; ++j) { // the square is (i,j), (i,j+1), (i+1,j+1), (i+1,j) // _ // |_| nodes[0] = i * grid + j; nodes[1] = i * grid + ((j+1)%grid); nodes[2] = ((i+1)%grid) * grid + ((j+1)%grid); nodes[3] = ((i+1)%grid) * grid + j; MC_fill_structure(mc, *next_struct, 4, nodes); if (next_struct->num_neighbors != 8 + (has_extra_node ? 4 : 0)) abort(); ++next_struct; } } } //========================================================================= // a 6-node connected structures { mc.num_switch_structures[4] = 2 * num_grid_nodes; mc.switch_structures[4] = new MC_switch_structure[2 * num_grid_nodes]; MC_switch_structure * next_struct = mc.switch_structures[4]; int nodes[6]; for (i = 0; i < grid; ++i) { for (j = 0; j < grid; ++j) { // _ _ // |_|_| nodes[0] = i * grid + j; nodes[1] = i * grid + ((j+1)%grid); nodes[2] = i * grid + ((j+2)%grid); nodes[3] = ((i+1)%grid) * grid + j; nodes[4] = ((i+1)%grid) * grid + ((j+1)%grid); nodes[5] = ((i+1)%grid) * grid + ((j+2)%grid); MC_fill_structure(mc, *next_struct, 6, nodes); if (next_struct->num_neighbors != 10 + (has_extra_node ? 6 : 0)) abort(); ++next_struct; // _ // |_| // |_| nodes[0] = i * grid + j; nodes[1] = i * grid + ((j+1)%grid); nodes[2] = ((i+1)%grid) * grid + j; nodes[3] = ((i+1)%grid) * grid + ((j+1)%grid); nodes[4] = ((i+2)%grid) * grid + j; nodes[5] = ((i+2)%grid) * grid + ((j+1)%grid); MC_fill_structure(mc, *next_struct, 6, nodes); if (next_struct->num_neighbors != 10 + (has_extra_node ? 6 : 0)) abort(); ++next_struct; } } } } if (tm.tm_par.entry(MC_tm_par::FeasSolFile).length() > 0) { std::ifstream solfile(tm.tm_par.entry(MC_tm_par::FeasSolFile).c_str()); if (! solfile) { throw BCP_fatal_error("Can't open feas solution file!\n"); } int* s = new int[mc.num_nodes]; for (i = 0; i < mc.num_nodes; ++i) { solfile.getline(line, 999); sscanf(line, "%i", s+i); } solfile.close(); mc.feas_sol = new MC_feas_sol(mc.num_nodes, s, mc.num_edges, mc.edges); printf("\nMC: value of input solution: %.0f\n\n", mc.feas_sol->cost); } }