/*M/////////////////////////////////////////////////////////////////////////////////////// // // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. // // By downloading, copying, installing or using the software you agree to this license. // If you do not agree to this license, do not download, install, // copy or use the software. // // // Intel License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000, Intel Corporation, all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistribution's of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistribution's in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // * The name of Intel Corporation may not be used to endorse or promote products // derived from this software without specific prior written permission. // // This software is provided by the copyright holders and contributors "as is" and // any express or implied warranties, including, but not limited to, the implied // warranties of merchantability and fitness for a particular purpose are disclaimed. // In no event shall the Intel Corporation or contributors be liable for any direct, // indirect, incidental, special, exemplary, or consequential damages // (including, but not limited to, procurement of substitute goods or services; // loss of use, data, or profits; or business interruption) however caused // and on any theory of liability, whether in contract, strict liability, // or tort (including negligence or otherwise) arising in any way out of // the use of this software, even if advised of the possibility of such damage. // //M*/ #include "_cvaux.h" #if 0 #include <float.h> #include <limits.h> #include <stdio.h> #include "_cvutils.h" #include "_cvwrap.h" /*typedef struct CvCliqueFinder { CvGraph* graph; int** adj_matr; int N; //graph size // stacks, counters etc/ int k; //stack size int* current_comp; int** All; int* ne; int* ce; int* fixp; //node with minimal disconnections int* nod; int* s; //for selected candidate int status; int best_score; } CvCliqueFinder; */ #define GO 1 #define BACK 2 #define PEREBOR 3 #define NEXT PEREBOR #define END 4 #define CV_GET_ADJ_VTX( vertex, edge ) \ ( \ assert(edge->vtx[0]==vertex||edge->vtx[1] == vertex ), \ (edge->vtx[0] == vertex)?edge->vtx[1]:edge->vtx[0] \ ) #define NUMBER( v ) ((v)->flags >> 1 ) void _MarkNodes( CvGraph* graph ) { //set number of vertices to their flags for( int i = 0; i < graph->total; i++ ) { CvGraphVtx* ver = cvGetGraphVtx( graph, i ); if( ver ) { ver->flags = i<<1; } } } void _FillAdjMatrix( CvGraph* graph, int** connected, int reverse ) { //assume all vertices are marked for( int i = 0; i < graph->total; i++ ) { for( int j = 0; j < graph->total; j++ ) { connected[i][j] = 0|reverse; } //memset( connected[i], 0, sizeof(int)*graph->total ); CvGraphVtx* ver = cvGetGraphVtx( graph, i ); if( ver ) { connected[i][i] = 1; for( CvGraphEdge* e = ver->first; e ; e = CV_NEXT_GRAPH_EDGE( e, ver ) ) { CvGraphVtx* v = CV_GET_ADJ_VTX( ver, e ); connected[i][NUMBER(v)] = 1^reverse; } } } } void cvStartFindCliques( CvGraph* graph, CvCliqueFinder* finder, int reverse, int weighted, int weighted_edges ) { int i; if (weighted) { finder->weighted = 1; finder->best_weight = 0; finder->vertex_weights = (float*)malloc( sizeof(float)*(graph->total+1)); finder->cur_weight = (float*)malloc( sizeof(float)*(graph->total+1)); finder->cand_weight = (float*)malloc( sizeof(float)*(graph->total+1)); finder->cur_weight[0] = 0; finder->cand_weight[0] = 0; for( i = 0 ; i < graph->total; i++ ) { CvGraphWeightedVtx* ver = (CvGraphWeightedVtx*)cvGetGraphVtx( graph, i ); assert(ver); assert(ver->weight>=0); finder->vertex_weights[i] = ver->weight; finder->cand_weight[0] += ver->weight; } } else finder->weighted = 0; if (weighted_edges) { finder->weighted_edges = 1; //finder->best_weight = 0; finder->edge_weights = (float*)malloc( sizeof(float)*(graph->total)*(graph->total)); //finder->cur_weight = (float*)malloc( sizeof(float)*(graph->total+1)); //finder->cand_weight = (float*)malloc( sizeof(float)*(graph->total+1)); //finder->cur_weight[0] = 0; //finder->cand_weight[0] = 0; memset( finder->edge_weights, 0, sizeof(float)*(graph->total)*(graph->total) ); for( i = 0 ; i < graph->total; i++ ) { CvGraphVtx* ver1 = cvGetGraphVtx( graph, i ); if(!ver1) continue; for( int j = i ; j < graph->total; j++ ) { CvGraphVtx* ver2 = cvGetGraphVtx( graph, j ); if(!ver2) continue; CvGraphEdge* edge = cvFindGraphEdgeByPtr( graph, ver1, ver2 ); if( edge ) { assert( ((CvGraphWeightedEdge*)edge)->weight >= 0 ); finder->edge_weights[ i * graph->total + j ] = finder->edge_weights[ j * graph->total + i ] = ((CvGraphWeightedEdge*)edge)->weight; } } } } else finder->weighted_edges = 0; //int* Compsub; //current component (vertex stack) finder->k = 0; //counter of steps int N = finder->N = graph->total; finder->current_comp = new int[N]; finder->All = new int*[N]; for( i = 0 ; i < finder->N; i++ ) { finder->All[i] = new int[N]; } finder->ne = new int[N+1]; finder->ce = new int[N+1]; finder->fixp = new int[N+1]; //node with minimal disconnections finder->nod = new int[N+1]; finder->s = new int[N+1]; //for selected candidate //form adj matrix finder->adj_matr = new int*[N]; //assume filled with 0 for( i = 0 ; i < N; i++ ) { finder->adj_matr[i] = new int[N]; } //set number to vertices _MarkNodes( graph ); _FillAdjMatrix( graph, finder->adj_matr, reverse ); //init all arrays int k = finder->k = 0; //stack size memset( finder->All[k], 0, sizeof(int) * N ); for( i = 0; i < N; i++ ) finder->All[k][i] = i; finder->ne[0] = 0; finder->ce[0] = N; finder->status = GO; finder->best_score = 0; } void cvEndFindCliques( CvCliqueFinder* finder ) { int i; //int* Compsub; //current component (vertex stack) delete finder->current_comp; for( i = 0 ; i < finder->N; i++ ) { delete finder->All[i]; } delete finder->All; delete finder->ne; delete finder->ce; delete finder->fixp; //node with minimal disconnections delete finder->nod; delete finder->s; //for selected candidate //delete adj matrix for( i = 0 ; i < finder->N; i++ ) { delete finder->adj_matr[i]; } delete finder->adj_matr; if(finder->weighted) { free(finder->vertex_weights); free(finder->cur_weight); free(finder->cand_weight); } if(finder->weighted_edges) { free(finder->edge_weights); } } int cvFindNextMaximalClique( CvCliqueFinder* finder ) { int** connected = finder->adj_matr; // int N = finder->N; //graph size // stacks, counters etc/ int k = finder->k; //stack size int* Compsub = finder->current_comp; int** All = finder->All; int* ne = finder->ne; int* ce = finder->ce; int* fixp = finder->fixp; //node with minimal disconnections int* nod = finder->nod; int* s = finder->s; //for selected candidate //START while( k >= 0) { int* old = All[k]; switch(finder->status) { case GO://Forward step /* we have all sets and will choose fixed point */ { //check potential size of clique if( (!finder->weighted) && (k + ce[k] - ne[k] < finder->best_score) ) { finder->status = BACK; break; } //check potential weight if( finder->weighted && !finder->weighted_edges && finder->cur_weight[k] + finder->cand_weight[k] < finder->best_weight ) { finder->status = BACK; break; } int minnod = ce[k]; nod[k] = 0; //for every vertex of All determine counter value and choose minimum for( int i = 0; i < ce[k] && minnod != 0; i++) { int p = old[i]; //current point int count = 0; //counter int pos = 0; /* Count disconnections with candidates */ for (int j = ne[k]; j < ce[k] && (count < minnod); j++) { if ( !connected[p][old[j]] ) { count++; /* Save position of potential candidate */ pos = j; } } /* Test new minimum */ if (count < minnod) { fixp[k] = p; //set current point as fixed minnod = count; //new value for minnod if (i < ne[k]) //if current fixed point belongs to 'not' { s[k] = pos; //s - selected candidate } else { s[k] = i; //selected candidate is fixed point itself /* preincr */ nod[k] = 1; //nod is aux variable, 1 means fixp == s } } }//for nod[k] = minnod + nod[k]; finder->status = NEXT;//go to backtrackcycle } break; case NEXT: //here we will look for candidate to translate into not //s[k] now contains index of choosen candidate { int* new_ = All[k+1]; if( nod[k] != 0 ) { //swap selected and first candidate int i, p = old[s[k]]; old[s[k]] = old[ne[k]]; int sel = old[ne[k]] = p; int newne = 0; //fill new set 'not' for ( i = 0; i < ne[k]; i++) { if (connected[sel][old[i]]) { new_[newne] = old[i]; newne++; } } //fill new set 'candidate' int newce = newne; i++;//skip selected candidate float candweight = 0; for (; i < ce[k]; i++) { if (connected[sel][old[i]]) { new_[newce] = old[i]; if( finder->weighted ) candweight += finder->vertex_weights[old[i]]; newce++; } } nod[k]--; //add selected to stack Compsub[k] = sel; k++; assert( k <= finder->N ); if( finder->weighted ) { //update weights of current clique and candidates finder->cur_weight[k] = finder->cur_weight[k-1] + finder->vertex_weights[sel]; finder->cand_weight[k] = candweight; } if( finder->weighted_edges ) { //update total weight by edge weights float added = 0; for( int ind = 0; ind < k-1; ind++ ) { added += finder->edge_weights[ Compsub[ind] * finder->N + sel ]; } finder->cur_weight[k] += added; } //check if 'not' and 'cand' are both empty if( newce == 0 ) { finder->best_score = MAX(finder->best_score, k ); if( finder->weighted ) finder->best_weight = MAX( finder->best_weight, finder->cur_weight[k] ); /*FILE* file = fopen("cliques.txt", "a" ); for (int t=0; t<k; t++) { fprintf(file, "%d ", Compsub[t]); } fprintf(file, "\n"); fclose(file); */ //output new clique//************************ finder->status = BACK; finder->k = k; return CLIQUE_FOUND; } else //check nonempty set of candidates if( newne < newce ) { //go further ne[k] = newne; ce[k] = newce; finder->status = GO; break; } } else finder->status = BACK; } break; case BACK: { //decrease stack k--; old = All[k]; if( k < 0 ) break; //add to not ne[k]++; if( nod[k] > 0 ) { //select next candidate for( s[k] = ne[k]; s[k] < ce[k]; s[k]++ ) { if( !connected[fixp[k]][old[s[k]]]) break; } assert( s[k] < ce[k] ); finder->status = NEXT; } else finder->status = BACK; } break; case END: assert(0); } }//end while finder->status = END; return CLIQUE_END; } void cvBronKerbosch( CvGraph* graph ) { int* Compsub; //current component (vertex stack) int k = 0; //counter of steps int N = graph->total; int i; Compsub = new int[N]; int** All = new int*[N]; for( i = 0 ; i < N; i++ ) { All[i] = new int[N]; } int* ne = new int[N]; int* ce = new int[N]; int* fixp = new int[N]; //node with minimal disconnections int* nod = new int[N]; int* s = new int[N]; //for selected candidate //form adj matrix int** connected = new int*[N]; //assume filled with 0 for( i = 0 ; i < N; i++ ) { connected[i] = new int[N]; } //set number to vertices _MarkNodes( graph ); _FillAdjMatrix( graph, connected, 0 ); //init all arrays k = 0; //stack size memset( All[k], 0, sizeof(int) * N ); for( i = 0; i < N; i++ ) All[k][i] = i; ne[0] = 0; ce[0] = N; int status = GO; int best_score = 0; //START while( k >= 0) { int* old = All[k]; switch(status) { case GO://Forward step /* we have all sets and will choose fixed point */ { if( k + ce[k] - ne[k] < best_score ) { status = BACK; break; } int minnod = ce[k]; nod[k] = 0; //for every vertex of All determine counter value and choose minimum for( int i = 0; i < ce[k] && minnod != 0; i++) { int p = old[i]; //current point int count = 0; //counter int pos = 0; /* Count disconnections with candidates */ for (int j = ne[k]; j < ce[k] && (count < minnod); j++) { if ( !connected[p][old[j]] ) { count++; /* Save position of potential candidate */ pos = j; } } /* Test new minimum */ if (count < minnod) { fixp[k] = p; //set current point as fixed minnod = count; //new value for minnod if (i < ne[k]) //if current fixed point belongs to 'not' { s[k] = pos; //s - selected candidate } else { s[k] = i; //selected candidate is fixed point itself /* preincr */ nod[k] = 1; //nod is aux variable, 1 means fixp == s } } }//for nod[k] = minnod + nod[k]; status = NEXT;//go to backtrackcycle } break; case NEXT: //here we will look for candidate to translate into not //s[k] now contains index of choosen candidate { int* new_ = All[k+1]; if( nod[k] != 0 ) { //swap selected and first candidate int p = old[s[k]]; old[s[k]] = old[ne[k]]; int sel = old[ne[k]] = p; int newne = 0; //fill new set 'not' for ( i = 0; i < ne[k]; i++) { if (connected[sel][old[i]]) { new_[newne] = old[i]; newne++; } } //fill new set 'candidate' int newce = newne; i++;//skip selected candidate for (; i < ce[k]; i++) { if (connected[sel][old[i]]) { new_[newce] = old[i]; newce++; } } nod[k]--; //add selected to stack Compsub[k] = sel; k++; //check if 'not' and 'cand' are both empty if( newce == 0 ) { best_score = MAX(best_score, k ); FILE* file = fopen("cliques.txt", "a" ); for (int t=0; t<k; t++) { fprintf(file, "%d ", Compsub[t]); } fprintf(file, "\n"); fclose(file); /*for( int t = 0; t < k; t++ ) { printf("%d ", Compsub[t] ); } printf("\n"); */ //printf("found %d\n", k); //output new clique//************************ status = BACK; } else //check nonempty set of candidates if( newne < newce ) { //go further ne[k] = newne; ce[k] = newce; status = GO; break; } } else status = BACK; } break; case BACK: { //decrease stack k--; old = All[k]; if( k < 0 ) break; //add to not ne[k]++; if( nod[k] > 0 ) { //select next candidate for( s[k] = ne[k]; s[k] < ce[k]; s[k]++ ) { if( !connected[fixp[k]][old[s[k]]]) break; } assert( s[k] < ce[k] ); status = NEXT; } else status = BACK; } break; } }//end while }//end cvBronKerbosch #endif