1/*M///////////////////////////////////////////////////////////////////////////////////////
2//
3//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4//
5//  By downloading, copying, installing or using the software you agree to this license.
6//  If you do not agree to this license, do not download, install,
7//  copy or use the software.
8//
9//
10//                        Intel License Agreement
11//                For Open Source Computer Vision Library
12//
13// Copyright (C) 2000, Intel Corporation, all rights reserved.
14// Third party copyrights are property of their respective owners.
15//
16// Redistribution and use in source and binary forms, with or without modification,
17// are permitted provided that the following conditions are met:
18//
19//   * Redistribution's of source code must retain the above copyright notice,
20//     this list of conditions and the following disclaimer.
21//
22//   * Redistribution's in binary form must reproduce the above copyright notice,
23//     this list of conditions and the following disclaimer in the documentation
24//     and/or other materials provided with the distribution.
25//
26//   * The name of Intel Corporation may not be used to endorse or promote products
27//     derived from this software without specific prior written permission.
28//
29// This software is provided by the copyright holders and contributors "as is" and
30// any express or implied warranties, including, but not limited to, the implied
31// warranties of merchantability and fitness for a particular purpose are disclaimed.
32// In no event shall the Intel Corporation or contributors be liable for any direct,
33// indirect, incidental, special, exemplary, or consequential damages
34// (including, but not limited to, procurement of substitute goods or services;
35// loss of use, data, or profits; or business interruption) however caused
36// and on any theory of liability, whether in contract, strict liability,
37// or tort (including negligence or otherwise) arising in any way out of
38// the use of this software, even if advised of the possibility of such damage.
39//
40//M*/
41
42#include "_cvaux.h"
43
44#if 0
45
46#include <float.h>
47#include <limits.h>
48#include <stdio.h>
49
50
51#include "_cvutils.h"
52#include "_cvwrap.h"
53
54/*typedef struct CvCliqueFinder
55{
56    CvGraph* graph;
57    int**    adj_matr;
58    int N; //graph size
59
60    // stacks, counters etc/
61    int k; //stack size
62    int* current_comp;
63    int** All;
64
65    int* ne;
66    int* ce;
67    int* fixp; //node with minimal disconnections
68    int* nod;
69    int* s; //for selected candidate
70    int status;
71    int best_score;
72
73} CvCliqueFinder;
74*/
75
76#define GO 1
77#define BACK 2
78#define PEREBOR 3
79#define NEXT PEREBOR
80#define END 4
81
82
83#define  CV_GET_ADJ_VTX( vertex, edge ) \
84(                                       \
85    assert(edge->vtx[0]==vertex||edge->vtx[1] == vertex ), \
86    (edge->vtx[0] == vertex)?edge->vtx[1]:edge->vtx[0]     \
87)
88
89
90#define NUMBER( v ) ((v)->flags >> 1 )
91
92void _MarkNodes( CvGraph* graph )
93{
94    //set number of vertices to their flags
95    for( int i = 0; i < graph->total; i++ )
96    {
97        CvGraphVtx* ver = cvGetGraphVtx( graph, i );
98        if( ver )
99        {
100            ver->flags = i<<1;
101        }
102    }
103}
104
105void _FillAdjMatrix( CvGraph* graph, int** connected, int reverse )
106{
107    //assume all vertices are marked
108    for( int i = 0; i < graph->total; i++ )
109    {
110        for( int j = 0; j < graph->total; j++ )
111        {
112            connected[i][j] = 0|reverse;
113        }
114        //memset( connected[i], 0, sizeof(int)*graph->total );
115        CvGraphVtx* ver = cvGetGraphVtx( graph, i );
116        if( ver )
117        {
118            connected[i][i] = 1;
119            for( CvGraphEdge* e = ver->first; e ; e = CV_NEXT_GRAPH_EDGE( e, ver ) )
120            {
121               CvGraphVtx* v = CV_GET_ADJ_VTX( ver, e );
122               connected[i][NUMBER(v)] = 1^reverse;
123            }
124        }
125    }
126}
127
128
129void cvStartFindCliques( CvGraph* graph, CvCliqueFinder* finder, int reverse, int weighted, int weighted_edges )
130{
131    int i;
132
133    if (weighted)
134    {
135        finder->weighted = 1;
136        finder->best_weight = 0;
137        finder->vertex_weights = (float*)malloc( sizeof(float)*(graph->total+1));
138        finder->cur_weight = (float*)malloc( sizeof(float)*(graph->total+1));
139        finder->cand_weight = (float*)malloc( sizeof(float)*(graph->total+1));
140
141        finder->cur_weight[0] = 0;
142        finder->cand_weight[0] = 0;
143        for( i = 0 ; i < graph->total; i++ )
144        {
145            CvGraphWeightedVtx* ver = (CvGraphWeightedVtx*)cvGetGraphVtx( graph, i );
146            assert(ver);
147            assert(ver->weight>=0);
148            finder->vertex_weights[i] = ver->weight;
149            finder->cand_weight[0] += ver->weight;
150        }
151    }
152    else finder->weighted = 0;
153
154    if (weighted_edges)
155    {
156        finder->weighted_edges = 1;
157        //finder->best_weight = 0;
158        finder->edge_weights = (float*)malloc( sizeof(float)*(graph->total)*(graph->total));
159        //finder->cur_weight = (float*)malloc( sizeof(float)*(graph->total+1));
160        //finder->cand_weight = (float*)malloc( sizeof(float)*(graph->total+1));
161
162        //finder->cur_weight[0] = 0;
163        //finder->cand_weight[0] = 0;
164        memset( finder->edge_weights, 0, sizeof(float)*(graph->total)*(graph->total) );
165        for( i = 0 ; i < graph->total; i++ )
166        {
167            CvGraphVtx* ver1 = cvGetGraphVtx( graph, i );
168            if(!ver1) continue;
169            for( int j = i ; j < graph->total; j++ )
170            {
171                CvGraphVtx* ver2 = cvGetGraphVtx( graph, j );
172                if(!ver2) continue;
173                CvGraphEdge* edge = cvFindGraphEdgeByPtr( graph, ver1, ver2 );
174                if( edge )
175                {
176                    assert( ((CvGraphWeightedEdge*)edge)->weight >= 0 );
177                    finder->edge_weights[ i * graph->total + j ] =
178                    finder->edge_weights[ j * graph->total + i ] = ((CvGraphWeightedEdge*)edge)->weight;
179                }
180            }
181        }
182    }
183    else finder->weighted_edges = 0;
184
185
186    //int* Compsub; //current component (vertex stack)
187    finder->k = 0; //counter of steps
188    int N = finder->N = graph->total;
189    finder->current_comp = new int[N];
190    finder->All = new int*[N];
191    for( i = 0 ; i < finder->N; i++ )
192    {
193        finder->All[i] = new int[N];
194    }
195
196    finder->ne = new int[N+1];
197    finder->ce = new int[N+1];
198    finder->fixp = new int[N+1]; //node with minimal disconnections
199    finder->nod = new int[N+1];
200    finder->s = new int[N+1]; //for selected candidate
201
202    //form adj matrix
203    finder->adj_matr = new int*[N]; //assume filled with 0
204    for( i = 0 ; i < N; i++ )
205    {
206        finder->adj_matr[i] = new int[N];
207    }
208
209    //set number to vertices
210    _MarkNodes( graph );
211    _FillAdjMatrix( graph, finder->adj_matr, reverse );
212
213    //init all arrays
214    int k = finder->k = 0; //stack size
215    memset( finder->All[k], 0, sizeof(int) * N );
216    for( i = 0; i < N; i++ )  finder->All[k][i] = i;
217    finder->ne[0] = 0;
218    finder->ce[0] = N;
219
220    finder->status = GO;
221    finder->best_score = 0;
222
223}
224
225void cvEndFindCliques( CvCliqueFinder* finder )
226{
227    int i;
228
229    //int* Compsub; //current component (vertex stack)
230    delete finder->current_comp;
231    for( i = 0 ; i < finder->N; i++ )
232    {
233        delete finder->All[i];
234    }
235    delete finder->All;
236
237    delete finder->ne;
238    delete finder->ce;
239    delete finder->fixp; //node with minimal disconnections
240    delete finder->nod;
241    delete finder->s; //for selected candidate
242
243    //delete adj matrix
244    for( i = 0 ; i < finder->N; i++ )
245    {
246        delete finder->adj_matr[i];
247    }
248    delete finder->adj_matr;
249
250    if(finder->weighted)
251    {
252        free(finder->vertex_weights);
253        free(finder->cur_weight);
254        free(finder->cand_weight);
255    }
256    if(finder->weighted_edges)
257    {
258        free(finder->edge_weights);
259    }
260}
261
262int cvFindNextMaximalClique( CvCliqueFinder* finder )
263{
264    int**  connected = finder->adj_matr;
265//    int N = finder->N; //graph size
266
267    // stacks, counters etc/
268    int k = finder->k; //stack size
269    int* Compsub = finder->current_comp;
270    int** All = finder->All;
271
272    int* ne = finder->ne;
273    int* ce = finder->ce;
274    int* fixp = finder->fixp; //node with minimal disconnections
275    int* nod = finder->nod;
276    int* s = finder->s; //for selected candidate
277
278    //START
279    while( k >= 0)
280    {
281        int* old = All[k];
282        switch(finder->status)
283        {
284        case GO://Forward step
285        /* we have all sets and will choose fixed point */
286            {
287                //check potential size of clique
288                if( (!finder->weighted) && (k + ce[k] - ne[k] < finder->best_score) )
289                {
290                    finder->status  = BACK;
291                    break;
292                }
293                //check potential weight
294                if( finder->weighted && !finder->weighted_edges &&
295                    finder->cur_weight[k] + finder->cand_weight[k] < finder->best_weight )
296                {
297                    finder->status  = BACK;
298                    break;
299                }
300
301                int minnod = ce[k];
302                nod[k] = 0;
303
304                //for every vertex of All determine counter value and choose minimum
305                for( int i = 0; i < ce[k] && minnod != 0; i++)
306                {
307                    int p = old[i]; //current point
308                    int count = 0;  //counter
309                    int pos = 0;
310
311                    /* Count disconnections with candidates */
312                    for (int j = ne[k]; j < ce[k] && (count < minnod); j++)
313                    {
314                        if ( !connected[p][old[j]] )
315                        {
316                            count++;
317                            /* Save position of potential candidate */
318                            pos = j;
319                        }
320                    }
321
322                    /* Test new minimum */
323                    if (count < minnod)
324                    {
325                        fixp[k] = p;     //set current point as fixed
326                        minnod = count;  //new value for minnod
327                        if (i < ne[k])      //if current fixed point belongs to 'not'
328                        {
329                            s[k] = pos;     //s - selected candidate
330                        }
331                        else
332                        {
333                            s[k] = i;        //selected candidate is fixed point itself
334                            /* preincr */
335                            nod[k] = 1;      //nod is aux variable, 1 means fixp == s
336                        }
337                    }
338                }//for
339
340                nod[k] = minnod + nod[k];
341                finder->status = NEXT;//go to backtrackcycle
342            }
343            break;
344        case NEXT:
345            //here we will look for candidate to translate into not
346            //s[k] now contains index of choosen candidate
347            {
348                int* new_ = All[k+1];
349                if( nod[k] != 0 )
350                {
351                    //swap selected and first candidate
352                    int i, p = old[s[k]];
353                    old[s[k]] = old[ne[k]];
354                    int sel = old[ne[k]] = p;
355
356                    int newne = 0;
357                    //fill new set 'not'
358                    for ( i = 0; i < ne[k]; i++)
359                    {
360                        if (connected[sel][old[i]])
361                        {
362                            new_[newne] = old[i];
363                            newne++;
364
365                        }
366                    }
367                    //fill new set 'candidate'
368                    int newce = newne;
369                    i++;//skip selected candidate
370
371                    float candweight = 0;
372
373                    for (; i < ce[k]; i++)
374                    {
375                        if (connected[sel][old[i]])
376                        {
377                            new_[newce] = old[i];
378
379                            if( finder->weighted )
380                                candweight += finder->vertex_weights[old[i]];
381
382                            newce++;
383                        }
384                    }
385
386                    nod[k]--;
387
388                    //add selected to stack
389                    Compsub[k] = sel;
390
391                    k++;
392                    assert( k <= finder->N );
393                    if( finder->weighted )
394                    {
395                        //update weights of current clique and candidates
396                        finder->cur_weight[k] = finder->cur_weight[k-1] + finder->vertex_weights[sel];
397                        finder->cand_weight[k] = candweight;
398                    }
399                    if( finder->weighted_edges )
400                    {
401                        //update total weight by edge weights
402                        float added = 0;
403                        for( int ind = 0; ind < k-1; ind++ )
404                        {
405                            added += finder->edge_weights[ Compsub[ind] * finder->N + sel ];
406                        }
407                        finder->cur_weight[k] += added;
408                    }
409
410                    //check if 'not' and 'cand' are both empty
411                    if( newce == 0 )
412                    {
413                        finder->best_score = MAX(finder->best_score, k );
414
415                        if( finder->weighted )
416                            finder->best_weight = MAX( finder->best_weight, finder->cur_weight[k] );
417                        /*FILE* file  = fopen("cliques.txt", "a" );
418
419                        for (int t=0; t<k; t++)
420                        {
421                          fprintf(file, "%d ", Compsub[t]);
422                        }
423                        fprintf(file, "\n");
424
425                        fclose(file);
426                        */
427
428                        //output new clique//************************
429                        finder->status = BACK;
430                        finder->k = k;
431
432                        return CLIQUE_FOUND;
433
434                    }
435                    else //check nonempty set of candidates
436                    if( newne < newce )
437                    {
438                        //go further
439                        ne[k] = newne;
440                        ce[k] = newce;
441                        finder->status  = GO;
442                        break;
443                    }
444
445                }
446                else
447                    finder->status  = BACK;
448
449            }
450            break;
451
452        case BACK:
453            {
454                //decrease stack
455                k--;
456                old = All[k];
457                if( k < 0 ) break;
458
459                //add to not
460                ne[k]++;
461
462                if( nod[k] > 0 )
463                {
464                    //select next candidate
465                    for( s[k] = ne[k]; s[k] < ce[k]; s[k]++ )
466                    {
467                        if( !connected[fixp[k]][old[s[k]]])
468                            break;
469                    }
470                    assert( s[k] < ce[k] );
471                    finder->status = NEXT;
472                }
473                else
474                    finder->status = BACK;
475
476            }
477            break;
478        case END: assert(0);
479
480        }
481    }//end while
482
483    finder->status = END;
484    return CLIQUE_END;
485}
486
487
488
489
490void cvBronKerbosch( CvGraph* graph )
491{
492    int* Compsub; //current component (vertex stack)
493    int k = 0; //counter of steps
494    int N = graph->total;
495    int i;
496    Compsub = new int[N];
497    int** All = new int*[N];
498    for( i = 0 ; i < N; i++ )
499    {
500        All[i] = new int[N];
501    }
502
503    int* ne = new int[N];
504    int* ce = new int[N];
505    int* fixp = new int[N]; //node with minimal disconnections
506    int* nod = new int[N];
507    int* s = new int[N]; //for selected candidate
508
509    //form adj matrix
510    int** connected = new int*[N]; //assume filled with 0
511    for( i = 0 ; i < N; i++ )
512    {
513        connected[i] = new int[N];
514    }
515
516
517
518    //set number to vertices
519    _MarkNodes( graph );
520    _FillAdjMatrix( graph, connected, 0 );
521
522    //init all arrays
523    k = 0; //stack size
524    memset( All[k], 0, sizeof(int) * N );
525    for( i = 0; i < N; i++ )  All[k][i] = i;
526    ne[0] = 0;
527    ce[0] = N;
528
529    int status = GO;
530    int best_score = 0;
531
532    //START
533    while( k >= 0)
534    {
535        int* old = All[k];
536        switch(status)
537        {
538        case GO://Forward step
539        /* we have all sets and will choose fixed point */
540            {
541
542                if( k + ce[k] - ne[k] < best_score )
543                {
544                    status  = BACK;
545                    break;
546                }
547
548                int minnod = ce[k];
549                nod[k] = 0;
550
551                //for every vertex of All determine counter value and choose minimum
552                for( int i = 0; i < ce[k] && minnod != 0; i++)
553                {
554                    int p = old[i]; //current point
555                    int count = 0;  //counter
556                    int pos = 0;
557
558                    /* Count disconnections with candidates */
559                    for (int j = ne[k]; j < ce[k] && (count < minnod); j++)
560                    {
561                        if ( !connected[p][old[j]] )
562                        {
563                            count++;
564                            /* Save position of potential candidate */
565                            pos = j;
566                        }
567                    }
568
569                    /* Test new minimum */
570                    if (count < minnod)
571                    {
572                        fixp[k] = p;     //set current point as fixed
573                        minnod = count;  //new value for minnod
574                        if (i < ne[k])      //if current fixed point belongs to 'not'
575                        {
576                            s[k] = pos;     //s - selected candidate
577                        }
578                        else
579                        {
580                            s[k] = i;        //selected candidate is fixed point itself
581                            /* preincr */
582                            nod[k] = 1;      //nod is aux variable, 1 means fixp == s
583                        }
584                    }
585                }//for
586
587                nod[k] = minnod + nod[k];
588                status = NEXT;//go to backtrackcycle
589            }
590            break;
591        case NEXT:
592            //here we will look for candidate to translate into not
593            //s[k] now contains index of choosen candidate
594            {
595                int* new_ = All[k+1];
596                if( nod[k] != 0 )
597                {
598                    //swap selected and first candidate
599                    int p = old[s[k]];
600                    old[s[k]] = old[ne[k]];
601                    int sel = old[ne[k]] = p;
602
603                    int newne = 0;
604                    //fill new set 'not'
605                    for ( i = 0; i < ne[k]; i++)
606                    {
607                        if (connected[sel][old[i]])
608                        {
609                            new_[newne] = old[i];
610                            newne++;
611
612                        }
613                    }
614                    //fill new set 'candidate'
615                    int newce = newne;
616                    i++;//skip selected candidate
617                    for (; i < ce[k]; i++)
618                    {
619                        if (connected[sel][old[i]])
620                        {
621                            new_[newce] = old[i];
622                            newce++;
623                        }
624                    }
625
626                    nod[k]--;
627
628                    //add selected to stack
629                    Compsub[k] = sel;
630                    k++;
631
632                    //check if 'not' and 'cand' are both empty
633                    if( newce == 0 )
634                    {
635                        best_score = MAX(best_score, k );
636
637                        FILE* file  = fopen("cliques.txt", "a" );
638
639                        for (int t=0; t<k; t++)
640                        {
641                          fprintf(file, "%d ", Compsub[t]);
642                        }
643                        fprintf(file, "\n");
644
645                        fclose(file);
646
647                        /*for( int t = 0; t < k; t++ )
648                        {
649                            printf("%d ", Compsub[t] );
650                        }
651                        printf("\n"); */
652
653                        //printf("found %d\n", k);
654
655                        //output new clique//************************
656                        status = BACK;
657                    }
658                    else //check nonempty set of candidates
659                    if( newne < newce )
660                    {
661                        //go further
662                        ne[k] = newne;
663                        ce[k] = newce;
664                        status  = GO;
665                        break;
666                    }
667
668                }
669                else
670                    status  = BACK;
671
672            }
673            break;
674
675        case BACK:
676            {
677                //decrease stack
678                k--;
679                old = All[k];
680                if( k < 0 ) break;
681
682                //add to not
683                ne[k]++;
684
685                if( nod[k] > 0 )
686                {
687                    //select next candidate
688                    for( s[k] = ne[k]; s[k] < ce[k]; s[k]++ )
689                    {
690                        if( !connected[fixp[k]][old[s[k]]])
691                            break;
692                    }
693                    assert( s[k] < ce[k] );
694                    status = NEXT;
695                }
696                else
697                    status = BACK;
698
699            }
700            break;
701
702
703        }
704    }//end while
705
706}//end cvBronKerbosch
707
708#endif
709
710