710 lines
22 KiB
C++
710 lines
22 KiB
C++
/*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 "precomp.hpp"
|
|
|
|
#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
|
|
|