/* 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 ); }
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; }
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_extend( CliqueExtender *clqe, const CGraph *cgraph, const IntSet *clique, const int weight, const CliqueExtendingMethod clqem ) { int result = 0; #ifdef DEBUG assert( (clqe) && (cgraph) && (clique) && ((vint_set_size(clique))) ); int en1, en2; if (!clq_validate( cgraph, vint_set_size(clique), vint_set_get_elements(clique), &en1, &en2 )) { fprintf( stderr, "ERROR clqe_extend : Nodes %d and %d are not in conflict.\n", en1, en2 ); exit( EXIT_FAILURE ); } #endif clqe->cgraph = cgraph; clqe_check_nodes_cap( clqe ); int nCandidates = clqe_get_best_candidates_clique_insertion( clqe, clique, clqem ); if (!nCandidates) goto TERMINATE; /* too many candidates, filtering */ if (nCandidates > (clqe->maxClqESize*2)) nCandidates = (clqe->maxClqESize*2); /* clique can be extended, starting to fill new clique */ memcpy( clqe->newClique, vint_set_get_elements( clique ), sizeof(int)*vint_set_size(clique) ); clqe->newCliqueSize = vint_set_size( clique ); int idxSelected = -1, selectedNode, i, removals; int *candidates = clqe->candidates; INSERT_CANDIDATE: if ( ( clqem == CLQEM_RANDOM ) || (clqe->costs == NULL) || (clqe->costsCap<cgraph_size(cgraph)) ) { idxSelected = ((int)((((double)rand()) / (((double)RAND_MAX)+1.0)) * ((double)nCandidates))); if ( clqem == CLQEM_PRIORITY_GREEDY ) fprintf( stderr, "Warning: using random selection for extension since no costs were informed.\n"); } else { /* costs informed, picking the one with the lowest cost */ int i, lowestCost = INT_MAX; for ( i=0 ; (i<nCandidates) ; ++i ) { if ( clqe->costs[ candidates[i] ] < lowestCost ) { lowestCost = clqe->costs[ candidates[i] ]; idxSelected = i; } } } #ifdef DEBUG assert( idxSelected >= 0 ); assert( idxSelected < nCandidates ); #endif selectedNode = candidates[ idxSelected ]; assert( selectedNode>=0 && selectedNode < cgraph_size(cgraph) ); clqe->newClique[ clqe->newCliqueSize++ ] = selectedNode; /* removing from candidates those which do not conflict with new inserted node */ removals = 0; for ( i=0 ; (i<nCandidates); ++i ) { if ( ( !cgraph_conflicting_nodes(cgraph, selectedNode, candidates[i] ) ) || (candidates[i]==selectedNode) ) { candidates[i] = INT_MAX; ++removals; } } qsort( candidates, nCandidates, sizeof(int), vint_set_cmp_int ); nCandidates -= removals; if ( ( nCandidates ) && (clqe->newCliqueSize<clqe->maxClqESize) ) goto INSERT_CANDIDATE; /* at this point we have an extended clique */ result += clq_set_add( clqe->clqSet, clqe->newCliqueSize, clqe->newClique, weight ); TERMINATE: /* { int n1, n2; int res = clq_validate( cgraph, clqe->newCliqueSize, clqe->newClique, &n1, &n2 ); assert(res); int i; printf("CLIQUE BEF ADD SIZE:\n"); for ( i=0 ; (i<clqe->newCliqueSize) ; ++i ) printf( "%d ", clqe->newClique[i] ); int sizeS = clq_set_clique_size( clqe->clqSet, clq_set_number_of_cliques(clqe->clqSet)-1 ); const int *el = clq_set_clique_elements( clqe->clqSet, clq_set_number_of_cliques(clqe->clqSet)-1 ); printf("\n-> -> CLIQUE BEF ADD SIZE: <- <-\n"); for ( i=0 ; (i<sizeS) ; ++i ) printf( "%d ", el[i] ); printf("\n"); } */ return result; }