/* enumerated all cliques containing nodes with a maximum degree. after the enumeration, these nodes can be safely removed from the graph returns how many node were enumerated */ int clq_sep_enum_all_cliques_low_degree_nodes( CliqueSeparation *sep, int iv[], const CGraph *ppGraph ) { int i; const int nodes = cgraph_size( ppGraph ); if (!nodes) return 0; CliqueEnumerator *clqEnum = sep->clqEnum; IntSet *neighs = &(sep->clqEnumNeighs); const int neighsCap = nodes*100; vint_set_check_capacity( neighs, neighsCap ); int *vneighs = vint_set_force_elements_access( neighs ); const int nCliquesBefore = clq_set_number_of_cliques( sep->clqSetOrig ); int removed = 0; clock_t start = clock(); for ( i=0 ; (i<nodes) ; i++ ) { if ( cgraph_degree( ppGraph, i ) <= sep->enumUsage ) { const int nodeNeighs = cgraph_get_all_conflicting( ppGraph, i, vneighs, neighsCap ); const int nodeWeight = cgraph_get_node_weight( ppGraph, i ); vint_set_force_size( neighs, nodeNeighs ); #ifdef DEBUG vint_set_force_check( neighs ); #endif if (neighs->size) { clq_enum_run( clqEnum, ppGraph, 1, &i, nodeWeight, neighs ); clq_set_add_using_original_indexes( sep->clqSetOrig, clq_enum_get_cliques( clqEnum ), cgraph_get_original_node_indexes( ppGraph ) ); } iv[ cgraph_get_original_node_index(ppGraph,i) ] = -1; ++removed; } } const int nCliquesAfter = clq_set_number_of_cliques( sep->clqSetOrig ); clock_t end = clock(); const double secs = (((double)end-start)/((double)CLOCKS_PER_SEC)); if (sep->verbose) { printf("Enumeration finished in %.3f seconds. Found %d violated cliques. Removed %d nodes from graph.\n", secs, nCliquesAfter-nCliquesBefore, removed ); fflush(stdout); fflush(stderr); } /* updating incidence vetor */ int idx = 0; const int nodesOrig = cgraph_size( sep->cgraph ); for ( i=0 ; (i<nodesOrig) ; ++i ) if ( iv[i] != -1 ) iv[i] = idx++; #ifdef DEBUG const CliqueSet *clqSet = sep->clqSetOrig; const int nCliques = clq_set_number_of_cliques( clqSet ); for ( i=0 ; (i<nCliques) ; ++i ) { const IntSet *clique = clq_set_get_clique( clqSet, i ); const int *el = vint_set_get_elements( clique ); const int cSize = vint_set_size( clique ); int n1,n2; if (!clq_validate( sep->cgraph, cSize, el, &n1, &n2 )) { fprintf( stderr, "Invalid clique found in enumeration. Nodes %d and %d are not neighbors.\n", n1, n2 ); exit( EXIT_FAILURE ); } } #endif return removed; }
void clq_sep_separate( CliqueSeparation *sep, const double x[] ) { const CGraph *cgraph = sep->cgraph; clq_set_clear( sep->clqSet ); clq_set_clear( sep->clqSetOrig ); clq_sep_check_node_cap( sep ); CliqueSet *clqSetOrig = sep->clqSetOrig; clq_set_clear( clqSetOrig ); /* before extension, orig indexes */ CliqueSet *clqSet = sep->clqSet; clq_set_clear( clqSet ); /* final clique set */ int *iv = sep->iv; const double minFrac = sep->minFrac; { IntQueue queue; int i, *neighs, csize = cgraph_size(cgraph); char inQueue[csize]; //'1' if a vertices is already in queue - '0' otherwise neighs = xmalloc(sizeof(int) * csize * 10); vint_queue_init(&queue, csize); for(i = 0; i < csize; i++) { if(cgraph_degree(cgraph, i) == 0) //deleting variables that are not binary { iv[i] = -1; inQueue[i] = '0'; //just to avoid memory problems } else if(cgraph_degree(cgraph, i) == 1 || fracPart(x[i]) < minFrac) { //integer variables and variables that have conflict only with their complements are deleted iv[i] = -1; vint_queue_push(&queue, i); inQueue[i] = '1'; } else { iv[i] = cgraph_degree(cgraph, i); inQueue[i] = '0'; } } while(!vint_queue_is_empty(&queue)) { int v; vint_queue_pop(&queue, &v); int nsize = cgraph_get_all_conflicting(cgraph, v, neighs, csize * 10); for(i = 0; i < nsize; i++) { int u = neighs[i]; if(iv[u] == -1) continue; assert(iv[u] > 0); iv[u]--; //considering v was deleted if(iv[u] == 0) { iv[u] = -1; if(inQueue[u] == '0') { vint_queue_push(&queue, u); inQueue[u] = '1'; } } } } int idx = 0; for(i = 0; i < csize; i++) if(iv[i] > 0) iv[i] = idx++; free(neighs); vint_queue_clean(&queue); } CGraph *ppcg = cgraph_create_induced_subgraph( cgraph, iv ); cgraph_set_low_degree( ppcg, sep->enumUsage ); clq_sep_update_ppgraph_weights( ppcg, cgraph_size(cgraph), x ); /* if enumeration is used, iv will be update*/ if (sep->verbose) cgraph_print_summary( ppcg, "pre-processed graph - part 1" ); /* separation works with integer weights */ const int minW = (int)(1000.0 + (sep->minViol*1000.0)); char enumerationComplete = 0; if ( sep->enumUsage > 0 ) { clq_enum_set_min_weight( sep->clqEnum, minW ); int enumNodes = clq_sep_enum_all_cliques_low_degree_nodes( sep, iv, ppcg ); if (enumNodes < cgraph_size(ppcg)) { /* more processing will be needed, creating a another preprocesses graph without already enumerated nodes */ cgraph_free( &ppcg ); ppcg = cgraph_create_induced_subgraph( cgraph, iv ); cgraph_set_low_degree( ppcg, sep->enumUsage ); clq_sep_update_ppgraph_weights( ppcg, cgraph_size(cgraph), x ); if (sep->verbose) cgraph_print_summary( ppcg, "pre-processed graph - part 2" ); } else { if (sep->verbose) printf("pre-processed graph - part 2 - no nodes left. all cliques have been enumerated.\n"); enumerationComplete = 1; } } int firstGraspClique = clq_set_number_of_cliques( clqSetOrig ); if ( (!enumerationComplete) && (cgraph_size(ppcg)>=2) ) { sep->bk = bk_create( ppcg ); clock_t startBK = clock(); int stillWorkToDo = bk_run( sep->bk, minW, sep->maxTimeBK ); clock_t endBK = clock(); if (sep->verbose) { printf("bk took %.3g seconds\n", ((double)endBK-startBK)/((double)CLOCKS_PER_SEC) ); } CliqueSet *bkClqSet = bk_get_clq_set(sep->bk); if (bkClqSet) { if (clq_set_number_of_cliques( bkClqSet )) { #ifdef DEBUG int nc = clq_set_number_of_cliques( bkClqSet ); int ic; for ( ic = 0 ; (ic<nc) ; ++ic ) { const IntSet *is = clq_set_get_clique( bkClqSet, ic ); int n1, n2; if (!clq_validate( ppcg, vint_set_size(is), vint_set_get_elements(is), &n1, &n2 )) { fprintf( stderr, "Nodes %d and %d are not in conflict in ppcg.\n", n1, n2 ); exit( EXIT_FAILURE ); } int j; for ( j=0 ; (j<vint_set_size(is)) ; ++j ) { const int vidx = vint_set_get_elements(is)[j]; assert( vidx >=0 ); assert( vidx < cgraph_size(ppcg) ); } } #endif clq_set_add_using_original_indexes( clqSetOrig, bkClqSet , cgraph_get_original_node_indexes( ppcg ) ); } } if (stillWorkToDo) { Grasp *grasp = grasp_create( ppcg, minW ); if (sep->verbose) { printf("running grasp\n"); } clock_t graspStart = clock(); grasp_run( grasp ); const CliqueSet *graspCliques = grasp_solution_set(grasp); /* before extension, pp indexes */ clq_set_add_using_original_indexes( clqSetOrig, graspCliques, cgraph_get_original_node_indexes( ppcg ) ); grasp_free( &grasp ); clock_t graspEnd = clock(); if (sep->verbose) { printf("grasp took %.3f seconds.\n", ((double)graspEnd-graspStart)/((double)CLOCKS_PER_SEC) ); } } bk_free( (sep->bk) ); sep->bk = NULL; } /* extending cliques */ vmg_adjust_vector_capacity( (void**)&(sep->extended), &(sep->extendedCap), clq_set_number_of_cliques(clqSetOrig), sizeof(char) ); char *extended = sep->extended; memset( extended, 0, sizeof(char)*clq_set_number_of_cliques( clqSetOrig ) ); /* since grasp ran in a restricted subgraph, cliques found may be dominated by the ones found in the enumeration phase, checking ... */ { int i; for ( i=firstGraspClique ; (i<clq_set_number_of_cliques(clqSetOrig)) ; ++i ) { const IntSet *graspClique = clq_set_get_clique( clqSetOrig, i ); int j; for ( j=0 ; (j<firstGraspClique) ; ++j ) if ( clq_dominates( clq_set_get_clique( clqSetOrig, j ), graspClique ) ) extended[i] = 1; } } if (sep->extendCliques) { clock_t startExtend = clock(); CliqueExtender *clqe = sep->clqe; CliqueExtendingMethod clqem = CLQEM_RANDOM; if (sep->hasCosts) { clqe_set_costs( clqe, sep->costs, cgraph_size(cgraph) ); clqem = CLQEM_PRIORITY_GREEDY; } int i; for ( i=0 ; (i<clq_set_number_of_cliques( clqSetOrig )) ; ++i ) if (!extended[i]) extended[i] = clqe_extend( clqe, cgraph, clq_set_get_clique(clqSetOrig,i), clq_set_weight(clqSetOrig,i), clqem ); /* adding all extended cliques */ clq_set_add_cliques( clqSet, clqe_get_cliques( clqe ) ); clock_t endExtend = clock(); const double timeExtend = ((double)endExtend-startExtend) / ((double)CLOCKS_PER_SEC); if (sep->verbose) { printf("clique extension took %.3f seconds.\n", timeExtend); } } /* adding cliques which were not extended */ { int i; for ( i=0 ; (i<clq_set_number_of_cliques(clqSetOrig)) ; ++i ) if ( !extended[i] ) clq_set_add( clqSet, clq_set_clique_size(clqSetOrig,i), clq_set_clique_elements(clqSetOrig,i), clq_set_weight(clqSetOrig,i) ); } /* need to be informed again next call */ sep->hasCosts = 0; cgraph_free( &ppcg ); }
void grasp_iteration( Grasp *grasp ) { const CGraph *cgraph = grasp->cgraph; grasp_select_alpha( grasp ); int nConflicts; int *conflicts = grasp->conflicts; grasp->cliqueSize = 0; grasp->cliqueWeight = 0; int nodeToEnter; grasp_fill_nodes_left( grasp ); if ( grasp->nNodesLeft == 0 ) return; assert( grasp->nNodesLeft ); INSERT_NODE_INTO_CLIQUE: grasp_build_candidate_list( grasp ); assert( grasp->nCandidates ); nodeToEnter = grasp_select_from_candidate_list( grasp ); assert( (nodeToEnter >= 0) && (nodeToEnter < cgraph_size(cgraph)) ); grasp->clique[ grasp->cliqueSize++ ] = nodeToEnter; grasp->cliqueWeight += grasp->w[nodeToEnter]; nConflicts = cgraph_get_all_conflicting( cgraph, nodeToEnter, conflicts, grasp->conflictsCap ); grasp_update_nodes_left( grasp, nConflicts, conflicts, nodeToEnter ); if ( grasp->nNodesLeft ) goto INSERT_NODE_INTO_CLIQUE; /* here we must have a maximal clique */ #ifdef DEBUG int *newNodes = xmalloc( cgraph_size(cgraph)*100 ); qsort( grasp->clique, grasp->cliqueSize, sizeof(int), vint_set_cmp_int ); int nodesToAdd = cgraph_get_candidates_clique_insertion( (CGraph*)cgraph, grasp->cliqueSize, grasp->clique, newNodes, cgraph_size(cgraph)*100 ); if (nodesToAdd) { fprintf( stderr, "ERROR: GRASP is generating non-maximal cliques.\n" ); fprintf( stderr, " clique being built: " ); { int i; for ( i=0 ; (i<grasp->cliqueSize) ; ++i ) fprintf( stderr, "%d ", grasp->clique[i] ); fprintf( stderr, "\n" ); } fprintf( stderr, " possible nodes for insertion: " ); { int i; for ( i=0 ; (i<nodesToAdd) ; ++i ) fprintf( stderr, "%d ", newNodes[i] ); fprintf( stderr, "\n" ); } exit( EXIT_FAILURE ); } free( newNodes ); #endif }
void clq_sep_separate( CliqueSeparation *sep, const double x[] ) { const CGraph *cgraph = sep->cgraph; clq_set_clear( sep->clqSet ); clq_set_clear( sep->clqSetOrig ); clq_sep_check_node_cap( sep ); CliqueSet *clqSetOrig = sep->clqSetOrig; clq_set_clear( clqSetOrig ); /* before extension, orig indexes */ CliqueSet *clqSet = sep->clqSet; clq_set_clear( clqSet ); /* final clique set */ int *iv = sep->iv; const double minFrac = sep->minFrac; { IntQueue queue; int i, *neighs, csize = cgraph_size(cgraph); char inQueue[csize]; //'1' if a vertices is already in queue - '0' otherwise neighs = xmalloc(sizeof(int) * csize * 10); vint_queue_init(&queue, csize); for(i = 0; i < csize; i++) { if(cgraph_degree(cgraph, i) == 0) //deleting variables that are not binary { iv[i] = -1; inQueue[i] = '0'; //just to avoid memory problems } else if(cgraph_degree(cgraph, i) == 1 || (fracPart(x[i]) < minFrac && x[i] < 0.99)) { //integer variables and variables that have conflict only with their complements are deleted iv[i] = -1; vint_queue_push(&queue, i); inQueue[i] = '1'; } else { iv[i] = cgraph_degree(cgraph, i); inQueue[i] = '0'; } } while(!vint_queue_is_empty(&queue)) { int v; vint_queue_pop(&queue, &v); int nsize = cgraph_get_all_conflicting(cgraph, v, neighs, csize * 10); for(i = 0; i < nsize; i++) { int u = neighs[i]; if(iv[u] == -1) continue; assert(iv[u] > 0); iv[u]--; //considering v was deleted if(iv[u] == 0) { iv[u] = -1; if(inQueue[u] == '0') { vint_queue_push(&queue, u); inQueue[u] = '1'; } } } } int idx = 0; for(i = 0; i < csize; i++) if(iv[i] > 0) iv[i] = idx++; free(neighs); vint_queue_clean(&queue); } CGraph *ppcg = cgraph_create_induced_subgraph( cgraph, iv ); clq_sep_update_ppgraph_weights( ppcg, cgraph_size(cgraph), x ); if (sep->verbose) cgraph_print_summary( ppcg, "pre-processed graph - part 1" ); /* separation works with integer weights */ const int minW = (int)(1000.0 + (sep->minViol*1000.0)); if(cgraph_size(ppcg)>=2) { sep->bk = bk_create( ppcg ); clock_t startBK = clock(); bk_set_max_it(sep->bk, sep->maxItBK); bk_set_min_weight(sep->bk, minW); bk_run( sep->bk ); clock_t endBK = clock(); if (sep->verbose) { printf("bk took %.3g seconds\n", ((double)endBK-startBK)/((double)CLOCKS_PER_SEC) ); } const CliqueSet *bkClqSet = bk_get_clq_set(sep->bk); if (bkClqSet) { if (clq_set_number_of_cliques( bkClqSet )) { #ifdef DEBUG int nc = clq_set_number_of_cliques( bkClqSet ); int ic; for ( ic = 0 ; (ic<nc) ; ++ic ) { const IntSet *is = clq_set_get_clique( bkClqSet, ic ); int n1, n2; if (!clq_validate( ppcg, vint_set_size(is), vint_set_get_elements(is), &n1, &n2 )) { fprintf( stderr, "Nodes %d and %d are not in conflict in ppcg.\n", n1, n2 ); exit( EXIT_FAILURE ); } int j; for ( j=0 ; (j<vint_set_size(is)) ; ++j ) { const int vidx = vint_set_get_elements(is)[j]; assert( vidx >=0 ); assert( vidx < cgraph_size(ppcg) ); } } #endif clq_set_add_using_original_indexes( clqSetOrig, bkClqSet , cgraph_get_original_node_indexes( ppcg ) ); } } bk_free( (sep->bk) ); sep->bk = NULL; } /* extending cliques */ vmg_adjust_vector_capacity( (void**)&(sep->extended), &(sep->extendedCap), clq_set_number_of_cliques(clqSetOrig), sizeof(char) ); char *extended = sep->extended; memset( extended, 0, sizeof(char)*clq_set_number_of_cliques( clqSetOrig ) ); if (sep->extendCliques) { clock_t startExtend = clock(); CliqueExtender *clqe = sep->clqe; if(sep->hasCosts) clqe_set_costs( clqe, sep->costs, cgraph_size(cgraph) ); int i; for ( i=0 ; (i<clq_set_number_of_cliques( clqSetOrig )) ; ++i ) extended[i] = clqe_extend( clqe, cgraph, clq_set_get_clique(clqSetOrig,i), clq_set_weight(clqSetOrig,i), sep->extendCliques ); /* adding all extended cliques */ clq_set_add_cliques( clqSet, clqe_get_cliques( clqe ) ); clock_t endExtend = clock(); const double timeExtend = ((double)endExtend-startExtend) / ((double)CLOCKS_PER_SEC); if (sep->verbose) { printf("clique extension took %.3f seconds.\n", timeExtend); } } /* adding cliques which were not extended */ { int i; for ( i=0 ; (i<clq_set_number_of_cliques(clqSetOrig)) ; ++i ) if ( !extended[i] ) clq_set_add( clqSet, clq_set_clique_size(clqSetOrig,i), clq_set_clique_elements(clqSetOrig,i), clq_set_weight(clqSetOrig,i) ); } /* need to be informed again next call */ sep->hasCosts = 0; cgraph_free( &ppcg ); }
int clqe_get_best_candidates_clique_insertion( CliqueExtender *clqe, const IntSet *clique, const CliqueExtendingMethod clqem ) { /* node with the smallest degree */ int nodeSD = -1, degree = INT_MAX, i; const int cliqueSize = vint_set_size( clique ), *cliqueEl = vint_set_get_elements( clique ); const CGraph *cgraph = clqe->cgraph; /* picking node with the smallest degree */ for ( i=0 ; (i<cliqueSize) ; ++i ) { if ( cgraph_degree( cgraph, cliqueEl[i] ) < degree ) { degree = cgraph_degree( cgraph, cliqueEl[i] ); nodeSD = cliqueEl[i]; } } int nCandidates = 0; int *candidates = clqe->candidates; assert(clqem == CLQEM_PRIORITY_GREEDY || clqem == CLQEM_RANDOM); if(clqem == CLQEM_PRIORITY_GREEDY) //clique extender method uses greedy selection (reduced cost) { const int *costs = clqe->costs; #ifdef DEBUG assert( costs ); int previousCost = INT_MIN; #endif NeighIterator *nit = clqe->nit; int selected = -1; nit_start( nit, cgraph, nodeSD, costs ); while ( ( (selected=nit_next(nit))!=INT_MAX ) && (nCandidates<clqe->maxClqESize) ) { #ifdef DEBUG int curCost = costs[selected]; assert( curCost>=previousCost ); previousCost = curCost; #endif /* need to have conflict with all nodes in clique an all others inserted */ for ( i=0 ; (i<cliqueSize) ; ++i ) if ( (!cgraph_conflicting_nodes( cgraph, cliqueEl[i], selected )) || (selected==cliqueEl[i]) ) break; if (i<cliqueSize) continue; for ( i=0 ; (i<nCandidates) ; ++i ) if (!cgraph_conflicting_nodes( cgraph, candidates[i], selected )) break; if (i<nCandidates) continue; candidates[nCandidates++] = selected; } } else //clique extender method uses random selection { int *neighs = xmalloc(sizeof(int) * cgraph_size(cgraph) * 2); int nConflicts = cgraph_get_all_conflicting( cgraph, nodeSD, neighs, cgraph_size(cgraph) * 2); int j, selected; if(nConflicts < clqe->maxClqESize) { for(i = 0; i < nConflicts; i++) { selected = neighs[i]; for(j = 0; j < cliqueSize; j++) if((!cgraph_conflicting_nodes(cgraph, cliqueEl[j], selected)) || (selected == cliqueEl[j])) break; if(j < cliqueSize) continue; for(j = 0; j < nCandidates; j++) if(!cgraph_conflicting_nodes(cgraph, candidates[j], selected)) break; if(j < nCandidates) continue; candidates[nCandidates++] = selected; } } else { int r, remaining = nConflicts; char *isSelected = xmalloc(sizeof(char) * nConflicts); memset(isSelected, 0, sizeof(char) * nConflicts); while(nCandidates < clqe->maxClqESize && remaining > 0) { do { r = rand() % nConflicts; selected = neighs[r]; } while(isSelected[r]); isSelected[r] = 1; remaining--; for(j = 0; j < cliqueSize; j++) if((!cgraph_conflicting_nodes(cgraph, cliqueEl[j], selected)) || (selected == cliqueEl[j])) break; if(j < cliqueSize) continue; for(j = 0; j < nCandidates; j++) if(!cgraph_conflicting_nodes(cgraph, candidates[j], selected)) break; if(j < nCandidates) continue; candidates[nCandidates++] = selected; } free(isSelected); } free(neighs); } return nCandidates; }