1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
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.
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
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.
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.
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.
42 //////////////////////////////////////////////////////////////////////////////////////////
43 //////////////////// tests for operations on dynamic data structures /////////////////////
44 //////////////////////////////////////////////////////////////////////////////////////////
46 #include "cxcoretest.h"
48 /****************************************************************************************\
49 * simple sequence implementation *
50 \****************************************************************************************/
52 typedef struct CvTsSimpleSeq
62 static CvTsSimpleSeq* cvTsCreateSimpleSeq( int max_count, int elem_size )
64 CvTsSimpleSeq* seq = (CvTsSimpleSeq*)cvAlloc( sizeof(*seq) + max_count * elem_size );
65 seq->elem_size = elem_size;
66 seq->max_count = max_count;
68 seq->array = (schar*)(seq + 1);
73 static void cvTsReleaseSimpleSeq( CvTsSimpleSeq** seq )
79 static schar* cvTsSimpleSeqElem( CvTsSimpleSeq* seq, int index )
81 assert( 0 <= index && index < seq->count );
82 return seq->array + index * seq->elem_size;
86 static void cvTsClearSimpleSeq( CvTsSimpleSeq* seq )
92 static void cvTsSimpleSeqShiftAndCopy( CvTsSimpleSeq* seq, int from_idx, int to_idx, void* elem=0 )
94 int elem_size = seq->elem_size;
96 if( from_idx == to_idx )
98 assert( from_idx > to_idx && !elem || from_idx < to_idx && elem );
100 if( from_idx < seq->count )
102 memmove( seq->array + to_idx*elem_size, seq->array + from_idx*elem_size,
103 (seq->count - from_idx)*elem_size );
105 seq->count += to_idx - from_idx;
106 if( elem && to_idx > from_idx )
107 memcpy( seq->array + from_idx*elem_size, elem, (to_idx - from_idx)*elem_size );
110 static void cvTsSimpleSeqInvert( CvTsSimpleSeq* seq )
112 int i, k, len = seq->count, elem_size = seq->elem_size;
113 schar *data = seq->array, t;
115 for( i = 0; i < len/2; i++ )
117 schar* a = data + i*elem_size;
118 schar* b = data + (len - i - 1)*elem_size;
119 for( k = 0; k < elem_size; k++ )
120 CV_SWAP( a[k], b[k], t );
124 /****************************************************************************************\
125 * simple cvset implementation *
126 \****************************************************************************************/
128 typedef struct CvTsSimpleSet
131 int count, max_count;
139 static void cvTsClearSimpleSet( CvTsSimpleSet* set_header )
142 int elem_size = set_header->elem_size;
144 for( i = 0; i < set_header->max_count; i++ )
146 set_header->array[i*elem_size] = 0;
147 set_header->free_stack[i] = set_header->max_count - i - 1;
149 set_header->free_count = set_header->max_count;
150 set_header->count = 0;
154 static CvTsSimpleSet* cvTsCreateSimpleSet( int max_count, int elem_size )
156 CvTsSimpleSet* set_header = (CvTsSimpleSet*)cvAlloc( sizeof(*set_header) + max_count *
157 (elem_size + 1 + sizeof(int)));
158 set_header->elem_size = elem_size + 1;
159 set_header->max_count = max_count;
160 set_header->free_stack = (int*)(set_header + 1);
161 set_header->array = (schar*)(set_header->free_stack + max_count);
163 cvTsClearSimpleSet( set_header );
168 static void cvTsReleaseSimpleSet( CvTsSimpleSet** set_header )
170 cvFree( set_header );
174 static schar* cvTsSimpleSetFind( CvTsSimpleSet* set_header, int index )
176 int idx = index * set_header->elem_size;
177 assert( 0 <= index && index < set_header->max_count );
178 return set_header->array[idx] ? set_header->array + idx + 1 : 0;
182 static int cvTsSimpleSetAdd( CvTsSimpleSet* set_header, void* elem )
185 assert( set_header->free_count > 0 );
187 idx = set_header->free_stack[--set_header->free_count];
188 idx2 = idx * set_header->elem_size;
189 assert( set_header->array[idx2] == 0 );
190 set_header->array[idx2] = 1;
191 if( set_header->elem_size > 1 )
192 memcpy( set_header->array + idx2 + 1, elem, set_header->elem_size - 1 );
193 set_header->count = MAX( set_header->count, idx + 1 );
199 static void cvTsSimpleSetRemove( CvTsSimpleSet* set_header, int index )
201 assert( set_header->free_count < set_header->max_count &&
202 0 <= index && index < set_header->max_count );
203 assert( set_header->array[index * set_header->elem_size] == 1 );
205 set_header->free_stack[set_header->free_count++] = index;
206 set_header->array[index * set_header->elem_size] = 0;
210 /****************************************************************************************\
211 * simple graph implementation *
212 \****************************************************************************************/
214 typedef struct CvTsSimpleGraph
224 static void cvTsClearSimpleGraph( CvTsSimpleGraph* graph )
226 int max_vtx_count = graph->vtx->max_count;
227 cvTsClearSimpleSet( graph->vtx );
228 memset( graph->matrix, 0, max_vtx_count * max_vtx_count * graph->edge_size );
232 static CvTsSimpleGraph* cvTsCreateSimpleGraph( int max_vtx_count, int vtx_size,
233 int edge_size, int oriented )
235 CvTsSimpleGraph* graph;
237 assert( max_vtx_count > 1 && vtx_size >= 0 && edge_size >= 0 );
238 graph = (CvTsSimpleGraph*)cvAlloc( sizeof(*graph) +
239 max_vtx_count * max_vtx_count * (edge_size + 1));
240 graph->vtx = cvTsCreateSimpleSet( max_vtx_count, vtx_size );
241 graph->edge_size = edge_size + 1;
242 graph->matrix = (char*)(graph + 1);
243 graph->oriented = oriented;
245 cvTsClearSimpleGraph( graph );
250 static void cvTsReleaseSimpleGraph( CvTsSimpleGraph** graph )
254 cvTsReleaseSimpleSet( &(graph[0]->vtx) );
260 static int cvTsSimpleGraphAddVertex( CvTsSimpleGraph* graph, void* vertex )
262 return cvTsSimpleSetAdd( graph->vtx, vertex );
266 static void cvTsSimpleGraphRemoveVertex( CvTsSimpleGraph* graph, int index )
268 int i, max_vtx_count = graph->vtx->max_count;
269 int edge_size = graph->edge_size;
270 cvTsSimpleSetRemove( graph->vtx, index );
272 /* remove all the corresponding edges */
273 for( i = 0; i < max_vtx_count; i++ )
275 graph->matrix[(i*max_vtx_count + index)*edge_size] =
276 graph->matrix[(index*max_vtx_count + i)*edge_size] = 0;
281 static void cvTsSimpleGraphAddEdge( CvTsSimpleGraph* graph, int idx1, int idx2, void* edge )
283 int i, t, n = graph->oriented ? 1 : 2;
285 assert( cvTsSimpleSetFind( graph->vtx, idx1 ) &&
286 cvTsSimpleSetFind( graph->vtx, idx2 ));
288 for( i = 0; i < n; i++ )
290 int ofs = (idx1*graph->vtx->max_count + idx2)*graph->edge_size;
291 assert( graph->matrix[ofs] == 0 );
292 graph->matrix[ofs] = 1;
293 if( graph->edge_size > 1 )
294 memcpy( graph->matrix + ofs + 1, edge, graph->edge_size - 1 );
296 CV_SWAP( idx1, idx2, t );
301 static void cvTsSimpleGraphRemoveEdge( CvTsSimpleGraph* graph, int idx1, int idx2 )
303 int i, t, n = graph->oriented ? 1 : 2;
305 assert( cvTsSimpleSetFind( graph->vtx, idx1 ) &&
306 cvTsSimpleSetFind( graph->vtx, idx2 ));
308 for( i = 0; i < n; i++ )
310 int ofs = (idx1*graph->vtx->max_count + idx2)*graph->edge_size;
311 assert( graph->matrix[ofs] == 1 );
312 graph->matrix[ofs] = 0;
313 CV_SWAP( idx1, idx2, t );
318 static schar* cvTsSimpleGraphFindVertex( CvTsSimpleGraph* graph, int index )
320 return cvTsSimpleSetFind( graph->vtx, index );
324 static char* cvTsSimpleGraphFindEdge( CvTsSimpleGraph* graph, int idx1, int idx2 )
326 if( cvTsSimpleGraphFindVertex( graph, idx1 ) &&
327 cvTsSimpleGraphFindVertex( graph, idx2 ))
329 char* edge = graph->matrix + (idx1 * graph->vtx->max_count + idx2)*graph->edge_size;
330 if( edge[0] ) return edge + 1;
336 static int cvTsSimpleGraphVertexDegree( CvTsSimpleGraph* graph, int index )
339 int edge_size = graph->edge_size;
340 int max_vtx_count = graph->vtx->max_count;
341 assert( cvTsSimpleGraphFindVertex( graph, index ) != 0 );
343 for( i = 0; i < max_vtx_count; i++ )
345 count += graph->matrix[(i*max_vtx_count + index)*edge_size] +
346 graph->matrix[(index*max_vtx_count + i)*edge_size];
349 if( !graph->oriented )
351 assert( count % 2 == 0 );
358 ///////////////////////////////////// the tests //////////////////////////////////
360 #define CV_TS_SEQ_CHECK_CONDITION( expr, err_msg ) \
363 set_error_context( #expr, err_msg, cvFuncName ); \
364 ts->set_failed_test_info( CvTS::FAIL_INVALID_OUTPUT ); \
368 class CxCore_DynStructBaseTest : public CvTest
371 CxCore_DynStructBaseTest( const char* test_name, const char* test_funcs );
372 virtual ~CxCore_DynStructBaseTest();
373 int write_default_params(CvFileStorage* fs);
374 bool can_do_fast_forward();
378 int read_params( CvFileStorage* fs );
380 void set_error_context( const char* condition,
382 const char* func_name );
383 int test_seq_block_consistence( int _struct_idx, CvSeq* seq, int total );
384 void update_progressbar();
386 int struct_count, max_struct_size, iterations, generations;
387 int min_log_storage_block_size, max_log_storage_block_size;
388 int min_log_elem_size, max_log_elem_size;
389 int gen, struct_idx, iter;
393 void** cxcore_struct;
394 void** simple_struct;
395 CvMemStorage* storage;
399 CxCore_DynStructBaseTest::CxCore_DynStructBaseTest( const char* test_name, const char* test_funcs ):
400 CvTest( test_name, test_funcs )
403 max_struct_size = 2000;
404 min_log_storage_block_size = 7;
405 max_log_storage_block_size = 12;
406 min_log_elem_size = 0;
407 max_log_elem_size = 8;
409 iterations = max_struct_size*2;
410 gen = struct_idx = iter = -1;
419 CxCore_DynStructBaseTest::~CxCore_DynStructBaseTest()
425 void CxCore_DynStructBaseTest::run_func()
429 bool CxCore_DynStructBaseTest::can_do_fast_forward()
435 void CxCore_DynStructBaseTest::clear()
438 cvReleaseMemStorage( &storage );
439 cvFree( &cxcore_struct );
440 cvFree( &simple_struct );
444 int CxCore_DynStructBaseTest::write_default_params( CvFileStorage* fs )
446 write_param( fs, "struct_count", struct_count );
447 write_param( fs, "max_struct_size", max_struct_size );
448 write_param( fs, "generations", generations );
449 write_param( fs, "iterations", iterations );
450 write_param( fs, "min_log_storage_block_size", min_log_storage_block_size );
451 write_param( fs, "max_log_storage_block_size", max_log_storage_block_size );
452 write_param( fs, "min_log_elem_size", min_log_elem_size );
453 write_param( fs, "max_log_elem_size", max_log_elem_size );
458 int CxCore_DynStructBaseTest::read_params( CvFileStorage* fs )
460 int code = CvTest::read_params( fs );
461 double sqrt_scale = sqrt(ts->get_test_case_count_scale());
465 struct_count = cvReadInt( find_param( fs, "struct_count" ), struct_count );
466 max_struct_size = cvReadInt( find_param( fs, "max_struct_size" ), max_struct_size );
467 generations = cvReadInt( find_param( fs, "generations" ), generations );
468 iterations = cvReadInt( find_param( fs, "iterations" ), iterations );
469 generations = cvRound(generations*sqrt_scale);
470 iterations = cvRound(iterations*sqrt_scale);
472 min_log_storage_block_size = cvReadInt( find_param( fs, "min_log_storage_block_size" ),
473 min_log_storage_block_size );
474 max_log_storage_block_size = cvReadInt( find_param( fs, "max_log_storage_block_size" ),
475 max_log_storage_block_size );
476 min_log_elem_size = cvReadInt( find_param( fs, "min_log_elem_size" ), min_log_elem_size );
477 max_log_elem_size = cvReadInt( find_param( fs, "max_log_elem_size" ), max_log_elem_size );
479 struct_count = cvTsClipInt( struct_count, 1, 100 );
480 max_struct_size = cvTsClipInt( max_struct_size, 1, 1<<20 );
481 generations = cvTsClipInt( generations, 1, 100 );
482 iterations = cvTsClipInt( iterations, 100, 1<<20 );
484 min_log_storage_block_size = cvTsClipInt( min_log_storage_block_size, 7, 20 );
485 max_log_storage_block_size = cvTsClipInt( max_log_storage_block_size,
486 min_log_storage_block_size, 20 );
488 min_log_elem_size = cvTsClipInt( min_log_elem_size, 0, 8 );
489 max_log_elem_size = cvTsClipInt( max_log_elem_size, min_log_elem_size, 10 );
495 void CxCore_DynStructBaseTest::update_progressbar()
499 if( test_progress < 0 )
502 cpu_freq = cvGetTickFrequency();
503 start_time = cvGetTickCount();
506 t = cvGetTickCount();
507 test_progress = update_progress( test_progress, 0, 0, ((double)(t - start_time))/(cpu_freq*1000) );
511 void CxCore_DynStructBaseTest::set_error_context( const char* condition,
513 const char* func_name )
515 ts->printf( CvTS::LOG, "%s: %s\n(\"%s\" failed).\n"
516 "generation = %d, struct_idx = %d, iter = %d\n",
517 func_name, err_msg, condition, gen, struct_idx, iter );
518 ts->set_failed_test_info( CvTS::FAIL_INVALID_OUTPUT );
522 int CxCore_DynStructBaseTest::test_seq_block_consistence( int _struct_idx, CvSeq* seq, int total )
524 int sum = 0, code = -1;
525 CV_FUNCNAME( "CxCore_DynStructBaseTest::test_seq_block_consistence" );
527 struct_idx = _struct_idx;
531 CV_TS_SEQ_CHECK_CONDITION( seq != 0, "Null sequence pointer" );
535 CvSeqBlock* block = seq->first;
536 CvSeqBlock* prev_block = block->prev;
538 int delta_idx = seq->first->start_index;
542 CV_TS_SEQ_CHECK_CONDITION( sum == block->start_index - delta_idx &&
543 block->count > 0 && block->prev == prev_block &&
544 prev_block->next == block,
545 "sequence blocks are inconsistent" );
549 if( block == seq->first ) break;
552 CV_TS_SEQ_CHECK_CONDITION( block->prev->count * seq->elem_size +
553 block->prev->data <= seq->block_max,
554 "block->data or block_max pointer are incorrect" );
557 CV_TS_SEQ_CHECK_CONDITION( seq->total == sum && sum == total,
558 "total number of elements is incorrect" );
568 CxCore_DynStructBaseTest ds_test( "ds", "" );
570 /////////////////////////////////// sequence tests ////////////////////////////////////
572 class CxCore_SeqBaseTest : public CxCore_DynStructBaseTest
575 CxCore_SeqBaseTest( const char* test_name, const char* test_funcs );
580 int test_multi_create();
581 int test_get_seq_elem( int _struct_idx, int iters );
582 int test_get_seq_reading( int _struct_idx, int iters );
583 int test_seq_ops( int iters );
587 CxCore_SeqBaseTest::CxCore_SeqBaseTest( const char* test_name, const char* test_funcs ) :
588 CxCore_DynStructBaseTest( test_name, test_funcs )
593 void CxCore_SeqBaseTest::clear()
598 for( i = 0; i < struct_count; i++ )
599 cvTsReleaseSimpleSeq( (CvTsSimpleSeq**)&simple_struct[i] );
601 CxCore_DynStructBaseTest::clear();
605 int CxCore_SeqBaseTest::test_multi_create()
607 CvSeqWriter* writer = (CvSeqWriter*)cvStackAlloc( struct_count*sizeof(writer[0]) );
608 int* pos = (int*)cvStackAlloc( struct_count*sizeof(pos[0]) );
609 int* index = (int*)cvStackAlloc( struct_count*sizeof(index[0]) );
610 int i, cur_count, elem_size;
612 CvRNG* rng = ts->get_rng();
614 CV_FUNCNAME( "CxCore_SeqBaseTest::test_multi_create" );
618 for( i = 0; i < struct_count; i++ )
627 t = cvTsRandReal(rng)*(max_log_elem_size - min_log_elem_size) + min_log_elem_size;
628 elem_size = cvRound( exp(t * CV_LOG2) );
629 elem_size = MIN( elem_size, (int)(storage->block_size - sizeof(void*) -
630 sizeof(CvSeqBlock) - sizeof(CvMemBlock)) );
632 cvTsReleaseSimpleSeq( (CvTsSimpleSeq**)&simple_struct[i] );
633 simple_struct[i] = sseq = cvTsCreateSimpleSeq( max_struct_size, elem_size );
634 cxcore_struct[i] = 0;
635 sseq->count = cvTsRandInt( rng ) % max_struct_size;
636 m = cvMat( 1, MAX(sseq->count,1)*elem_size, CV_8UC1, sseq->array );
637 cvRandArr( rng, &m, CV_RAND_UNI, cvScalarAll(0), cvScalarAll(256) );
640 for( cur_count = struct_count; cur_count > 0; cur_count-- )
644 int k = cvTsRandInt( rng ) % cur_count;
645 struct_idx = index[k];
646 CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[struct_idx];
648 if( pos[struct_idx] < 0 )
650 int hdr_size = (cvTsRandInt(rng) % 10)*4 + sizeof(CvSeq);
651 hdr_size = MIN( hdr_size, (int)(storage->block_size - sizeof(CvMemBlock)) );
652 elem_size = sseq->elem_size;
654 if( cvTsRandInt(rng) % 2 )
656 CV_CALL( cvStartWriteSeq( 0, hdr_size, elem_size, storage, writer + struct_idx ));
661 CV_CALL( s = cvCreateSeq( 0, hdr_size, elem_size, storage ));
662 CV_CALL( cvStartAppendToSeq( s, writer + struct_idx ));
665 CV_CALL( cvSetSeqBlockSize( writer[struct_idx].seq, cvTsRandInt( rng ) % 10000 ));
669 update_progressbar();
670 if( pos[struct_idx] == sseq->count )
672 CV_CALL( cxcore_struct[struct_idx] = cvEndWriteSeq( writer + struct_idx ));
674 for( ; k < cur_count-1; k++ )
675 index[k] = index[k+1];
680 schar* el = cvTsSimpleSeqElem( sseq, pos[struct_idx] );
681 CV_WRITE_SEQ_ELEM_VAR( el, writer[struct_idx] );
695 int CxCore_SeqBaseTest::test_get_seq_elem( int _struct_idx, int iters )
698 CvRNG* rng = ts->get_rng();
700 CV_FUNCNAME( "CxCore_SeqBaseTest::test_get_seq_elem" );
704 CvSeq* seq = (CvSeq*)cxcore_struct[_struct_idx];
705 CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[_struct_idx];
706 struct_idx = _struct_idx;
708 assert( seq->total == sseq->count );
710 if( sseq->count == 0 )
713 for( i = 0; i < iters; i++ )
715 int idx = cvTsRandInt(rng) % (sseq->count*3) - sseq->count*3/2;
716 int idx0 = (unsigned)idx < (unsigned)(sseq->count) ? idx : idx < 0 ?
717 idx + sseq->count : idx - sseq->count;
718 int bad_range = (unsigned)idx0 >= (unsigned)(sseq->count);
720 CV_CALL( elem = cvGetSeqElem( seq, idx ));
724 CV_TS_SEQ_CHECK_CONDITION( elem == 0,
725 "cvGetSeqElem doesn't "
726 "handle \"out of range\" properly" );
730 CV_TS_SEQ_CHECK_CONDITION( elem != 0 &&
731 !memcmp( elem, cvTsSimpleSeqElem(sseq, idx0), sseq->elem_size ),
732 "cvGetSeqElem returns wrong element" );
734 CV_CALL( idx = cvSeqElemIdx(seq, elem ));
735 CV_TS_SEQ_CHECK_CONDITION( idx >= 0 && idx == idx0,
736 "cvSeqElemIdx is incorrect" );
748 int CxCore_SeqBaseTest::test_get_seq_reading( int _struct_idx, int iters )
750 const int max_val = 3*5 + 2;
752 CvSeq* seq = (CvSeq*)cxcore_struct[_struct_idx];
753 CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[_struct_idx];
754 int total = seq->total;
755 CvRNG* rng = ts->get_rng();
759 CV_FUNCNAME( "CxCore_SeqBaseTest::test_get_seq_reading" );
763 assert( total == sseq->count );
764 this->struct_idx = _struct_idx;
765 elem = (schar*)alloca( sseq->elem_size );
767 pos = cvTsRandInt(rng) % 2;
768 CV_CALL( cvStartReadSeq( seq, &reader, pos ));
772 CV_TS_SEQ_CHECK_CONDITION( reader.ptr == 0, "Empty sequence reader pointer is not NULL" );
777 pos = pos ? seq->total - 1 : 0;
779 CV_TS_SEQ_CHECK_CONDITION( pos == cvGetSeqReaderPos(&reader),
780 "initial reader position is wrong" );
782 for( iter = 0; iter < iters; iter++ )
784 int op = cvTsRandInt(rng) % max_val;
786 if( op >= max_val - 2 )
788 int new_pos, new_pos0;
790 int is_relative = op == max_val - 1;
792 new_pos = cvTsRandInt(rng) % (total*2) - total;
793 new_pos0 = new_pos + (is_relative ? pos : 0 );
795 if( new_pos0 < 0 ) new_pos0 += total;
796 if( new_pos0 >= total ) new_pos0 -= total;
798 bad_range = (unsigned)new_pos0 >= (unsigned)total;
799 CV_CALL( cvSetSeqReaderPos( &reader, new_pos, is_relative ));
803 CV_TS_SEQ_CHECK_CONDITION( new_pos0 == cvGetSeqReaderPos( &reader ),
804 "cvset reader position doesn't work" );
809 CV_TS_SEQ_CHECK_CONDITION( pos == cvGetSeqReaderPos( &reader ),
810 "reader doesn't stay at the current position after wrong positioning" );
815 int direction = (op % 3) - 1;
816 memcpy( elem, reader.ptr, sseq->elem_size );
820 CV_NEXT_SEQ_ELEM( sseq->elem_size, reader );
822 else if( direction < 0 )
824 CV_PREV_SEQ_ELEM( sseq->elem_size, reader );
827 CV_TS_SEQ_CHECK_CONDITION( memcmp(elem, cvTsSimpleSeqElem(sseq, pos),
828 sseq->elem_size) == 0, "reading is incorrect" );
830 if( pos < 0 ) pos += total;
831 if( pos >= total ) pos -= total;
833 CV_TS_SEQ_CHECK_CONDITION( pos == cvGetSeqReaderPos( &reader ),
834 "reader doesn't move correctly after reading" );
846 int CxCore_SeqBaseTest::test_seq_ops( int iters )
848 const int max_op = 14;
850 int max_elem_size = 0;
851 schar *elem = 0, *elem2 = 0;
853 CvRNG* rng = ts->get_rng();
855 CV_FUNCNAME( "CxCore_SeqBaseTest::test_seq_ops" );
859 for( i = 0; i < struct_count; i++ )
860 max_elem_size = MAX( max_elem_size, ((CvSeq*)cxcore_struct[i])->elem_size );
862 CV_CALL( elem_mat = cvCreateMat( 1, max_struct_size*max_elem_size, CV_8UC1 ));
863 elem = (schar*)elem_mat->data.ptr;
865 for( iter = 0; iter < iters; iter++ )
867 struct_idx = cvTsRandInt(rng) % struct_count;
868 int op = cvTsRandInt(rng) % max_op;
869 CvSeq* seq = (CvSeq*)cxcore_struct[struct_idx];
870 CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[struct_idx];
871 int elem_size = sseq->elem_size;
872 int whence = 0, pos = 0, count = 0;
878 case 2: // push/pushfront/insert
879 if( sseq->count == sseq->max_count )
882 elem_mat->cols = elem_size;
883 cvRandArr( rng, elem_mat, CV_RAND_UNI, cvScalarAll(0), cvScalarAll(255) );
889 CV_CALL(cvSeqPushFront( seq, elem ));
891 else if( whence > 0 )
894 CV_CALL(cvSeqPush( seq, elem ));
898 pos = cvTsRandInt(rng) % (sseq->count + 1);
899 CV_CALL(cvSeqInsert( seq, pos, elem ));
902 cvTsSimpleSeqShiftAndCopy( sseq, pos, pos + 1, elem );
903 elem2 = cvGetSeqElem( seq, pos );
904 CV_TS_SEQ_CHECK_CONDITION( elem2 != 0, "The inserted element could not be retrieved" );
905 CV_TS_SEQ_CHECK_CONDITION( seq->total == sseq->count &&
906 memcmp(elem2, cvTsSimpleSeqElem(sseq,pos), elem_size) == 0,
907 "The inserted sequence element is wrong" );
912 case 5: // pop/popfront/remove
913 if( sseq->count == 0 )
920 CV_CALL( cvSeqPopFront( seq, elem ));
922 else if( whence > 0 )
925 CV_CALL( cvSeqPop( seq, elem ));
929 pos = cvTsRandInt(rng) % sseq->count;
930 CV_CALL( cvSeqRemove( seq, pos ));
934 CV_TS_SEQ_CHECK_CONDITION( seq->total == sseq->count - 1 &&
935 memcmp( elem, cvTsSimpleSeqElem(sseq,pos), elem_size) == 0,
936 "The popped sequence element isn't correct" );
938 cvTsSimpleSeqShiftAndCopy( sseq, pos + 1, pos );
940 if( sseq->count > 0 )
942 CV_CALL( elem2 = cvGetSeqElem( seq, pos < sseq->count ? pos : -1 ));
943 CV_TS_SEQ_CHECK_CONDITION( elem2 != 0, "GetSeqElem fails after removing the element" );
945 CV_TS_SEQ_CHECK_CONDITION( memcmp( elem2,
946 cvTsSimpleSeqElem(sseq, pos - (pos == sseq->count)), elem_size) == 0,
947 "The first shifted element is not correct after removing another element" );
951 CV_TS_SEQ_CHECK_CONDITION( seq->first == 0,
952 "The sequence doesn't become empty after the final remove" );
958 case 8: // push [front] multi/insert slice
959 if( sseq->count == sseq->max_count )
962 count = cvTsRandInt( rng ) % (sseq->max_count - sseq->count + 1);
963 elem_mat->cols = MAX(count,1) * elem_size;
964 cvRandArr( rng, elem_mat, CV_RAND_UNI, cvScalarAll(0), cvScalarAll(255) );
967 pos = whence < 0 ? 0 : whence > 0 ? sseq->count : cvTsRandInt(rng) % (sseq->count+1);
970 CV_CALL( cvSeqPushMulti( seq, elem, count, whence < 0 ));
976 CV_CALL( cvMakeSeqHeaderForArray( CV_SEQ_KIND_GENERIC, sizeof(CvSeq),
978 elem_mat->data.ptr, count,
981 CV_CALL( cvSeqInsertSlice( seq, pos, &header ));
983 cvTsSimpleSeqShiftAndCopy( sseq, pos, pos + count, elem );
985 if( sseq->count > 0 )
987 // choose the random element among the added
988 pos = count > 0 ? cvTsRandInt(rng) % count + pos : MAX(pos-1,0);
989 CV_CALL( elem2 = cvGetSeqElem( seq, pos ));
990 CV_TS_SEQ_CHECK_CONDITION( elem2 != 0, "multi push operation doesn't add elements" );
991 CV_TS_SEQ_CHECK_CONDITION( seq->total == sseq->count &&
992 memcmp( elem2, cvTsSimpleSeqElem(sseq,pos), elem_size) == 0,
993 "One of the added elements is wrong" );
997 CV_TS_SEQ_CHECK_CONDITION( seq->total == 0 && seq->first == 0,
998 "Adding no elements to empty sequence fails" );
1004 case 11: // pop [front] multi
1005 if( sseq->count == 0 )
1008 count = cvTsRandInt(rng) % (sseq->count+1);
1010 pos = whence < 0 ? 0 : whence > 0 ? sseq->count - count :
1011 cvTsRandInt(rng) % (sseq->count - count + 1);
1015 CV_CALL( cvSeqPopMulti( seq, elem, count, whence < 0 ));
1019 CV_TS_SEQ_CHECK_CONDITION( memcmp(elem,
1020 cvTsSimpleSeqElem(sseq,pos), elem_size) == 0,
1021 "The first (in the sequence order) removed element is wrong after popmulti" );
1026 CV_CALL( cvSeqRemoveSlice( seq, cvSlice(pos, pos + count) ));
1029 CV_TS_SEQ_CHECK_CONDITION( seq->total == sseq->count - count,
1030 "The popmulti left a wrong number of elements in the sequence" );
1032 cvTsSimpleSeqShiftAndCopy( sseq, pos + count, pos, 0 );
1033 if( sseq->count > 0 )
1035 pos = whence < 0 ? 0 : MIN( pos, sseq->count - 1 );
1036 elem2 = cvGetSeqElem( seq, pos );
1037 CV_TS_SEQ_CHECK_CONDITION( elem2 &&
1038 memcmp( elem2, cvTsSimpleSeqElem(sseq,pos), elem_size) == 0,
1039 "The last sequence element is wrong after POP" );
1043 CV_TS_SEQ_CHECK_CONDITION( seq->total == 0 && seq->first == 0,
1044 "The sequence doesn't become empty after final POP" );
1047 case 12: // seqslice
1049 CvMemStoragePos storage_pos;
1050 cvSaveMemStoragePos( storage, &storage_pos );
1052 int copy_data = cvTsRandInt(rng) % 2;
1053 count = cvTsRandInt(rng) % (seq->total + 1);
1054 pos = cvTsRandInt(rng) % (seq->total - count + 1);
1055 CvSeq* seq_slice = cvSeqSlice( seq, cvSlice(pos, pos + count), storage, copy_data );
1057 CV_TS_SEQ_CHECK_CONDITION( seq_slice && seq_slice->total == count,
1058 "cvSeqSlice returned incorrect slice" );
1062 int test_idx = cvTsRandInt(rng) % count;
1063 elem2 = cvGetSeqElem( seq_slice, test_idx );
1064 schar* elem3 = cvGetSeqElem( seq, pos + test_idx );
1065 CV_TS_SEQ_CHECK_CONDITION( elem2 &&
1066 memcmp( elem2, cvTsSimpleSeqElem(sseq,pos + test_idx), elem_size) == 0,
1067 "The extracted slice elements are not correct" );
1068 CV_TS_SEQ_CHECK_CONDITION( (elem2 == elem3) ^ copy_data,
1069 "copy_data flag is handled incorrectly" );
1072 cvRestoreMemStoragePos( storage, &storage_pos );
1076 cvTsClearSimpleSeq( sseq );
1078 CV_TS_SEQ_CHECK_CONDITION( seq->total == 0 && seq->first == 0,
1079 "The sequence doesn't become empty after clear" );
1086 if( test_seq_block_consistence(struct_idx, seq, sseq->count) < 0 )
1089 if( test_get_seq_elem(struct_idx, 7) < 0 )
1092 update_progressbar();
1100 elem_mat->cols = 1; // just to skip a consistency check
1101 cvReleaseMat( &elem_mat );
1107 void CxCore_SeqBaseTest::run( int )
1109 CvRNG* rng = ts->get_rng();
1113 //CV_FUNCNAME( "CxCore_SeqBaseTest::run" );
1120 simple_struct = (void**)cvAlloc( struct_count * sizeof(simple_struct[0]) );
1121 memset( simple_struct, 0, struct_count * sizeof(simple_struct[0]) );
1122 cxcore_struct = (void**)cvAlloc( struct_count * sizeof(cxcore_struct[0]) );
1123 memset( cxcore_struct, 0, struct_count * sizeof(cxcore_struct[0]) );
1125 for( gen = 0; gen < generations; gen++ )
1127 struct_idx = iter = -1;
1131 t = cvTsRandReal(rng)*(max_log_storage_block_size - min_log_storage_block_size)
1132 + min_log_storage_block_size;
1133 storage = cvCreateMemStorage( cvRound( exp(t * CV_LOG2) ) );
1136 iter = struct_idx = -1;
1137 test_multi_create();
1139 for( i = 0; i < struct_count; i++ )
1141 if( test_seq_block_consistence(i, (CvSeq*)cxcore_struct[i],
1142 ((CvTsSimpleSeq*)simple_struct[i])->count) < 0 )
1145 if( test_get_seq_elem( i, MAX(iterations/3,7) ) < 0 )
1148 if( test_get_seq_reading( i, MAX(iterations/3,7) ) < 0 )
1150 update_progressbar();
1153 if( test_seq_ops( iterations ) < 0 )
1156 if( cvTsRandInt(rng) % 2 )
1157 cvReleaseMemStorage( &storage );
1159 cvClearMemStorage( storage );
1165 CxCore_SeqBaseTest seqbase_test( "ds-seq-base", "cvCreateSeq, cvClearSeq, cvSeqSlice, "
1166 "cvStartAppendToSeq, cvStartWriteSeq, cvEndWriteSeq, CV_WRITE_SEQ_ELEM_VAR, "
1167 "cvGetSeqElem, cvSeqElemIdx, cvStartReadSeq, CV_NEXT_SEQ_ELEM, CV_PREV_SEQ_ELEM, "
1168 "cvSetSeqReaderPos, cvGetSeqReaderPos, cvSeqPush, cvSeqPushFront, cvSeqPop, "
1169 "cvSeqPopFront, cvSeqPushMulti, cvSeqPopMulti, cvSeqInsert, cvSeqRemove, "
1170 "cvSeqInsertSlice, cvSeqRemoveSlice, cvMakeSeqHeaderForArray" );
1172 ////////////////////////////// more sequence tests //////////////////////////////////////
1174 class CxCore_SeqSortInvTest : public CxCore_SeqBaseTest
1177 CxCore_SeqSortInvTest( const char* test_name, const char* test_funcs );
1184 CxCore_SeqSortInvTest::CxCore_SeqSortInvTest( const char* test_name, const char* test_funcs ) :
1185 CxCore_SeqBaseTest( test_name, test_funcs )
1190 static int icvCmpSeqElems( const void* a, const void* b, void* userdata )
1192 return memcmp( a, b, ((CvSeq*)userdata)->elem_size );
1195 static int icvCmpSeqElems2_elem_size = 0;
1196 static int icvCmpSeqElems2( const void* a, const void* b )
1198 return memcmp( a, b, icvCmpSeqElems2_elem_size );
1202 void CxCore_SeqSortInvTest::run( int )
1204 CvRNG* rng = ts->get_rng();
1207 schar *elem0, *elem, *elem2;
1210 CV_FUNCNAME( "CxCore_SeqSortInvTest::run" );
1217 simple_struct = (void**)cvAlloc( struct_count * sizeof(simple_struct[0]) );
1218 memset( simple_struct, 0, struct_count * sizeof(simple_struct[0]) );
1219 cxcore_struct = (void**)cvAlloc( struct_count * sizeof(cxcore_struct[0]) );
1220 memset( cxcore_struct, 0, struct_count * sizeof(cxcore_struct[0]) );
1222 for( gen = 0; gen < generations; gen++ )
1224 struct_idx = iter = -1;
1228 t = cvTsRandReal(rng)*(max_log_storage_block_size - min_log_storage_block_size)
1229 + min_log_storage_block_size;
1230 storage = cvCreateMemStorage( cvRound( exp(t * CV_LOG2) ) );
1233 for( iter = 0; iter < iterations/10; iter++ )
1236 test_multi_create();
1238 for( i = 0; i < struct_count; i++ )
1240 CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[i];
1241 max_size = MAX( max_size, sseq->count*sseq->elem_size );
1244 if( !buffer || buffer->cols < max_size )
1246 cvReleaseMat( &buffer );
1247 CV_CALL( buffer = cvCreateMat( 1, max_size, CV_8UC1 ));
1250 for( i = 0; i < struct_count; i++ )
1252 CvSeq* seq = (CvSeq*)cxcore_struct[i];
1253 CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[i];
1254 CvSlice slice = CV_WHOLE_SEQ;
1256 //printf("%d. %d. %d-th size = %d\n", gen, iter, i, sseq->count );
1258 CV_CALL( cvSeqInvert( seq ));
1259 cvTsSimpleSeqInvert( sseq );
1261 if( test_seq_block_consistence( i, seq, sseq->count ) < 0 )
1264 if( sseq->count > 0 && cvTsRandInt(rng) % 2 == 0 )
1266 slice.end_index = cvTsRandInt(rng) % sseq->count + 1;
1267 slice.start_index = cvTsRandInt(rng) % (sseq->count - slice.end_index + 1);
1268 slice.end_index += slice.start_index;
1271 CV_CALL( cvCvtSeqToArray( seq, buffer->data.ptr, slice ));
1273 slice.end_index = MIN( slice.end_index, sseq->count );
1274 CV_TS_SEQ_CHECK_CONDITION( sseq->count == 0 || memcmp( buffer->data.ptr,
1275 sseq->array + slice.start_index*sseq->elem_size,
1276 (slice.end_index - slice.start_index)*sseq->elem_size ) == 0,
1277 "cvSeqInvert returned wrong result" );
1279 for( k = 0; k < (sseq->count > 0 ? 10 : 0); k++ )
1281 int idx0 = cvTsRandInt(rng) % sseq->count, idx = 0;
1282 CV_CALL( elem0 = cvTsSimpleSeqElem( sseq, idx0 ));
1283 CV_CALL( elem = cvGetSeqElem( seq, idx0 ));
1284 elem2 = cvSeqSearch( seq, elem0, k % 2 ? icvCmpSeqElems : 0, 0, &idx, seq );
1286 CV_TS_SEQ_CHECK_CONDITION( elem != 0 &&
1287 memcmp( elem0, elem, seq->elem_size ) == 0,
1288 "cvSeqInvert gives incorrect result" );
1289 CV_TS_SEQ_CHECK_CONDITION( elem2 != 0 &&
1290 memcmp( elem0, elem2, seq->elem_size ) == 0 &&
1291 elem2 == cvGetSeqElem( seq, idx ),
1292 "cvSeqSearch failed (linear search)" );
1295 CV_CALL( cvSeqSort( seq, icvCmpSeqElems, seq ));
1297 if( test_seq_block_consistence( i, seq, sseq->count ) < 0 )
1300 if( sseq->count > 0 )
1302 // !!! This is not thread-safe !!!
1303 icvCmpSeqElems2_elem_size = sseq->elem_size;
1304 qsort( sseq->array, sseq->count, sseq->elem_size, icvCmpSeqElems2 );
1306 if( cvTsRandInt(rng) % 2 == 0 )
1308 slice.end_index = cvTsRandInt(rng) % sseq->count + 1;
1309 slice.start_index = cvTsRandInt(rng) % (sseq->count - slice.end_index + 1);
1310 slice.end_index += slice.start_index;
1314 CV_CALL( cvCvtSeqToArray( seq, buffer->data.ptr, slice ));
1315 CV_TS_SEQ_CHECK_CONDITION( sseq->count == 0 || memcmp( buffer->data.ptr,
1316 sseq->array + slice.start_index*sseq->elem_size,
1317 (slice.end_index - slice.start_index)*sseq->elem_size ) == 0,
1318 "cvSeqSort returned wrong result" );
1320 for( k = 0; k < (sseq->count > 0 ? 10 : 0); k++ )
1322 int idx0 = cvTsRandInt(rng) % sseq->count, idx = 0;
1323 CV_CALL( elem0 = cvTsSimpleSeqElem( sseq, idx0 ));
1324 CV_CALL( elem = cvGetSeqElem( seq, idx0 ));
1325 elem2 = cvSeqSearch( seq, elem0, icvCmpSeqElems, 1, &idx, seq );
1327 CV_TS_SEQ_CHECK_CONDITION( elem != 0 &&
1328 memcmp( elem0, elem, seq->elem_size ) == 0,
1329 "cvSeqSort gives incorrect result" );
1330 CV_TS_SEQ_CHECK_CONDITION( elem2 != 0 &&
1331 memcmp( elem0, elem2, seq->elem_size ) == 0 &&
1332 elem2 == cvGetSeqElem( seq, idx ),
1333 "cvSeqSearch failed (binary search)" );
1337 cvClearMemStorage( storage );
1340 cvReleaseMemStorage( &storage );
1345 cvReleaseMat( &buffer );
1349 CxCore_SeqSortInvTest seqsortinv_test( "ds-seq-sortinv",
1350 "cvCreateSeq, cvStartAppendToSeq, cvStartWriteSeq, "
1351 "cvEndWriteSeq, CV_WRITE_SEQ_ELEM_VAR, "
1352 "cvSeqSort, cvSeqSearch, cvSeqInvert, "
1353 "cvCvtSeqToArray, cvGetSeqElem" );
1355 /////////////////////////////////////// set tests ///////////////////////////////////////
1357 class CxCore_SetTest : public CxCore_DynStructBaseTest
1365 //int test_seq_block_consistence( int struct_idx );
1366 int test_set_ops( int iters );
1370 CxCore_SetTest::CxCore_SetTest():
1371 CxCore_DynStructBaseTest( "ds-set", "cvCreateSet, cvClearSet, "
1372 "cvSetAdd, cvSetRemove, cvSetNew, cvSetRemoveByPtr, cvGetSetElem" )
1377 void CxCore_SetTest::clear()
1381 for( i = 0; i < struct_count; i++ )
1382 cvTsReleaseSimpleSet( (CvTsSimpleSet**)&simple_struct[i] );
1383 CxCore_DynStructBaseTest::clear();
1387 int CxCore_SetTest::test_set_ops( int iters )
1389 const int max_op = 4;
1391 int max_elem_size = 0;
1393 CvSetElem *elem = 0, *elem2 = 0, *elem3 = 0;
1394 schar* elem_data = 0;
1395 CvMat* elem_mat = 0;
1396 CvRNG* rng = ts->get_rng();
1397 //int max_active_count = 0, mean_active_count = 0;
1399 CV_FUNCNAME( "CxCore_SetTest::test_set_ops" );
1403 for( i = 0; i < struct_count; i++ )
1404 max_elem_size = MAX( max_elem_size, ((CvSeq*)cxcore_struct[i])->elem_size );
1406 CV_CALL( elem_mat = cvCreateMat( 1, max_elem_size, CV_8UC1 ));
1408 for( iter = 0; iter < iters; iter++ )
1410 struct_idx = cvTsRandInt(rng) % struct_count;
1412 CvSet* cvset = (CvSet*)cxcore_struct[struct_idx];
1413 CvTsSimpleSet* sset = (CvTsSimpleSet*)simple_struct[struct_idx];
1414 int pure_elem_size = sset->elem_size - 1;
1415 int prev_total = cvset->total, prev_count = cvset->active_count;
1416 int op = cvTsRandInt(rng) % (iter <= iters/10 ? 2 : max_op);
1417 int by_ptr = op % 2 == 0;
1418 CvSetElem* first_free = cvset->free_elems;
1419 CvSetElem* next_free = first_free ? first_free->next_free : 0;
1422 if( iter > iters/10 && cvTsRandInt(rng)%200 == 0 ) // clear set
1424 int prev_count = cvset->total;
1425 cvClearSet( cvset );
1426 cvTsClearSimpleSet( sset );
1428 CV_TS_SEQ_CHECK_CONDITION( cvset->active_count == 0 && cvset->total == 0 &&
1429 cvset->first == 0 && cvset->free_elems == 0 &&
1430 (cvset->free_blocks != 0 || prev_count == 0),
1431 "cvClearSet doesn't remove all the elements" );
1434 else if( op == 0 || op == 1 ) // add element
1436 if( sset->free_count == 0 )
1439 elem_mat->cols = cvset->elem_size;
1440 cvRandArr( rng, elem_mat, CV_RAND_UNI, cvScalarAll(0), cvScalarAll(255) );
1441 elem = (CvSetElem*)elem_mat->data.ptr;
1445 CV_CALL( elem2 = cvSetNew( cvset ));
1446 CV_TS_SEQ_CHECK_CONDITION( elem2 != 0, "cvSetNew returned NULL pointer" );
1450 pass_data = cvTsRandInt(rng) % 2;
1451 CV_CALL( idx = cvSetAdd( cvset, pass_data ? elem : 0, &elem2 ));
1452 CV_TS_SEQ_CHECK_CONDITION( elem2 != 0 && elem2->flags == idx,
1453 "cvSetAdd returned NULL pointer or a wrong index" );
1456 elem_data = (schar*)elem + sizeof(int);
1459 memcpy( (schar*)elem2 + sizeof(int), elem_data, pure_elem_size );
1462 idx0 = cvTsSimpleSetAdd( sset, elem_data );
1463 CV_CALL( elem3 = cvGetSetElem( cvset, idx ));
1465 CV_TS_SEQ_CHECK_CONDITION( CV_IS_SET_ELEM(elem3) &&
1466 idx == idx0 && elem3 == elem2 && (!pass_data ||
1467 memcmp( (char*)elem3 + sizeof(int), elem_data, pure_elem_size) == 0),
1468 "The added element is not correct" );
1470 CV_TS_SEQ_CHECK_CONDITION( (!first_free || elem3 == first_free) &&
1471 (!next_free || cvset->free_elems == next_free) &&
1472 cvset->active_count == prev_count + 1,
1473 "The free node list is modified incorrectly" );
1475 else if( op == 2 || op == 3 ) // remove element
1477 idx = cvTsRandInt(rng) % sset->max_count;
1479 if( sset->free_count == sset->max_count || idx >= sset->count )
1482 elem_data = cvTsSimpleSetFind(sset, idx);
1483 if( elem_data == 0 )
1486 CV_CALL( elem = cvGetSetElem( cvset, idx ));
1487 CV_TS_SEQ_CHECK_CONDITION( CV_IS_SET_ELEM(elem) && elem->flags == idx &&
1488 memcmp((char*)elem + sizeof(int), elem_data, pure_elem_size) == 0,
1489 "cvGetSetElem returned wrong element" );
1493 CV_CALL( cvSetRemoveByPtr( cvset, elem ));
1497 CV_CALL( cvSetRemove( cvset, idx ));
1500 cvTsSimpleSetRemove( sset, idx );
1502 CV_TS_SEQ_CHECK_CONDITION( !CV_IS_SET_ELEM(elem) && !cvGetSetElem(cvset, idx) &&
1503 (elem->flags & CV_SET_ELEM_IDX_MASK) == idx,
1504 "cvSetRemove[ByPtr] didn't release the element properly" );
1506 CV_TS_SEQ_CHECK_CONDITION( elem->next_free == first_free &&
1507 cvset->free_elems == elem &&
1508 cvset->active_count == prev_count - 1,
1509 "The free node list has not been updated properly" );
1512 //max_active_count = MAX( max_active_count, cvset->active_count );
1513 //mean_active_count += cvset->active_count;
1514 CV_TS_SEQ_CHECK_CONDITION( cvset->active_count == sset->max_count - sset->free_count &&
1515 cvset->total >= cvset->active_count &&
1516 (cvset->total == 0 || cvset->total >= prev_total),
1517 "The total number of cvset elements is not correct" );
1519 // CvSet and simple set do not neccessary have the same "total" (active & free) number,
1520 // so pass "set->total" to skip that check
1521 test_seq_block_consistence( struct_idx, (CvSeq*)cvset, cvset->total );
1522 update_progressbar();
1526 //ts->printf( CvTS::LOG, "\ngeneration %d. max_active_count = %d,\n\tmean_active_count = %d\n",
1527 // gen, max_active_count, mean_active_count/iters );
1532 elem_mat->cols = 1; // just to skip a consistency check
1533 cvReleaseMat( &elem_mat );
1539 void CxCore_SetTest::run( int )
1541 CvRNG* rng = ts->get_rng();
1545 CV_FUNCNAME( "CxCore_SetTest::run" );
1552 simple_struct = (void**)cvAlloc( struct_count * sizeof(simple_struct[0]) );
1553 memset( simple_struct, 0, struct_count * sizeof(simple_struct[0]) );
1554 cxcore_struct = (void**)cvAlloc( struct_count * sizeof(cxcore_struct[0]) );
1555 memset( cxcore_struct, 0, struct_count * sizeof(cxcore_struct[0]) );
1557 for( gen = 0; gen < generations; gen++ )
1559 struct_idx = iter = -1;
1560 t = cvTsRandReal(rng)*(max_log_storage_block_size - min_log_storage_block_size) + min_log_storage_block_size;
1561 storage = cvCreateMemStorage( cvRound( exp(t * CV_LOG2) ) );
1563 for( i = 0; i < struct_count; i++ )
1565 t = cvTsRandReal(rng)*(max_log_elem_size - min_log_elem_size) + min_log_elem_size;
1566 int pure_elem_size = cvRound( exp(t * CV_LOG2) );
1567 int elem_size = pure_elem_size + sizeof(int);
1568 elem_size = (elem_size + sizeof(size_t) - 1) & ~(sizeof(size_t)-1);
1569 elem_size = MAX( elem_size, (int)sizeof(CvSetElem) );
1570 elem_size = MIN( elem_size, (int)(storage->block_size - sizeof(void*) - sizeof(CvMemBlock) - sizeof(CvSeqBlock)) );
1571 pure_elem_size = MIN( pure_elem_size, elem_size-(int)sizeof(CvSetElem) );
1573 cvTsReleaseSimpleSet( (CvTsSimpleSet**)&simple_struct[i] );
1574 simple_struct[i] = cvTsCreateSimpleSet( max_struct_size, pure_elem_size );
1575 CV_CALL( cxcore_struct[i] = cvCreateSet( 0, sizeof(CvSet), elem_size, storage ));
1578 if( test_set_ops( iterations*100 ) < 0 )
1581 cvReleaseMemStorage( &storage );
1587 CxCore_SetTest set_test;
1590 /////////////////////////////////////// graph tests //////////////////////////////////
1592 class CxCore_GraphTest : public CxCore_DynStructBaseTest
1600 //int test_seq_block_consistence( int struct_idx );
1601 int test_graph_ops( int iters );
1605 CxCore_GraphTest::CxCore_GraphTest():
1606 CxCore_DynStructBaseTest( "ds-graph", "cvCreateGraph, cvClearGraph, "
1607 "cvGraphAddVtx, cvGraphRemoveVtx, cvGraphRemoveVtxByPtr, "
1608 "cvGraphAddEdge, cvGraphAddEdgeByPtr, "
1609 "cvGraphRemoveEdge, cvGraphRemoveEdgeByPtr, "
1610 "cvGraphVtxDegree, cvGraphVtxDegreeByPtr, "
1611 "cvGetGraphVtx, cvFindGraphEdge, cvFindGraphEdgeByPtr " )
1616 void CxCore_GraphTest::clear()
1620 for( i = 0; i < struct_count; i++ )
1621 cvTsReleaseSimpleGraph( (CvTsSimpleGraph**)&simple_struct[i] );
1622 CxCore_DynStructBaseTest::clear();
1626 int CxCore_GraphTest::test_graph_ops( int iters )
1628 const int max_op = 4;
1629 int i, k, code = -1;
1630 int max_elem_size = 0;
1632 CvGraphVtx *vtx = 0, *vtx2 = 0, *vtx3 = 0;
1633 CvGraphEdge* edge = 0, *edge2 = 0;
1634 CvMat* elem_mat = 0;
1635 CvRNG* rng = ts->get_rng();
1636 //int max_active_count = 0, mean_active_count = 0;
1638 CV_FUNCNAME( "CxCore_GraphTest::test_graph_ops" );
1642 for( i = 0; i < struct_count; i++ )
1644 CvGraph* graph = (CvGraph*)cxcore_struct[i];
1645 max_elem_size = MAX( max_elem_size, graph->elem_size );
1646 max_elem_size = MAX( max_elem_size, graph->edges->elem_size );
1649 CV_CALL( elem_mat = cvCreateMat( 1, max_elem_size, CV_8UC1 ));
1651 for( iter = 0; iter < iters; iter++ )
1653 struct_idx = cvTsRandInt(rng) % struct_count;
1654 CvGraph* graph = (CvGraph*)cxcore_struct[struct_idx];
1655 CvTsSimpleGraph* sgraph = (CvTsSimpleGraph*)simple_struct[struct_idx];
1656 CvSet* edges = graph->edges;
1659 int pure_vtx_size = sgraph->vtx->elem_size - 1,
1660 pure_edge_size = sgraph->edge_size - 1;
1661 int prev_vtx_total = graph->total,
1662 prev_edge_total = graph->edges->total,
1663 prev_vtx_count = graph->active_count,
1664 prev_edge_count = graph->edges->active_count;
1665 int op = cvTsRandInt(rng) % max_op;
1666 int pass_data = 0, vtx_degree0 = 0, vtx_degree = 0;
1667 CvSetElem *first_free, *next_free;
1669 if( cvTsRandInt(rng) % 200 == 0 ) // clear graph
1671 int prev_vtx_count = graph->total, prev_edge_count = graph->edges->total;
1673 cvClearGraph( graph );
1674 cvTsClearSimpleGraph( sgraph );
1676 CV_TS_SEQ_CHECK_CONDITION( graph->active_count == 0 && graph->total == 0 &&
1677 graph->first == 0 && graph->free_elems == 0 &&
1678 (graph->free_blocks != 0 || prev_vtx_count == 0),
1679 "The graph is not empty after clearing" );
1681 CV_TS_SEQ_CHECK_CONDITION( edges->active_count == 0 && edges->total == 0 &&
1682 edges->first == 0 && edges->free_elems == 0 &&
1683 (edges->free_blocks != 0 || prev_edge_count == 0),
1684 "The graph is not empty after clearing" );
1686 else if( op == 0 ) // add vertex
1688 if( sgraph->vtx->free_count == 0 )
1691 first_free = graph->free_elems;
1692 next_free = first_free ? first_free->next_free : 0;
1696 elem_mat->cols = graph->elem_size;
1697 cvRandArr( rng, elem_mat, CV_RAND_UNI, cvScalarAll(0), cvScalarAll(255) );
1700 vtx = (CvGraphVtx*)elem_mat->data.ptr;
1701 idx0 = cvTsSimpleGraphAddVertex( sgraph, vtx + 1 );
1703 pass_data = cvTsRandInt(rng) % 2;
1704 CV_CALL( idx = cvGraphAddVtx( graph, pass_data ? vtx : 0, &vtx2 ));
1706 if( !pass_data && pure_vtx_size > 0 )
1707 memcpy( vtx2 + 1, vtx + 1, pure_vtx_size );
1709 vtx3 = cvGetGraphVtx( graph, idx );
1711 CV_TS_SEQ_CHECK_CONDITION( CV_IS_SET_ELEM(vtx3) && vtx3->flags == idx &&
1712 vtx3->first == 0 || idx == idx0 && vtx3 == vtx2 &&
1713 (!pass_data || pure_vtx_size == 0 ||
1714 memcmp(vtx3 + 1, vtx + 1, pure_vtx_size) == 0),
1715 "The added element is not correct" );
1717 CV_TS_SEQ_CHECK_CONDITION( (!first_free || first_free == (CvSetElem*)vtx3) &&
1718 (!next_free || graph->free_elems == next_free) &&
1719 graph->active_count == prev_vtx_count + 1,
1720 "The free node list is modified incorrectly" );
1722 else if( op == 1 ) // remove vertex
1724 idx = cvTsRandInt(rng) % sgraph->vtx->max_count;
1725 if( sgraph->vtx->free_count == sgraph->vtx->max_count || idx >= sgraph->vtx->count )
1728 vtx_data = cvTsSimpleGraphFindVertex(sgraph, idx);
1732 vtx_degree0 = cvTsSimpleGraphVertexDegree( sgraph, idx );
1733 first_free = graph->free_elems;
1735 CV_CALL( vtx = cvGetGraphVtx( graph, idx ));
1736 CV_TS_SEQ_CHECK_CONDITION( CV_IS_SET_ELEM(vtx) && vtx->flags == idx &&
1737 (pure_vtx_size == 0 || memcmp( vtx + 1, vtx_data, pure_vtx_size) == 0),
1738 "cvGetGraphVtx returned wrong element" );
1740 if( cvTsRandInt(rng) % 2 )
1742 CV_CALL( vtx_degree = cvGraphVtxDegreeByPtr( graph, vtx ));
1743 CV_CALL( cvGraphRemoveVtxByPtr( graph, vtx ));
1747 CV_CALL( vtx_degree = cvGraphVtxDegree( graph, idx ));
1748 CV_CALL( cvGraphRemoveVtx( graph, idx ));
1751 cvTsSimpleGraphRemoveVertex( sgraph, idx );
1753 CV_TS_SEQ_CHECK_CONDITION( vtx_degree == vtx_degree0,
1754 "Number of incident edges is different in two graph representations" );
1756 CV_TS_SEQ_CHECK_CONDITION( !CV_IS_SET_ELEM(vtx) && !cvGetGraphVtx(graph, idx) &&
1757 (vtx->flags & CV_SET_ELEM_IDX_MASK) == idx,
1758 "cvGraphRemoveVtx[ByPtr] didn't release the vertex properly" );
1760 CV_TS_SEQ_CHECK_CONDITION( graph->edges->active_count == prev_edge_count - vtx_degree,
1761 "cvGraphRemoveVtx[ByPtr] didn't remove all the incident edges "
1762 "(or removed some extra)" );
1764 CV_TS_SEQ_CHECK_CONDITION( ((CvSetElem*)vtx)->next_free == first_free &&
1765 graph->free_elems == (CvSetElem*)vtx &&
1766 graph->active_count == prev_vtx_count - 1,
1767 "The free node list has not been updated properly" );
1769 else if( op == 2 ) // add edge
1771 int v_idx[2] = {0,0}, res = 0;
1772 int v_prev_degree[2] = {0,0}, v_degree[2] = {0,0};
1774 if( sgraph->vtx->free_count >= sgraph->vtx->max_count-1 )
1777 for( i = 0, k = 0; i < 10; i++ )
1779 int j = cvTsRandInt(rng) % sgraph->vtx->count;
1780 vtx_data = cvTsSimpleGraphFindVertex( sgraph, j );
1786 else if( v_idx[0] != v_idx[1] &&
1787 cvTsSimpleGraphFindEdge( sgraph, v_idx[0], v_idx[1] ) == 0 )
1798 first_free = graph->edges->free_elems;
1799 next_free = first_free ? first_free->next_free : 0;
1801 CV_CALL( edge = cvFindGraphEdge( graph, v_idx[0], v_idx[1] ));
1802 CV_TS_SEQ_CHECK_CONDITION( edge == 0, "Extra edge appeared in the graph" );
1804 if( pure_edge_size > 0 )
1806 elem_mat->cols = graph->edges->elem_size;
1807 cvRandArr( rng, elem_mat, CV_RAND_UNI, cvScalarAll(0), cvScalarAll(255) );
1809 edge = (CvGraphEdge*)elem_mat->data.ptr;
1811 // assign some default weight that is easy to check for
1812 // consistensy, 'cause an edge weight is not stored
1813 // in the simple graph
1814 edge->weight = (float)(v_idx[0] + v_idx[1]);
1815 pass_data = cvTsRandInt(rng) % 2;
1817 CV_CALL( vtx = cvGetGraphVtx( graph, v_idx[0] ));
1818 CV_CALL( vtx2 = cvGetGraphVtx( graph, v_idx[1] ));
1819 CV_TS_SEQ_CHECK_CONDITION( vtx != 0 && vtx2 != 0 && vtx->flags == v_idx[0] &&
1820 vtx2->flags == v_idx[1], "Some of the vertices are missing" );
1822 if( cvTsRandInt(rng) % 2 )
1824 CV_CALL( v_prev_degree[0] = cvGraphVtxDegreeByPtr( graph, vtx ));
1825 CV_CALL( v_prev_degree[1] = cvGraphVtxDegreeByPtr( graph, vtx2 ));
1826 CV_CALL( res = cvGraphAddEdgeByPtr(graph, vtx, vtx2, pass_data ? edge : 0, &edge2));
1827 CV_CALL( v_degree[0] = cvGraphVtxDegreeByPtr( graph, vtx ));
1828 CV_CALL( v_degree[1] = cvGraphVtxDegreeByPtr( graph, vtx2 ));
1832 CV_CALL( v_prev_degree[0] = cvGraphVtxDegree( graph, v_idx[0] ));
1833 CV_CALL( v_prev_degree[1] = cvGraphVtxDegree( graph, v_idx[1] ));
1834 CV_CALL( res = cvGraphAddEdge(graph, v_idx[0], v_idx[1], pass_data ? edge : 0, &edge2));
1835 CV_CALL( v_degree[0] = cvGraphVtxDegree( graph, v_idx[0] ));
1836 CV_CALL( v_degree[1] = cvGraphVtxDegree( graph, v_idx[1] ));
1839 //edge3 = (CvGraphEdge*)cvGetSetElem( graph->edges, idx );
1840 CV_TS_SEQ_CHECK_CONDITION( res == 1 && edge2 != 0 && CV_IS_SET_ELEM(edge2) &&
1841 (edge2->vtx[0] == vtx && edge2->vtx[1] == vtx2 ||
1842 !CV_IS_GRAPH_ORIENTED(graph) && edge2->vtx[0] == vtx2 && edge2->vtx[1] == vtx) &&
1843 (!pass_data || pure_edge_size == 0 || memcmp( edge2 + 1, edge + 1, pure_edge_size ) == 0),
1844 "The edge has been added incorrectly" );
1848 if( pure_edge_size > 0 )
1849 memcpy( edge2 + 1, edge + 1, pure_edge_size );
1850 edge2->weight = edge->weight;
1853 CV_TS_SEQ_CHECK_CONDITION( v_degree[0] == v_prev_degree[0] + 1 &&
1854 v_degree[1] == v_prev_degree[1] + 1,
1855 "The vertices lists have not been updated properly" );
1857 cvTsSimpleGraphAddEdge( sgraph, v_idx[0], v_idx[1], edge + 1 );
1859 CV_TS_SEQ_CHECK_CONDITION( (!first_free || first_free == (CvSetElem*)edge2) &&
1860 (!next_free || graph->edges->free_elems == next_free) &&
1861 graph->edges->active_count == prev_edge_count + 1,
1862 "The free node list is modified incorrectly" );
1864 else if( op == 3 ) // find & remove edge
1866 int v_idx[2] = {0,0}, by_ptr;
1867 int v_prev_degree[2] = {0,0}, v_degree[2] = {0,0};
1869 if( sgraph->vtx->free_count >= sgraph->vtx->max_count-1 )
1873 for( i = 0, k = 0; i < 10; i++ )
1875 int j = cvTsRandInt(rng) % sgraph->vtx->count;
1876 vtx_data = cvTsSimpleGraphFindVertex( sgraph, j );
1884 edge_data = cvTsSimpleGraphFindEdge( sgraph, v_idx[0], v_idx[1] );
1897 by_ptr = cvTsRandInt(rng) % 2;
1898 first_free = graph->edges->free_elems;
1900 CV_CALL( vtx = cvGetGraphVtx( graph, v_idx[0] ));
1901 CV_CALL( vtx2 = cvGetGraphVtx( graph, v_idx[1] ));
1902 CV_TS_SEQ_CHECK_CONDITION( vtx != 0 && vtx2 != 0 && vtx->flags == v_idx[0] &&
1903 vtx2->flags == v_idx[1], "Some of the vertices are missing" );
1907 CV_CALL( edge = cvFindGraphEdgeByPtr( graph, vtx, vtx2 ));
1908 CV_CALL( v_prev_degree[0] = cvGraphVtxDegreeByPtr( graph, vtx ));
1909 CV_CALL( v_prev_degree[1] = cvGraphVtxDegreeByPtr( graph, vtx2 ));
1913 CV_CALL( edge = cvFindGraphEdge( graph, v_idx[0], v_idx[1] ));
1914 CV_CALL( v_prev_degree[0] = cvGraphVtxDegree( graph, v_idx[0] ));
1915 CV_CALL( v_prev_degree[1] = cvGraphVtxDegree( graph, v_idx[1] ));
1920 CV_TS_SEQ_CHECK_CONDITION( edge != 0 && edge->weight == v_idx[0] + v_idx[1] &&
1921 (edge->vtx[0] == vtx && edge->vtx[1] == vtx2 ||
1922 !CV_IS_GRAPH_ORIENTED(graph) && edge->vtx[1] == vtx && edge->vtx[0] == vtx2) &&
1923 (pure_edge_size == 0 || memcmp(edge + 1, edge_data, pure_edge_size) == 0),
1924 "An edge is missing or incorrect" );
1928 CV_CALL( cvGraphRemoveEdgeByPtr( graph, vtx, vtx2 ));
1929 CV_CALL( edge2 = cvFindGraphEdgeByPtr( graph, vtx, vtx2 ));
1930 CV_CALL( v_degree[0] = cvGraphVtxDegreeByPtr( graph, vtx ));
1931 CV_CALL( v_degree[1] = cvGraphVtxDegreeByPtr( graph, vtx2 ));
1935 CV_CALL( cvGraphRemoveEdge(graph, v_idx[0], v_idx[1] ));
1936 CV_CALL( edge2 = cvFindGraphEdge( graph, v_idx[0], v_idx[1] ));
1937 CV_CALL( v_degree[0] = cvGraphVtxDegree( graph, v_idx[0] ));
1938 CV_CALL( v_degree[1] = cvGraphVtxDegree( graph, v_idx[1] ));
1941 CV_TS_SEQ_CHECK_CONDITION( !edge2 && !CV_IS_SET_ELEM(edge),
1942 "The edge has not been removed from the edge set" );
1944 CV_TS_SEQ_CHECK_CONDITION( v_degree[0] == v_prev_degree[0] - 1 &&
1945 v_degree[1] == v_prev_degree[1] - 1,
1946 "The vertices lists have not been updated properly" );
1948 cvTsSimpleGraphRemoveEdge( sgraph, v_idx[0], v_idx[1] );
1950 CV_TS_SEQ_CHECK_CONDITION( graph->edges->free_elems == (CvSetElem*)edge &&
1951 graph->edges->free_elems->next_free == first_free &&
1952 graph->edges->active_count == prev_edge_count - 1,
1953 "The free edge list has not been modified properly" );
1956 //max_active_count = MAX( max_active_count, graph->active_count );
1957 //mean_active_count += graph->active_count;
1959 CV_TS_SEQ_CHECK_CONDITION( graph->active_count == sgraph->vtx->max_count - sgraph->vtx->free_count &&
1960 graph->total >= graph->active_count &&
1961 (graph->total == 0 || graph->total >= prev_vtx_total),
1962 "The total number of graph vertices is not correct" );
1964 CV_TS_SEQ_CHECK_CONDITION( graph->edges->total >= graph->edges->active_count &&
1965 (graph->edges->total == 0 || graph->edges->total >= prev_edge_total),
1966 "The total number of graph vertices is not correct" );
1968 // CvGraph and simple graph do not neccessary have the same "total" (active & free) number,
1969 // so pass "graph->total" (or "graph->edges->total") to skip that check
1970 test_seq_block_consistence( struct_idx, (CvSeq*)graph, graph->total );
1971 test_seq_block_consistence( struct_idx, (CvSeq*)graph->edges, graph->edges->total );
1972 update_progressbar();
1976 //ts->printf( CvTS::LOG, "\ngeneration %d. max_active_count = %d,\n\tmean_active_count = %d\n",
1977 // gen, max_active_count, mean_active_count/iters );
1982 elem_mat->cols = 1; // just to skip a consistency check
1983 cvReleaseMat( &elem_mat );
1989 void CxCore_GraphTest::run( int )
1991 CvRNG* rng = ts->get_rng();
1995 CV_FUNCNAME( "CxCore_GraphTest::run" );
2002 simple_struct = (void**)cvAlloc( struct_count * sizeof(simple_struct[0]) );
2003 memset( simple_struct, 0, struct_count * sizeof(simple_struct[0]) );
2004 cxcore_struct = (void**)cvAlloc( struct_count * sizeof(cxcore_struct[0]) );
2005 memset( cxcore_struct, 0, struct_count * sizeof(cxcore_struct[0]) );
2007 for( gen = 0; gen < generations; gen++ )
2009 struct_idx = iter = -1;
2010 t = cvTsRandReal(rng)*(max_log_storage_block_size - min_log_storage_block_size) + min_log_storage_block_size;
2011 storage = cvCreateMemStorage( cvRound( exp(t * CV_LOG2) ) );
2013 for( i = 0; i < struct_count; i++ )
2015 int pure_elem_size[2], elem_size[2];
2016 int is_oriented = (gen + i) % 2;
2017 for( k = 0; k < 2; k++ )
2019 t = cvTsRandReal(rng)*(max_log_elem_size - min_log_elem_size) + min_log_elem_size;
2020 int pe = cvRound( exp(t * CV_LOG2) ) - 1; // pure_elem_size==0 does also make sense
2021 int delta = k == 0 ? sizeof(CvGraphVtx) : sizeof(CvGraphEdge);
2023 e = (e + sizeof(size_t) - 1) & ~(sizeof(size_t)-1);
2024 e = MIN( e, (int)(storage->block_size - sizeof(CvMemBlock) -
2025 sizeof(CvSeqBlock) - sizeof(void*)) );
2026 pe = MIN(pe, e - delta);
2027 pure_elem_size[k] = pe;
2031 cvTsReleaseSimpleGraph( (CvTsSimpleGraph**)&simple_struct[i] );
2032 simple_struct[i] = cvTsCreateSimpleGraph( max_struct_size/4, pure_elem_size[0],
2033 pure_elem_size[1], is_oriented );
2034 CV_CALL( cxcore_struct[i] = cvCreateGraph( is_oriented ? CV_ORIENTED_GRAPH : CV_GRAPH,
2035 sizeof(CvGraph), elem_size[0], elem_size[1],
2039 if( test_graph_ops( iterations*10 ) < 0 )
2042 cvReleaseMemStorage( &storage );
2048 CxCore_GraphTest graph_test;
2052 //////////// graph scan test //////////////
2054 class CxCore_GraphScanTest : public CxCore_DynStructBaseTest
2057 CxCore_GraphScanTest();
2061 //int test_seq_block_consistence( int struct_idx );
2062 int create_random_graph( int );
2066 CxCore_GraphScanTest::CxCore_GraphScanTest():
2067 CxCore_DynStructBaseTest( "ds-graphscan", "cvCreateGraph, "
2068 "cvGraphAddVtx, cvGraphAddEdge, cvNextGraphItem, "
2069 "cvCreateGraphScanner, cvReleaseGraphScanner" )
2076 int CxCore_GraphScanTest::create_random_graph( int _struct_idx )
2078 CvRNG* rng = ts->get_rng();
2079 int is_oriented = cvTsRandInt(rng) % 2;
2080 int i, vtx_count = cvTsRandInt(rng) % max_struct_size;
2081 int edge_count = cvTsRandInt(rng) % MAX(vtx_count*20, 1);
2084 CV_FUNCNAME( "CxCore_GraphScanTest::create_random_graph" );
2088 struct_idx = _struct_idx;
2090 CV_CALL( cxcore_struct[_struct_idx] = graph = cvCreateGraph(
2091 is_oriented ? CV_ORIENTED_GRAPH : CV_GRAPH,
2092 sizeof(CvGraph), sizeof(CvGraphVtx), sizeof(CvGraphEdge), storage ));
2094 for( i = 0; i < vtx_count; i++ )
2095 CV_CALL( cvGraphAddVtx( graph ));
2097 assert( graph->active_count == vtx_count );
2099 for( i = 0; i < edge_count; i++ )
2101 int j = cvTsRandInt(rng) % vtx_count;
2102 int k = cvTsRandInt(rng) % vtx_count;
2105 CV_CALL( cvGraphAddEdge( graph, j, k ));
2108 assert( graph->active_count == vtx_count && graph->edges->active_count <= edge_count );
2116 void CxCore_GraphScanTest::run( int )
2118 CvRNG* rng = ts->get_rng();
2119 CvGraphScanner* scanner = 0;
2120 CvMat* vtx_mask = 0, *edge_mask = 0;
2124 CV_FUNCNAME( "CxCore_GraphTest::run" );
2131 cxcore_struct = (void**)cvAlloc( struct_count * sizeof(cxcore_struct[0]) );
2132 memset( cxcore_struct, 0, struct_count * sizeof(cxcore_struct[0]) );
2134 for( gen = 0; gen < generations; gen++ )
2136 struct_idx = iter = -1;
2137 t = cvTsRandReal(rng)*(max_log_storage_block_size - min_log_storage_block_size) + min_log_storage_block_size;
2138 storage = cvCreateMemStorage( cvRound( exp(t * CV_LOG2) ) );
2142 // special regression test for one sample graph.
2143 // !!! ATTENTION !!! The test relies on the particular order of the inserted edges
2144 // (LIFO: the edge inserted last goes first in the list of incident edges).
2145 // if it is changed, the test will have to be modified.
2147 int vtx_count = -1, edge_count = 0, edges[][3] =
2149 {0,4,'f'}, {0,1,'t'}, {1,4,'t'}, {1,2,'t'}, {2,3,'t'}, {4,3,'c'}, {3,1,'b'},
2150 {5,7,'t'}, {7,5,'b'}, {5,6,'t'}, {6,0,'c'}, {7,6,'c'}, {6,4,'c'}, {-1,-1,0}
2154 CV_CALL( graph = cvCreateGraph( CV_ORIENTED_GRAPH, sizeof(CvGraph),
2155 sizeof(CvGraphVtx), sizeof(CvGraphEdge), storage ));
2157 for( i = 0; edges[i][0] >= 0; i++ )
2159 vtx_count = MAX( vtx_count, edges[i][0] );
2160 vtx_count = MAX( vtx_count, edges[i][1] );
2164 for( i = 0; i < vtx_count; i++ )
2165 CV_CALL( cvGraphAddVtx( graph ));
2167 for( i = 0; edges[i][0] >= 0; i++ )
2170 CV_CALL( cvGraphAddEdge( graph, edges[i][0], edges[i][1], 0, &edge ));
2171 edge->weight = (float)edges[i][2];
2175 CV_CALL( scanner = cvCreateGraphScanner( graph, 0, CV_GRAPH_ALL_ITEMS ));
2179 int code, a = -1, b = -1;
2181 CV_CALL( code = cvNextGraphItem( scanner ));
2185 case CV_GRAPH_VERTEX:
2188 a = cvGraphVtxIdx( graph, scanner->vtx );
2190 case CV_GRAPH_TREE_EDGE:
2191 event = "Tree Edge";
2193 CV_TS_SEQ_CHECK_CONDITION( scanner->edge->weight == (float)'t',
2194 "Invalid edge type" );
2195 a = cvGraphVtxIdx( graph, scanner->vtx );
2196 b = cvGraphVtxIdx( graph, scanner->dst );
2198 case CV_GRAPH_BACK_EDGE:
2199 event = "Back Edge";
2201 CV_TS_SEQ_CHECK_CONDITION( scanner->edge->weight == (float)'b',
2202 "Invalid edge type" );
2203 a = cvGraphVtxIdx( graph, scanner->vtx );
2204 b = cvGraphVtxIdx( graph, scanner->dst );
2206 case CV_GRAPH_CROSS_EDGE:
2207 event = "Cross Edge";
2209 CV_TS_SEQ_CHECK_CONDITION( scanner->edge->weight == (float)'c',
2210 "Invalid edge type" );
2211 a = cvGraphVtxIdx( graph, scanner->vtx );
2212 b = cvGraphVtxIdx( graph, scanner->dst );
2214 case CV_GRAPH_FORWARD_EDGE:
2215 event = "Forward Edge";
2217 CV_TS_SEQ_CHECK_CONDITION( scanner->edge->weight == (float)'f',
2218 "Invalid edge type" );
2219 a = cvGraphVtxIdx( graph, scanner->vtx );
2220 b = cvGraphVtxIdx( graph, scanner->dst );
2222 case CV_GRAPH_BACKTRACKING:
2223 event = "Backtracking";
2224 a = cvGraphVtxIdx( graph, scanner->vtx );
2226 case CV_GRAPH_NEW_TREE:
2227 event = "New search tree";
2230 event = "End of procedure";
2233 CV_TS_SEQ_CHECK_CONDITION( 0, "Invalid code appeared during graph scan" );
2236 ts->printf( CvTS::LOG, "%s", event );
2240 ts->printf( CvTS::LOG, ": (%d,%d)", a, b );
2242 ts->printf( CvTS::LOG, ": %d", a );
2245 ts->printf( CvTS::LOG, "\n" );
2251 CV_TS_SEQ_CHECK_CONDITION( vtx_count == 0 && edge_count == 0,
2252 "Not every vertex/edge has been visited" );
2253 update_progressbar();
2256 // for a random graph the test just checks that every graph vertex and
2257 // every edge is vitisted during the scan
2258 for( iter = 0; iter < iterations; iter++ )
2260 create_random_graph(0);
2261 CvGraph* graph = (CvGraph*)cxcore_struct[0];
2263 // iterate twice to check that scanner doesn't damage the graph
2264 for( i = 0; i < 2; i++ )
2266 CvGraphVtx* start_vtx = cvTsRandInt(rng) % 2 || graph->active_count == 0 ? 0 :
2267 cvGetGraphVtx( graph, cvTsRandInt(rng) % graph->active_count );
2269 CV_CALL( scanner = cvCreateGraphScanner( graph, start_vtx, CV_GRAPH_ALL_ITEMS ));
2271 if( !vtx_mask || vtx_mask->cols < graph->active_count )
2273 cvReleaseMat( &vtx_mask );
2274 CV_CALL( vtx_mask = cvCreateMat( 1, graph->active_count, CV_8UC1 ));
2277 if( !edge_mask || edge_mask->cols < graph->edges->active_count )
2279 cvReleaseMat( &edge_mask );
2280 CV_CALL( edge_mask = cvCreateMat( 1, graph->edges->active_count, CV_8UC1 ));
2284 cvZero( edge_mask );
2289 CV_CALL( code = cvNextGraphItem( scanner ));
2291 if( code == CV_GRAPH_OVER )
2293 else if( code & CV_GRAPH_ANY_EDGE )
2295 int edge_idx = scanner->edge->flags & CV_SET_ELEM_IDX_MASK;
2297 CV_TS_SEQ_CHECK_CONDITION( edge_idx < graph->edges->active_count &&
2298 edge_mask->data.ptr[edge_idx] == 0,
2299 "The edge is not found or visited for the second time" );
2300 edge_mask->data.ptr[edge_idx] = 1;
2302 else if( code & CV_GRAPH_VERTEX )
2304 int vtx_idx = scanner->vtx->flags & CV_SET_ELEM_IDX_MASK;
2306 CV_TS_SEQ_CHECK_CONDITION( vtx_idx < graph->active_count &&
2307 vtx_mask->data.ptr[vtx_idx] == 0,
2308 "The vtx is not found or visited for the second time" );
2309 vtx_mask->data.ptr[vtx_idx] = 1;
2313 cvReleaseGraphScanner( &scanner );
2315 CV_TS_SEQ_CHECK_CONDITION( cvNorm(vtx_mask,0,CV_L1) == graph->active_count &&
2316 cvNorm(edge_mask,0,CV_L1) == graph->edges->active_count,
2317 "Some vertices or edges have not been visited" );
2318 update_progressbar();
2320 cvClearMemStorage( storage );
2323 cvReleaseMemStorage( &storage );
2328 cvReleaseGraphScanner( &scanner );
2329 cvReleaseMat( &vtx_mask );
2330 cvReleaseMat( &edge_mask );
2333 CxCore_GraphScanTest graphscan_test;