opencv/modules/legacy/src/clique.cpp

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