Пример #1
0
/* 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;
}
Пример #2
0
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 );
}
Пример #3
0
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 );
}
Пример #4
0
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;
}