Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/core/test/test_ds.cpp
16337 views
1
// This file is part of OpenCV project.
2
// It is subject to the license terms in the LICENSE file found in the top-level directory
3
// of this distribution and at http://opencv.org/license.html.
4
#include "test_precomp.hpp"
5
6
namespace opencv_test { namespace {
7
8
typedef struct CvTsSimpleSeq
9
{
10
schar* array;
11
int count;
12
int max_count;
13
int elem_size;
14
} CvTsSimpleSeq;
15
16
17
static CvTsSimpleSeq* cvTsCreateSimpleSeq( int max_count, int elem_size )
18
{
19
CvTsSimpleSeq* seq = (CvTsSimpleSeq*)cvAlloc( sizeof(*seq) + max_count * elem_size );
20
seq->elem_size = elem_size;
21
seq->max_count = max_count;
22
seq->count = 0;
23
seq->array = (schar*)(seq + 1);
24
return seq;
25
}
26
27
28
static void cvTsReleaseSimpleSeq( CvTsSimpleSeq** seq )
29
{
30
cvFree( seq );
31
}
32
33
34
static schar* cvTsSimpleSeqElem( CvTsSimpleSeq* seq, int index )
35
{
36
assert( 0 <= index && index < seq->count );
37
return seq->array + index * seq->elem_size;
38
}
39
40
41
static void cvTsClearSimpleSeq( CvTsSimpleSeq* seq )
42
{
43
seq->count = 0;
44
}
45
46
47
static void cvTsSimpleSeqShiftAndCopy( CvTsSimpleSeq* seq, int from_idx, int to_idx, void* elem=0 )
48
{
49
int elem_size = seq->elem_size;
50
51
if( from_idx == to_idx )
52
return;
53
assert( (from_idx > to_idx && !elem) || (from_idx < to_idx && elem) );
54
55
if( from_idx < seq->count )
56
{
57
memmove( seq->array + to_idx*elem_size, seq->array + from_idx*elem_size,
58
(seq->count - from_idx)*elem_size );
59
}
60
seq->count += to_idx - from_idx;
61
if( elem )
62
memcpy( seq->array + from_idx*elem_size, elem, (to_idx - from_idx)*elem_size );
63
}
64
65
static void cvTsSimpleSeqInvert( CvTsSimpleSeq* seq )
66
{
67
int i, k, len = seq->count, elem_size = seq->elem_size;
68
schar *data = seq->array, t;
69
70
for( i = 0; i < len/2; i++ )
71
{
72
schar* a = data + i*elem_size;
73
schar* b = data + (len - i - 1)*elem_size;
74
for( k = 0; k < elem_size; k++ )
75
CV_SWAP( a[k], b[k], t );
76
}
77
}
78
79
/****************************************************************************************\
80
* simple cvset implementation *
81
\****************************************************************************************/
82
83
typedef struct CvTsSimpleSet
84
{
85
schar* array;
86
int count, max_count;
87
int elem_size;
88
int* free_stack;
89
int free_count;
90
} CvTsSimpleSet;
91
92
93
static void cvTsClearSimpleSet( CvTsSimpleSet* set_header )
94
{
95
int i;
96
int elem_size = set_header->elem_size;
97
98
for( i = 0; i < set_header->max_count; i++ )
99
{
100
set_header->array[i*elem_size] = 0;
101
set_header->free_stack[i] = set_header->max_count - i - 1;
102
}
103
set_header->free_count = set_header->max_count;
104
set_header->count = 0;
105
}
106
107
108
static CvTsSimpleSet* cvTsCreateSimpleSet( int max_count, int elem_size )
109
{
110
CvTsSimpleSet* set_header = (CvTsSimpleSet*)cvAlloc( sizeof(*set_header) + max_count *
111
(elem_size + 1 + sizeof(int)));
112
set_header->elem_size = elem_size + 1;
113
set_header->max_count = max_count;
114
set_header->free_stack = (int*)(set_header + 1);
115
set_header->array = (schar*)(set_header->free_stack + max_count);
116
117
cvTsClearSimpleSet( set_header );
118
return set_header;
119
}
120
121
122
static void cvTsReleaseSimpleSet( CvTsSimpleSet** set_header )
123
{
124
cvFree( set_header );
125
}
126
127
128
static schar* cvTsSimpleSetFind( CvTsSimpleSet* set_header, int index )
129
{
130
int idx = index * set_header->elem_size;
131
assert( 0 <= index && index < set_header->max_count );
132
return set_header->array[idx] ? set_header->array + idx + 1 : 0;
133
}
134
135
136
static int cvTsSimpleSetAdd( CvTsSimpleSet* set_header, void* elem )
137
{
138
int idx, idx2;
139
assert( set_header->free_count > 0 );
140
141
idx = set_header->free_stack[--set_header->free_count];
142
idx2 = idx * set_header->elem_size;
143
assert( set_header->array[idx2] == 0 );
144
set_header->array[idx2] = 1;
145
if( set_header->elem_size > 1 )
146
memcpy( set_header->array + idx2 + 1, elem, set_header->elem_size - 1 );
147
set_header->count = MAX( set_header->count, idx + 1 );
148
149
return idx;
150
}
151
152
153
static void cvTsSimpleSetRemove( CvTsSimpleSet* set_header, int index )
154
{
155
assert( set_header->free_count < set_header->max_count &&
156
0 <= index && index < set_header->max_count );
157
assert( set_header->array[index * set_header->elem_size] == 1 );
158
159
set_header->free_stack[set_header->free_count++] = index;
160
set_header->array[index * set_header->elem_size] = 0;
161
}
162
163
164
/****************************************************************************************\
165
* simple graph implementation *
166
\****************************************************************************************/
167
168
typedef struct CvTsSimpleGraph
169
{
170
char* matrix;
171
int edge_size;
172
int oriented;
173
CvTsSimpleSet* vtx;
174
} CvTsSimpleGraph;
175
176
177
static void cvTsClearSimpleGraph( CvTsSimpleGraph* graph )
178
{
179
int max_vtx_count = graph->vtx->max_count;
180
cvTsClearSimpleSet( graph->vtx );
181
memset( graph->matrix, 0, max_vtx_count * max_vtx_count * graph->edge_size );
182
}
183
184
185
static CvTsSimpleGraph* cvTsCreateSimpleGraph( int max_vtx_count, int vtx_size,
186
int edge_size, int oriented )
187
{
188
CvTsSimpleGraph* graph;
189
190
assert( max_vtx_count > 1 && vtx_size >= 0 && edge_size >= 0 );
191
graph = (CvTsSimpleGraph*)cvAlloc( sizeof(*graph) +
192
max_vtx_count * max_vtx_count * (edge_size + 1));
193
graph->vtx = cvTsCreateSimpleSet( max_vtx_count, vtx_size );
194
graph->edge_size = edge_size + 1;
195
graph->matrix = (char*)(graph + 1);
196
graph->oriented = oriented;
197
198
cvTsClearSimpleGraph( graph );
199
return graph;
200
}
201
202
203
static void cvTsReleaseSimpleGraph( CvTsSimpleGraph** graph )
204
{
205
if( *graph )
206
{
207
cvTsReleaseSimpleSet( &(graph[0]->vtx) );
208
cvFree( graph );
209
}
210
}
211
212
213
static int cvTsSimpleGraphAddVertex( CvTsSimpleGraph* graph, void* vertex )
214
{
215
return cvTsSimpleSetAdd( graph->vtx, vertex );
216
}
217
218
219
static void cvTsSimpleGraphRemoveVertex( CvTsSimpleGraph* graph, int index )
220
{
221
int i, max_vtx_count = graph->vtx->max_count;
222
int edge_size = graph->edge_size;
223
cvTsSimpleSetRemove( graph->vtx, index );
224
225
/* remove all the corresponding edges */
226
for( i = 0; i < max_vtx_count; i++ )
227
{
228
graph->matrix[(i*max_vtx_count + index)*edge_size] =
229
graph->matrix[(index*max_vtx_count + i)*edge_size] = 0;
230
}
231
}
232
233
234
static void cvTsSimpleGraphAddEdge( CvTsSimpleGraph* graph, int idx1, int idx2, void* edge )
235
{
236
int i, t, n = graph->oriented ? 1 : 2;
237
238
assert( cvTsSimpleSetFind( graph->vtx, idx1 ) &&
239
cvTsSimpleSetFind( graph->vtx, idx2 ));
240
241
for( i = 0; i < n; i++ )
242
{
243
int ofs = (idx1*graph->vtx->max_count + idx2)*graph->edge_size;
244
assert( graph->matrix[ofs] == 0 );
245
graph->matrix[ofs] = 1;
246
if( graph->edge_size > 1 )
247
memcpy( graph->matrix + ofs + 1, edge, graph->edge_size - 1 );
248
249
CV_SWAP( idx1, idx2, t );
250
}
251
}
252
253
254
static void cvTsSimpleGraphRemoveEdge( CvTsSimpleGraph* graph, int idx1, int idx2 )
255
{
256
int i, t, n = graph->oriented ? 1 : 2;
257
258
assert( cvTsSimpleSetFind( graph->vtx, idx1 ) &&
259
cvTsSimpleSetFind( graph->vtx, idx2 ));
260
261
for( i = 0; i < n; i++ )
262
{
263
int ofs = (idx1*graph->vtx->max_count + idx2)*graph->edge_size;
264
assert( graph->matrix[ofs] == 1 );
265
graph->matrix[ofs] = 0;
266
CV_SWAP( idx1, idx2, t );
267
}
268
}
269
270
271
static schar* cvTsSimpleGraphFindVertex( CvTsSimpleGraph* graph, int index )
272
{
273
return cvTsSimpleSetFind( graph->vtx, index );
274
}
275
276
277
static char* cvTsSimpleGraphFindEdge( CvTsSimpleGraph* graph, int idx1, int idx2 )
278
{
279
if( cvTsSimpleGraphFindVertex( graph, idx1 ) &&
280
cvTsSimpleGraphFindVertex( graph, idx2 ))
281
{
282
char* edge = graph->matrix + (idx1 * graph->vtx->max_count + idx2)*graph->edge_size;
283
if( edge[0] ) return edge + 1;
284
}
285
return 0;
286
}
287
288
289
static int cvTsSimpleGraphVertexDegree( CvTsSimpleGraph* graph, int index )
290
{
291
int i, count = 0;
292
int edge_size = graph->edge_size;
293
int max_vtx_count = graph->vtx->max_count;
294
assert( cvTsSimpleGraphFindVertex( graph, index ) != 0 );
295
296
for( i = 0; i < max_vtx_count; i++ )
297
{
298
count += graph->matrix[(i*max_vtx_count + index)*edge_size] +
299
graph->matrix[(index*max_vtx_count + i)*edge_size];
300
}
301
302
if( !graph->oriented )
303
{
304
assert( count % 2 == 0 );
305
count /= 2;
306
}
307
return count;
308
}
309
310
311
///////////////////////////////////// the tests //////////////////////////////////
312
313
#define CV_TS_SEQ_CHECK_CONDITION( expr, err_msg ) \
314
if( !(expr) ) \
315
{ \
316
set_error_context( #expr, err_msg, __FILE__, __LINE__ ); \
317
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );\
318
throw -1; \
319
}
320
321
class Core_DynStructBaseTest : public cvtest::BaseTest
322
{
323
public:
324
Core_DynStructBaseTest();
325
virtual ~Core_DynStructBaseTest();
326
bool can_do_fast_forward();
327
void clear();
328
329
protected:
330
int read_params( CvFileStorage* fs );
331
void run_func(void);
332
void set_error_context( const char* condition,
333
const char* err_msg,
334
const char* file, int line );
335
int test_seq_block_consistence( int _struct_idx, CvSeq* seq, int total );
336
void update_progressbar();
337
338
int struct_count, max_struct_size, iterations, generations;
339
int min_log_storage_block_size, max_log_storage_block_size;
340
int min_log_elem_size, max_log_elem_size;
341
int gen, struct_idx, iter;
342
int test_progress;
343
int64 start_time;
344
double cpu_freq;
345
vector<void*> cxcore_struct;
346
vector<void*> simple_struct;
347
Ptr<CvMemStorage> storage;
348
};
349
350
351
Core_DynStructBaseTest::Core_DynStructBaseTest()
352
{
353
struct_count = 2;
354
max_struct_size = 2000;
355
min_log_storage_block_size = 7;
356
max_log_storage_block_size = 12;
357
min_log_elem_size = 0;
358
max_log_elem_size = 8;
359
generations = 10;
360
iterations = max_struct_size*2;
361
gen = struct_idx = iter = -1;
362
test_progress = -1;
363
}
364
365
366
Core_DynStructBaseTest::~Core_DynStructBaseTest()
367
{
368
clear();
369
}
370
371
372
void Core_DynStructBaseTest::run_func()
373
{
374
}
375
376
bool Core_DynStructBaseTest::can_do_fast_forward()
377
{
378
return false;
379
}
380
381
382
void Core_DynStructBaseTest::clear()
383
{
384
cvtest::BaseTest::clear();
385
}
386
387
388
int Core_DynStructBaseTest::read_params( CvFileStorage* fs )
389
{
390
int code = cvtest::BaseTest::read_params( fs );
391
double sqrt_scale = sqrt(ts->get_test_case_count_scale());
392
if( code < 0 )
393
return code;
394
395
struct_count = cvReadInt( find_param( fs, "struct_count" ), struct_count );
396
max_struct_size = cvReadInt( find_param( fs, "max_struct_size" ), max_struct_size );
397
generations = cvReadInt( find_param( fs, "generations" ), generations );
398
iterations = cvReadInt( find_param( fs, "iterations" ), iterations );
399
generations = cvRound(generations*sqrt_scale);
400
iterations = cvRound(iterations*sqrt_scale);
401
402
min_log_storage_block_size = cvReadInt( find_param( fs, "min_log_storage_block_size" ),
403
min_log_storage_block_size );
404
max_log_storage_block_size = cvReadInt( find_param( fs, "max_log_storage_block_size" ),
405
max_log_storage_block_size );
406
min_log_elem_size = cvReadInt( find_param( fs, "min_log_elem_size" ), min_log_elem_size );
407
max_log_elem_size = cvReadInt( find_param( fs, "max_log_elem_size" ), max_log_elem_size );
408
409
struct_count = cvtest::clipInt( struct_count, 1, 100 );
410
max_struct_size = cvtest::clipInt( max_struct_size, 1, 1<<20 );
411
generations = cvtest::clipInt( generations, 1, 100 );
412
iterations = cvtest::clipInt( iterations, 100, 1<<20 );
413
414
min_log_storage_block_size = cvtest::clipInt( min_log_storage_block_size, 7, 20 );
415
max_log_storage_block_size = cvtest::clipInt( max_log_storage_block_size,
416
min_log_storage_block_size, 20 );
417
418
min_log_elem_size = cvtest::clipInt( min_log_elem_size, 0, 8 );
419
max_log_elem_size = cvtest::clipInt( max_log_elem_size, min_log_elem_size, 10 );
420
421
return 0;
422
}
423
424
425
void Core_DynStructBaseTest::update_progressbar()
426
{
427
int64 t;
428
429
if( test_progress < 0 )
430
{
431
test_progress = 0;
432
cpu_freq = cv::getTickFrequency();
433
start_time = cv::getTickCount();
434
}
435
436
t = cv::getTickCount();
437
test_progress = update_progress( test_progress, 0, 0, (double)(t - start_time)/cpu_freq );
438
}
439
440
441
void Core_DynStructBaseTest::set_error_context( const char* condition,
442
const char* err_msg,
443
const char* filename, int lineno )
444
{
445
ts->printf( cvtest::TS::LOG, "file %s, line %d: %s\n(\"%s\" failed).\n"
446
"generation = %d, struct_idx = %d, iter = %d\n",
447
filename, lineno, err_msg, condition, gen, struct_idx, iter );
448
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
449
}
450
451
452
int Core_DynStructBaseTest::test_seq_block_consistence( int _struct_idx, CvSeq* seq, int total )
453
{
454
int sum = 0;
455
struct_idx = _struct_idx;
456
457
CV_TS_SEQ_CHECK_CONDITION( seq != 0, "Null sequence pointer" );
458
459
if( seq->first )
460
{
461
CvSeqBlock* block = seq->first;
462
CvSeqBlock* prev_block = block->prev;
463
464
int delta_idx = seq->first->start_index;
465
466
for( ;; )
467
{
468
CV_TS_SEQ_CHECK_CONDITION( sum == block->start_index - delta_idx &&
469
block->count > 0 && block->prev == prev_block &&
470
prev_block->next == block,
471
"sequence blocks are inconsistent" );
472
sum += block->count;
473
prev_block = block;
474
block = block->next;
475
if( block == seq->first ) break;
476
}
477
478
CV_TS_SEQ_CHECK_CONDITION( block->prev->count * seq->elem_size +
479
block->prev->data <= seq->block_max,
480
"block->data or block_max pointer are incorrect" );
481
}
482
483
CV_TS_SEQ_CHECK_CONDITION( seq->total == sum && sum == total,
484
"total number of elements is incorrect" );
485
486
return 0;
487
}
488
489
490
/////////////////////////////////// sequence tests ////////////////////////////////////
491
492
class Core_SeqBaseTest : public Core_DynStructBaseTest
493
{
494
public:
495
Core_SeqBaseTest();
496
virtual ~Core_SeqBaseTest();
497
void clear();
498
void run( int );
499
500
protected:
501
int test_multi_create();
502
int test_get_seq_elem( int _struct_idx, int iters );
503
int test_get_seq_reading( int _struct_idx, int iters );
504
int test_seq_ops( int iters );
505
};
506
507
Core_SeqBaseTest::Core_SeqBaseTest()
508
{
509
}
510
511
Core_SeqBaseTest::~Core_SeqBaseTest()
512
{
513
clear();
514
}
515
516
void Core_SeqBaseTest::clear()
517
{
518
for( size_t i = 0; i < simple_struct.size(); i++ )
519
cvTsReleaseSimpleSeq( (CvTsSimpleSeq**)&simple_struct[i] );
520
Core_DynStructBaseTest::clear();
521
}
522
523
524
int Core_SeqBaseTest::test_multi_create()
525
{
526
vector<CvSeqWriter> writer(struct_count);
527
vector<int> pos(struct_count);
528
vector<int> index(struct_count);
529
int cur_count, elem_size;
530
RNG& rng = ts->get_rng();
531
532
for( int i = 0; i < struct_count; i++ )
533
{
534
double t;
535
CvTsSimpleSeq* sseq;
536
537
pos[i] = -1;
538
index[i] = i;
539
540
t = cvtest::randReal(rng)*(max_log_elem_size - min_log_elem_size) + min_log_elem_size;
541
elem_size = cvRound( exp(t * CV_LOG2) );
542
elem_size = MIN( elem_size, (int)(storage->block_size - sizeof(void*) -
543
sizeof(CvSeqBlock) - sizeof(CvMemBlock)) );
544
545
cvTsReleaseSimpleSeq( (CvTsSimpleSeq**)&simple_struct[i] );
546
simple_struct[i] = sseq = cvTsCreateSimpleSeq( max_struct_size, elem_size );
547
cxcore_struct[i] = 0;
548
sseq->count = cvtest::randInt( rng ) % max_struct_size;
549
Mat m( 1, MAX(sseq->count,1)*elem_size, CV_8UC1, sseq->array );
550
cvtest::randUni( rng, m, Scalar::all(0), Scalar::all(256) );
551
}
552
553
for( cur_count = struct_count; cur_count > 0; cur_count-- )
554
{
555
for(;;)
556
{
557
int k = cvtest::randInt( rng ) % cur_count;
558
struct_idx = index[k];
559
CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[struct_idx];
560
561
if( pos[struct_idx] < 0 )
562
{
563
int hdr_size = (cvtest::randInt(rng) % 10)*4 + sizeof(CvSeq);
564
hdr_size = MIN( hdr_size, (int)(storage->block_size - sizeof(CvMemBlock)) );
565
elem_size = sseq->elem_size;
566
567
if( cvtest::randInt(rng) % 2 )
568
{
569
cvStartWriteSeq( 0, hdr_size, elem_size, storage, &writer[struct_idx] );
570
}
571
else
572
{
573
CvSeq* s;
574
s = cvCreateSeq( 0, hdr_size, elem_size, storage );
575
cvStartAppendToSeq( s, &writer[struct_idx] );
576
}
577
578
cvSetSeqBlockSize( writer[struct_idx].seq, cvtest::randInt( rng ) % 10000 );
579
pos[struct_idx] = 0;
580
}
581
582
update_progressbar();
583
if( pos[struct_idx] == sseq->count )
584
{
585
cxcore_struct[struct_idx] = cvEndWriteSeq( &writer[struct_idx] );
586
/* del index */
587
for( ; k < cur_count-1; k++ )
588
index[k] = index[k+1];
589
break;
590
}
591
592
{
593
schar* el = cvTsSimpleSeqElem( sseq, pos[struct_idx] );
594
CV_WRITE_SEQ_ELEM_VAR( el, writer[struct_idx] );
595
}
596
pos[struct_idx]++;
597
}
598
}
599
600
return 0;
601
}
602
603
604
int Core_SeqBaseTest::test_get_seq_elem( int _struct_idx, int iters )
605
{
606
RNG& rng = ts->get_rng();
607
608
CvSeq* seq = (CvSeq*)cxcore_struct[_struct_idx];
609
CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[_struct_idx];
610
struct_idx = _struct_idx;
611
612
assert( seq->total == sseq->count );
613
614
if( sseq->count == 0 )
615
return 0;
616
617
for( int i = 0; i < iters; i++ )
618
{
619
int idx = cvtest::randInt(rng) % (sseq->count*3) - sseq->count*3/2;
620
int idx0 = (unsigned)idx < (unsigned)(sseq->count) ? idx : idx < 0 ?
621
idx + sseq->count : idx - sseq->count;
622
int bad_range = (unsigned)idx0 >= (unsigned)(sseq->count);
623
schar* elem;
624
elem = cvGetSeqElem( seq, idx );
625
626
if( bad_range )
627
{
628
CV_TS_SEQ_CHECK_CONDITION( elem == 0,
629
"cvGetSeqElem doesn't "
630
"handle \"out of range\" properly" );
631
}
632
else
633
{
634
CV_TS_SEQ_CHECK_CONDITION( elem != 0 &&
635
!memcmp( elem, cvTsSimpleSeqElem(sseq, idx0), sseq->elem_size ),
636
"cvGetSeqElem returns wrong element" );
637
638
idx = cvSeqElemIdx(seq, elem );
639
CV_TS_SEQ_CHECK_CONDITION( idx >= 0 && idx == idx0,
640
"cvSeqElemIdx is incorrect" );
641
}
642
}
643
644
return 0;
645
}
646
647
648
int Core_SeqBaseTest::test_get_seq_reading( int _struct_idx, int iters )
649
{
650
const int max_val = 3*5 + 2;
651
CvSeq* seq = (CvSeq*)cxcore_struct[_struct_idx];
652
CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[_struct_idx];
653
int total = seq->total;
654
RNG& rng = ts->get_rng();
655
CvSeqReader reader;
656
vector<schar> _elem(sseq->elem_size);
657
schar* elem = &_elem[0];
658
659
assert( total == sseq->count );
660
this->struct_idx = _struct_idx;
661
662
int pos = cvtest::randInt(rng) % 2;
663
cvStartReadSeq( seq, &reader, pos );
664
665
if( total == 0 )
666
{
667
CV_TS_SEQ_CHECK_CONDITION( reader.ptr == 0, "Empty sequence reader pointer is not NULL" );
668
return 0;
669
}
670
671
pos = pos ? seq->total - 1 : 0;
672
673
CV_TS_SEQ_CHECK_CONDITION( pos == cvGetSeqReaderPos(&reader),
674
"initial reader position is wrong" );
675
676
for( iter = 0; iter < iters; iter++ )
677
{
678
int op = cvtest::randInt(rng) % max_val;
679
680
if( op >= max_val - 2 )
681
{
682
int new_pos, new_pos0;
683
int bad_range;
684
int is_relative = op == max_val - 1;
685
686
new_pos = cvtest::randInt(rng) % (total*2) - total;
687
new_pos0 = new_pos + (is_relative ? pos : 0 );
688
689
if( new_pos0 < 0 ) new_pos0 += total;
690
if( new_pos0 >= total ) new_pos0 -= total;
691
692
bad_range = (unsigned)new_pos0 >= (unsigned)total;
693
cvSetSeqReaderPos( &reader, new_pos, is_relative );
694
695
if( !bad_range )
696
{
697
CV_TS_SEQ_CHECK_CONDITION( new_pos0 == cvGetSeqReaderPos( &reader ),
698
"cvset reader position doesn't work" );
699
pos = new_pos0;
700
}
701
else
702
{
703
CV_TS_SEQ_CHECK_CONDITION( pos == cvGetSeqReaderPos( &reader ),
704
"reader doesn't stay at the current position after wrong positioning" );
705
}
706
}
707
else
708
{
709
int direction = (op % 3) - 1;
710
memcpy( elem, reader.ptr, sseq->elem_size );
711
712
if( direction > 0 )
713
{
714
CV_NEXT_SEQ_ELEM( sseq->elem_size, reader );
715
}
716
else if( direction < 0 )
717
{
718
CV_PREV_SEQ_ELEM( sseq->elem_size, reader );
719
}
720
721
CV_TS_SEQ_CHECK_CONDITION( memcmp(elem, cvTsSimpleSeqElem(sseq, pos),
722
sseq->elem_size) == 0, "reading is incorrect" );
723
pos += direction;
724
if( -pos > 0 ) pos += total;
725
if( pos >= total ) pos -= total;
726
727
CV_TS_SEQ_CHECK_CONDITION( pos == cvGetSeqReaderPos( &reader ),
728
"reader doesn't move correctly after reading" );
729
}
730
}
731
732
return 0;
733
}
734
735
736
int Core_SeqBaseTest::test_seq_ops( int iters )
737
{
738
const int max_op = 14;
739
int max_elem_size = 0;
740
schar* elem2 = 0;
741
RNG& rng = ts->get_rng();
742
743
for( int i = 0; i < struct_count; i++ )
744
max_elem_size = MAX( max_elem_size, ((CvSeq*)cxcore_struct[i])->elem_size );
745
746
vector<schar> elem_buf(max_struct_size*max_elem_size);
747
schar* elem = (schar*)&elem_buf[0];
748
Mat elem_mat;
749
750
for( iter = 0; iter < iters; iter++ )
751
{
752
struct_idx = cvtest::randInt(rng) % struct_count;
753
int op = cvtest::randInt(rng) % max_op;
754
CvSeq* seq = (CvSeq*)cxcore_struct[struct_idx];
755
CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[struct_idx];
756
int elem_size = sseq->elem_size;
757
int whence = 0, pos = 0, count = 0;
758
759
switch( op )
760
{
761
case 0:
762
case 1:
763
case 2: // push/pushfront/insert
764
if( sseq->count == sseq->max_count )
765
break;
766
767
elem_mat = Mat(1, elem_size, CV_8U, elem);
768
cvtest::randUni( rng, elem_mat, cvScalarAll(0), cvScalarAll(255) );
769
770
whence = op - 1;
771
if( whence < 0 )
772
{
773
pos = 0;
774
cvSeqPushFront( seq, elem );
775
}
776
else if( whence > 0 )
777
{
778
pos = sseq->count;
779
cvSeqPush( seq, elem );
780
}
781
else
782
{
783
pos = cvtest::randInt(rng) % (sseq->count + 1);
784
cvSeqInsert( seq, pos, elem );
785
}
786
787
cvTsSimpleSeqShiftAndCopy( sseq, pos, pos + 1, elem );
788
elem2 = cvGetSeqElem( seq, pos );
789
CV_TS_SEQ_CHECK_CONDITION( elem2 != 0, "The inserted element could not be retrieved" );
790
CV_TS_SEQ_CHECK_CONDITION( seq->total == sseq->count &&
791
memcmp(elem2, cvTsSimpleSeqElem(sseq,pos), elem_size) == 0,
792
"The inserted sequence element is wrong" );
793
break;
794
795
case 3:
796
case 4:
797
case 5: // pop/popfront/remove
798
if( sseq->count == 0 )
799
break;
800
801
whence = op - 4;
802
if( whence < 0 )
803
{
804
pos = 0;
805
cvSeqPopFront( seq, elem );
806
}
807
else if( whence > 0 )
808
{
809
pos = sseq->count-1;
810
cvSeqPop( seq, elem );
811
}
812
else
813
{
814
pos = cvtest::randInt(rng) % sseq->count;
815
cvSeqRemove( seq, pos );
816
}
817
818
if( whence != 0 )
819
CV_TS_SEQ_CHECK_CONDITION( seq->total == sseq->count - 1 &&
820
memcmp( elem, cvTsSimpleSeqElem(sseq,pos), elem_size) == 0,
821
"The popped sequence element isn't correct" );
822
823
cvTsSimpleSeqShiftAndCopy( sseq, pos + 1, pos );
824
825
if( sseq->count > 0 )
826
{
827
elem2 = cvGetSeqElem( seq, pos < sseq->count ? pos : -1 );
828
CV_TS_SEQ_CHECK_CONDITION( elem2 != 0, "GetSeqElem fails after removing the element" );
829
830
CV_TS_SEQ_CHECK_CONDITION( memcmp( elem2,
831
cvTsSimpleSeqElem(sseq, pos - (pos == sseq->count)), elem_size) == 0,
832
"The first shifted element is not correct after removing another element" );
833
}
834
else
835
{
836
CV_TS_SEQ_CHECK_CONDITION( seq->first == 0,
837
"The sequence doesn't become empty after the final remove" );
838
}
839
break;
840
841
case 6:
842
case 7:
843
case 8: // push [front] multi/insert slice
844
if( sseq->count == sseq->max_count )
845
break;
846
847
count = cvtest::randInt( rng ) % (sseq->max_count - sseq->count + 1);
848
elem_mat = Mat(1, MAX(count,1) * elem_size, CV_8U, elem);
849
cvtest::randUni( rng, elem_mat, cvScalarAll(0), cvScalarAll(255) );
850
851
whence = op - 7;
852
pos = whence < 0 ? 0 : whence > 0 ? sseq->count : (int)(cvtest::randInt(rng) % (sseq->count+1));
853
if( whence != 0 )
854
{
855
cvSeqPushMulti( seq, elem, count, whence < 0 );
856
}
857
else
858
{
859
CvSeq header;
860
CvSeqBlock block;
861
cvMakeSeqHeaderForArray( CV_SEQ_KIND_GENERIC, sizeof(CvSeq),
862
sseq->elem_size,
863
elem, count,
864
&header, &block );
865
866
cvSeqInsertSlice( seq, pos, &header );
867
}
868
cvTsSimpleSeqShiftAndCopy( sseq, pos, pos + count, elem );
869
870
if( sseq->count > 0 )
871
{
872
// choose the random element among the added
873
pos = count > 0 ? (int)(cvtest::randInt(rng) % count + pos) : MAX(pos-1,0);
874
elem2 = cvGetSeqElem( seq, pos );
875
CV_TS_SEQ_CHECK_CONDITION( elem2 != 0, "multi push operation doesn't add elements" );
876
CV_TS_SEQ_CHECK_CONDITION( seq->total == sseq->count &&
877
memcmp( elem2, cvTsSimpleSeqElem(sseq,pos), elem_size) == 0,
878
"One of the added elements is wrong" );
879
}
880
else
881
{
882
CV_TS_SEQ_CHECK_CONDITION( seq->total == 0 && seq->first == 0,
883
"Adding no elements to empty sequence fails" );
884
}
885
break;
886
887
case 9:
888
case 10:
889
case 11: // pop [front] multi
890
if( sseq->count == 0 )
891
break;
892
893
count = cvtest::randInt(rng) % (sseq->count+1);
894
whence = op - 10;
895
pos = whence < 0 ? 0 : whence > 0 ? sseq->count - count :
896
(int)(cvtest::randInt(rng) % (sseq->count - count + 1));
897
898
if( whence != 0 )
899
{
900
cvSeqPopMulti( seq, elem, count, whence < 0 );
901
902
if( count > 0 )
903
{
904
CV_TS_SEQ_CHECK_CONDITION( memcmp(elem,
905
cvTsSimpleSeqElem(sseq,pos), elem_size) == 0,
906
"The first (in the sequence order) removed element is wrong after popmulti" );
907
}
908
}
909
else
910
{
911
cvSeqRemoveSlice( seq, cvSlice(pos, pos + count) );
912
}
913
914
CV_TS_SEQ_CHECK_CONDITION( seq->total == sseq->count - count,
915
"The popmulti left a wrong number of elements in the sequence" );
916
917
cvTsSimpleSeqShiftAndCopy( sseq, pos + count, pos, 0 );
918
if( sseq->count > 0 )
919
{
920
pos = whence < 0 ? 0 : MIN( pos, sseq->count - 1 );
921
elem2 = cvGetSeqElem( seq, pos );
922
CV_TS_SEQ_CHECK_CONDITION( elem2 &&
923
memcmp( elem2, cvTsSimpleSeqElem(sseq,pos), elem_size) == 0,
924
"The last sequence element is wrong after POP" );
925
}
926
else
927
{
928
CV_TS_SEQ_CHECK_CONDITION( seq->total == 0 && seq->first == 0,
929
"The sequence doesn't become empty after final POP" );
930
}
931
break;
932
case 12: // seqslice
933
{
934
CvMemStoragePos storage_pos;
935
cvSaveMemStoragePos( storage, &storage_pos );
936
937
int copy_data = cvtest::randInt(rng) % 2;
938
count = cvtest::randInt(rng) % (seq->total + 1);
939
pos = cvtest::randInt(rng) % (seq->total - count + 1);
940
CvSeq* seq_slice = cvSeqSlice( seq, cvSlice(pos, pos + count), storage, copy_data );
941
942
CV_TS_SEQ_CHECK_CONDITION( seq_slice && seq_slice->total == count,
943
"cvSeqSlice returned incorrect slice" );
944
945
if( count > 0 )
946
{
947
int test_idx = cvtest::randInt(rng) % count;
948
elem2 = cvGetSeqElem( seq_slice, test_idx );
949
schar* elem3 = cvGetSeqElem( seq, pos + test_idx );
950
CV_TS_SEQ_CHECK_CONDITION( elem2 &&
951
memcmp( elem2, cvTsSimpleSeqElem(sseq,pos + test_idx), elem_size) == 0,
952
"The extracted slice elements are not correct" );
953
CV_TS_SEQ_CHECK_CONDITION( (elem2 == elem3) ^ copy_data,
954
"copy_data flag is handled incorrectly" );
955
}
956
957
cvRestoreMemStoragePos( storage, &storage_pos );
958
}
959
break;
960
case 13: // clear
961
cvTsClearSimpleSeq( sseq );
962
cvClearSeq( seq );
963
CV_TS_SEQ_CHECK_CONDITION( seq->total == 0 && seq->first == 0,
964
"The sequence doesn't become empty after clear" );
965
break;
966
default:
967
assert(0);
968
return -1;
969
}
970
971
if( test_seq_block_consistence(struct_idx, seq, sseq->count) < 0 )
972
return -1;
973
974
if( test_get_seq_elem(struct_idx, 7) < 0 )
975
return -1;
976
977
update_progressbar();
978
}
979
980
return 0;
981
}
982
983
984
void Core_SeqBaseTest::run( int )
985
{
986
try
987
{
988
RNG& rng = ts->get_rng();
989
int i;
990
double t;
991
992
clear();
993
test_progress = -1;
994
995
simple_struct.resize(struct_count, 0);
996
cxcore_struct.resize(struct_count, 0);
997
998
for( gen = 0; gen < generations; gen++ )
999
{
1000
struct_idx = iter = -1;
1001
1002
if( !storage )
1003
{
1004
t = cvtest::randReal(rng)*(max_log_storage_block_size - min_log_storage_block_size)
1005
+ min_log_storage_block_size;
1006
storage.reset(cvCreateMemStorage( cvRound( exp(t * CV_LOG2) ) ));
1007
}
1008
1009
iter = struct_idx = -1;
1010
test_multi_create();
1011
1012
for( i = 0; i < struct_count; i++ )
1013
{
1014
if( test_seq_block_consistence(i, (CvSeq*)cxcore_struct[i],
1015
((CvTsSimpleSeq*)simple_struct[i])->count) < 0 )
1016
return;
1017
1018
if( test_get_seq_elem( i, MAX(iterations/3,7) ) < 0 )
1019
return;
1020
1021
if( test_get_seq_reading( i, MAX(iterations/3,7) ) < 0 )
1022
return;
1023
update_progressbar();
1024
}
1025
1026
if( test_seq_ops( iterations ) < 0 )
1027
return;
1028
1029
if( cvtest::randInt(rng) % 2 )
1030
storage.release();
1031
else
1032
cvClearMemStorage( storage );
1033
}
1034
}
1035
catch(const int &)
1036
{
1037
}
1038
}
1039
1040
1041
////////////////////////////// more sequence tests //////////////////////////////////////
1042
1043
class Core_SeqSortInvTest : public Core_SeqBaseTest
1044
{
1045
public:
1046
Core_SeqSortInvTest();
1047
void run( int );
1048
1049
protected:
1050
};
1051
1052
1053
Core_SeqSortInvTest::Core_SeqSortInvTest()
1054
{
1055
}
1056
1057
1058
static int icvCmpSeqElems( const void* a, const void* b, void* userdata )
1059
{
1060
return memcmp( a, b, ((CvSeq*)userdata)->elem_size );
1061
}
1062
1063
static int icvCmpSeqElems2_elem_size = 0;
1064
static int icvCmpSeqElems2( const void* a, const void* b )
1065
{
1066
return memcmp( a, b, icvCmpSeqElems2_elem_size );
1067
}
1068
1069
1070
void Core_SeqSortInvTest::run( int )
1071
{
1072
try
1073
{
1074
RNG& rng = ts->get_rng();
1075
int i, k;
1076
double t;
1077
schar *elem0, *elem, *elem2;
1078
vector<uchar> buffer;
1079
1080
clear();
1081
test_progress = -1;
1082
1083
simple_struct.resize(struct_count, 0);
1084
cxcore_struct.resize(struct_count, 0);
1085
1086
for( gen = 0; gen < generations; gen++ )
1087
{
1088
struct_idx = iter = -1;
1089
1090
if( !storage )
1091
{
1092
t = cvtest::randReal(rng)*(max_log_storage_block_size - min_log_storage_block_size)
1093
+ min_log_storage_block_size;
1094
storage.reset(cvCreateMemStorage( cvRound( exp(t * CV_LOG2) ) ));
1095
}
1096
1097
for( iter = 0; iter < iterations/10; iter++ )
1098
{
1099
int max_size = 0;
1100
test_multi_create();
1101
1102
for( i = 0; i < struct_count; i++ )
1103
{
1104
CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[i];
1105
max_size = MAX( max_size, sseq->count*sseq->elem_size );
1106
}
1107
1108
buffer.resize(max_size);
1109
1110
for( i = 0; i < struct_count; i++ )
1111
{
1112
CvSeq* seq = (CvSeq*)cxcore_struct[i];
1113
CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[i];
1114
CvSlice slice = CV_WHOLE_SEQ;
1115
1116
//printf("%d. %d. %d-th size = %d\n", gen, iter, i, sseq->count );
1117
1118
cvSeqInvert( seq );
1119
cvTsSimpleSeqInvert( sseq );
1120
1121
if( test_seq_block_consistence( i, seq, sseq->count ) < 0 )
1122
return;
1123
1124
if( sseq->count > 0 && cvtest::randInt(rng) % 2 == 0 )
1125
{
1126
slice.end_index = cvtest::randInt(rng) % sseq->count + 1;
1127
slice.start_index = cvtest::randInt(rng) % (sseq->count - slice.end_index + 1);
1128
slice.end_index += slice.start_index;
1129
}
1130
1131
cvCvtSeqToArray( seq, &buffer[0], slice );
1132
1133
slice.end_index = MIN( slice.end_index, sseq->count );
1134
CV_TS_SEQ_CHECK_CONDITION( sseq->count == 0 || memcmp( &buffer[0],
1135
sseq->array + slice.start_index*sseq->elem_size,
1136
(slice.end_index - slice.start_index)*sseq->elem_size ) == 0,
1137
"cvSeqInvert returned wrong result" );
1138
1139
for( k = 0; k < (sseq->count > 0 ? 10 : 0); k++ )
1140
{
1141
int idx0 = cvtest::randInt(rng) % sseq->count, idx = 0;
1142
elem0 = cvTsSimpleSeqElem( sseq, idx0 );
1143
elem = cvGetSeqElem( seq, idx0 );
1144
elem2 = cvSeqSearch( seq, elem0, k % 2 ? icvCmpSeqElems : 0, 0, &idx, seq );
1145
1146
CV_TS_SEQ_CHECK_CONDITION( elem != 0 &&
1147
memcmp( elem0, elem, seq->elem_size ) == 0,
1148
"cvSeqInvert gives incorrect result" );
1149
CV_TS_SEQ_CHECK_CONDITION( elem2 != 0 &&
1150
memcmp( elem0, elem2, seq->elem_size ) == 0 &&
1151
elem2 == cvGetSeqElem( seq, idx ),
1152
"cvSeqSearch failed (linear search)" );
1153
}
1154
1155
cvSeqSort( seq, icvCmpSeqElems, seq );
1156
1157
if( test_seq_block_consistence( i, seq, sseq->count ) < 0 )
1158
return;
1159
1160
if( sseq->count > 0 )
1161
{
1162
// !!! This is not thread-safe !!!
1163
icvCmpSeqElems2_elem_size = sseq->elem_size;
1164
qsort( sseq->array, sseq->count, sseq->elem_size, icvCmpSeqElems2 );
1165
1166
if( cvtest::randInt(rng) % 2 == 0 )
1167
{
1168
slice.end_index = cvtest::randInt(rng) % sseq->count + 1;
1169
slice.start_index = cvtest::randInt(rng) % (sseq->count - slice.end_index + 1);
1170
slice.end_index += slice.start_index;
1171
}
1172
}
1173
1174
cvCvtSeqToArray( seq, &buffer[0], slice );
1175
CV_TS_SEQ_CHECK_CONDITION( sseq->count == 0 || memcmp( &buffer[0],
1176
sseq->array + slice.start_index*sseq->elem_size,
1177
(slice.end_index - slice.start_index)*sseq->elem_size ) == 0,
1178
"cvSeqSort returned wrong result" );
1179
1180
for( k = 0; k < (sseq->count > 0 ? 10 : 0); k++ )
1181
{
1182
int idx0 = cvtest::randInt(rng) % sseq->count, idx = 0;
1183
elem0 = cvTsSimpleSeqElem( sseq, idx0 );
1184
elem = cvGetSeqElem( seq, idx0 );
1185
elem2 = cvSeqSearch( seq, elem0, icvCmpSeqElems, 1, &idx, seq );
1186
1187
CV_TS_SEQ_CHECK_CONDITION( elem != 0 &&
1188
memcmp( elem0, elem, seq->elem_size ) == 0,
1189
"cvSeqSort gives incorrect result" );
1190
CV_TS_SEQ_CHECK_CONDITION( elem2 != 0 &&
1191
memcmp( elem0, elem2, seq->elem_size ) == 0 &&
1192
elem2 == cvGetSeqElem( seq, idx ),
1193
"cvSeqSearch failed (binary search)" );
1194
}
1195
}
1196
1197
cvClearMemStorage( storage );
1198
}
1199
1200
storage.release();
1201
}
1202
}
1203
catch (const int &)
1204
{
1205
}
1206
}
1207
1208
1209
/////////////////////////////////////// set tests ///////////////////////////////////////
1210
1211
class Core_SetTest : public Core_DynStructBaseTest
1212
{
1213
public:
1214
Core_SetTest();
1215
virtual ~Core_SetTest();
1216
void clear();
1217
void run( int );
1218
1219
protected:
1220
//int test_seq_block_consistence( int struct_idx );
1221
int test_set_ops( int iters );
1222
};
1223
1224
1225
Core_SetTest::Core_SetTest()
1226
{
1227
}
1228
1229
Core_SetTest::~Core_SetTest()
1230
{
1231
clear();
1232
}
1233
1234
void Core_SetTest::clear()
1235
{
1236
for( size_t i = 0; i < simple_struct.size(); i++ )
1237
cvTsReleaseSimpleSet( (CvTsSimpleSet**)&simple_struct[i] );
1238
Core_DynStructBaseTest::clear();
1239
}
1240
1241
1242
int Core_SetTest::test_set_ops( int iters )
1243
{
1244
const int max_op = 4;
1245
int max_elem_size = 0;
1246
int idx, idx0;
1247
CvSetElem *elem = 0, *elem2 = 0, *elem3 = 0;
1248
schar* elem_data = 0;
1249
RNG& rng = ts->get_rng();
1250
//int max_active_count = 0, mean_active_count = 0;
1251
1252
for( int i = 0; i < struct_count; i++ )
1253
max_elem_size = MAX( max_elem_size, ((CvSeq*)cxcore_struct[i])->elem_size );
1254
1255
vector<schar> elem_buf(max_elem_size);
1256
Mat elem_mat;
1257
1258
for( iter = 0; iter < iters; iter++ )
1259
{
1260
struct_idx = cvtest::randInt(rng) % struct_count;
1261
1262
CvSet* cvset = (CvSet*)cxcore_struct[struct_idx];
1263
CvTsSimpleSet* sset = (CvTsSimpleSet*)simple_struct[struct_idx];
1264
int pure_elem_size = sset->elem_size - 1;
1265
int prev_total = cvset->total, prev_count = cvset->active_count;
1266
int op = cvtest::randInt(rng) % (iter <= iters/10 ? 2 : max_op);
1267
int by_ptr = op % 2 == 0;
1268
CvSetElem* first_free = cvset->free_elems;
1269
CvSetElem* next_free = first_free ? first_free->next_free : 0;
1270
int pass_data = 0;
1271
1272
if( iter > iters/10 && cvtest::randInt(rng)%200 == 0 ) // clear set
1273
{
1274
prev_count = cvset->total;
1275
cvClearSet( cvset );
1276
cvTsClearSimpleSet( sset );
1277
1278
CV_TS_SEQ_CHECK_CONDITION( cvset->active_count == 0 && cvset->total == 0 &&
1279
cvset->first == 0 && cvset->free_elems == 0 &&
1280
(cvset->free_blocks != 0 || prev_count == 0),
1281
"cvClearSet doesn't remove all the elements" );
1282
continue;
1283
}
1284
else if( op == 0 || op == 1 ) // add element
1285
{
1286
if( sset->free_count == 0 )
1287
continue;
1288
1289
elem_mat = Mat(1, cvset->elem_size, CV_8U, &elem_buf[0]);
1290
cvtest::randUni( rng, elem_mat, cvScalarAll(0), cvScalarAll(255) );
1291
elem = (CvSetElem*)&elem_buf[0];
1292
1293
if( by_ptr )
1294
{
1295
elem2 = cvSetNew( cvset );
1296
CV_TS_SEQ_CHECK_CONDITION( elem2 != 0, "cvSetNew returned NULL pointer" );
1297
}
1298
else
1299
{
1300
pass_data = cvtest::randInt(rng) % 2;
1301
idx = cvSetAdd( cvset, pass_data ? elem : 0, &elem2 );
1302
CV_TS_SEQ_CHECK_CONDITION( elem2 != 0 && elem2->flags == idx,
1303
"cvSetAdd returned NULL pointer or a wrong index" );
1304
}
1305
1306
elem_data = (schar*)elem + sizeof(int);
1307
1308
if( !pass_data )
1309
memcpy( (schar*)elem2 + sizeof(int), elem_data, pure_elem_size );
1310
1311
idx = elem2->flags;
1312
idx0 = cvTsSimpleSetAdd( sset, elem_data );
1313
elem3 = cvGetSetElem( cvset, idx );
1314
1315
CV_TS_SEQ_CHECK_CONDITION( CV_IS_SET_ELEM(elem3) &&
1316
idx == idx0 && elem3 == elem2 && (!pass_data ||
1317
memcmp( (char*)elem3 + sizeof(int), elem_data, pure_elem_size) == 0),
1318
"The added element is not correct" );
1319
1320
CV_TS_SEQ_CHECK_CONDITION( (!first_free || elem3 == first_free) &&
1321
(!next_free || cvset->free_elems == next_free) &&
1322
cvset->active_count == prev_count + 1,
1323
"The free node list is modified incorrectly" );
1324
}
1325
else if( op == 2 || op == 3 ) // remove element
1326
{
1327
idx = cvtest::randInt(rng) % sset->max_count;
1328
1329
if( sset->free_count == sset->max_count || idx >= sset->count )
1330
continue;
1331
1332
elem_data = cvTsSimpleSetFind(sset, idx);
1333
if( elem_data == 0 )
1334
continue;
1335
1336
elem = cvGetSetElem( cvset, idx );
1337
CV_TS_SEQ_CHECK_CONDITION( CV_IS_SET_ELEM(elem) && elem->flags == idx &&
1338
memcmp((char*)elem + sizeof(int), elem_data, pure_elem_size) == 0,
1339
"cvGetSetElem returned wrong element" );
1340
1341
if( by_ptr )
1342
{
1343
cvSetRemoveByPtr( cvset, elem );
1344
}
1345
else
1346
{
1347
cvSetRemove( cvset, idx );
1348
}
1349
1350
cvTsSimpleSetRemove( sset, idx );
1351
1352
CV_TS_SEQ_CHECK_CONDITION( !CV_IS_SET_ELEM(elem) && !cvGetSetElem(cvset, idx) &&
1353
(elem->flags & CV_SET_ELEM_IDX_MASK) == idx,
1354
"cvSetRemove[ByPtr] didn't release the element properly" );
1355
1356
CV_TS_SEQ_CHECK_CONDITION( elem->next_free == first_free &&
1357
cvset->free_elems == elem &&
1358
cvset->active_count == prev_count - 1,
1359
"The free node list has not been updated properly" );
1360
}
1361
1362
//max_active_count = MAX( max_active_count, cvset->active_count );
1363
//mean_active_count += cvset->active_count;
1364
CV_TS_SEQ_CHECK_CONDITION( cvset->active_count == sset->max_count - sset->free_count &&
1365
cvset->total >= cvset->active_count &&
1366
(cvset->total == 0 || cvset->total >= prev_total),
1367
"The total number of cvset elements is not correct" );
1368
1369
// CvSet and simple set do not necessary have the same "total" (active & free) number,
1370
// so pass "set->total" to skip that check
1371
test_seq_block_consistence( struct_idx, (CvSeq*)cvset, cvset->total );
1372
update_progressbar();
1373
}
1374
1375
return 0;
1376
}
1377
1378
1379
void Core_SetTest::run( int )
1380
{
1381
try
1382
{
1383
RNG& rng = ts->get_rng();
1384
double t;
1385
1386
clear();
1387
test_progress = -1;
1388
1389
simple_struct.resize(struct_count, 0);
1390
cxcore_struct.resize(struct_count, 0);
1391
1392
for( gen = 0; gen < generations; gen++ )
1393
{
1394
struct_idx = iter = -1;
1395
t = cvtest::randReal(rng)*(max_log_storage_block_size - min_log_storage_block_size) + min_log_storage_block_size;
1396
storage.reset(cvCreateMemStorage( cvRound( exp(t * CV_LOG2) ) ));
1397
1398
for( int i = 0; i < struct_count; i++ )
1399
{
1400
t = cvtest::randReal(rng)*(max_log_elem_size - min_log_elem_size) + min_log_elem_size;
1401
int pure_elem_size = cvRound( exp(t * CV_LOG2) );
1402
int elem_size = pure_elem_size + sizeof(int);
1403
elem_size = (elem_size + sizeof(size_t) - 1) & ~(sizeof(size_t)-1);
1404
elem_size = MAX( elem_size, (int)sizeof(CvSetElem) );
1405
elem_size = MIN( elem_size, (int)(storage->block_size - sizeof(void*) - sizeof(CvMemBlock) - sizeof(CvSeqBlock)) );
1406
pure_elem_size = MIN( pure_elem_size, elem_size-(int)sizeof(CvSetElem) );
1407
1408
cvTsReleaseSimpleSet( (CvTsSimpleSet**)&simple_struct[i] );
1409
simple_struct[i] = cvTsCreateSimpleSet( max_struct_size, pure_elem_size );
1410
cxcore_struct[i] = cvCreateSet( 0, sizeof(CvSet), elem_size, storage );
1411
}
1412
1413
if( test_set_ops( iterations*100 ) < 0 )
1414
return;
1415
1416
storage.release();
1417
}
1418
}
1419
catch(const int &)
1420
{
1421
}
1422
}
1423
1424
1425
/////////////////////////////////////// graph tests //////////////////////////////////
1426
1427
class Core_GraphTest : public Core_DynStructBaseTest
1428
{
1429
public:
1430
Core_GraphTest();
1431
virtual ~Core_GraphTest();
1432
void clear();
1433
void run( int );
1434
1435
protected:
1436
//int test_seq_block_consistence( int struct_idx );
1437
int test_graph_ops( int iters );
1438
};
1439
1440
1441
Core_GraphTest::Core_GraphTest()
1442
{
1443
}
1444
1445
Core_GraphTest::~Core_GraphTest()
1446
{
1447
clear();
1448
}
1449
1450
void Core_GraphTest::clear()
1451
{
1452
for( size_t i = 0; i < simple_struct.size(); i++ )
1453
cvTsReleaseSimpleGraph( (CvTsSimpleGraph**)&simple_struct[i] );
1454
Core_DynStructBaseTest::clear();
1455
}
1456
1457
1458
int Core_GraphTest::test_graph_ops( int iters )
1459
{
1460
const int max_op = 4;
1461
int i, k;
1462
int max_elem_size = 0;
1463
int idx, idx0;
1464
CvGraphVtx *vtx = 0, *vtx2 = 0, *vtx3 = 0;
1465
CvGraphEdge* edge = 0, *edge2 = 0;
1466
RNG& rng = ts->get_rng();
1467
//int max_active_count = 0, mean_active_count = 0;
1468
1469
for( i = 0; i < struct_count; i++ )
1470
{
1471
CvGraph* graph = (CvGraph*)cxcore_struct[i];
1472
max_elem_size = MAX( max_elem_size, graph->elem_size );
1473
max_elem_size = MAX( max_elem_size, graph->edges->elem_size );
1474
}
1475
1476
vector<schar> elem_buf(max_elem_size);
1477
Mat elem_mat;
1478
1479
for( iter = 0; iter < iters; iter++ )
1480
{
1481
struct_idx = cvtest::randInt(rng) % struct_count;
1482
CvGraph* graph = (CvGraph*)cxcore_struct[struct_idx];
1483
CvTsSimpleGraph* sgraph = (CvTsSimpleGraph*)simple_struct[struct_idx];
1484
CvSet* edges = graph->edges;
1485
schar *vtx_data;
1486
char *edge_data;
1487
int pure_vtx_size = sgraph->vtx->elem_size - 1,
1488
pure_edge_size = sgraph->edge_size - 1;
1489
int prev_vtx_total = graph->total,
1490
prev_edge_total = graph->edges->total,
1491
prev_vtx_count = graph->active_count,
1492
prev_edge_count = graph->edges->active_count;
1493
int op = cvtest::randInt(rng) % max_op;
1494
int pass_data = 0, vtx_degree0 = 0, vtx_degree = 0;
1495
CvSetElem *first_free, *next_free;
1496
1497
if( cvtest::randInt(rng) % 200 == 0 ) // clear graph
1498
{
1499
int prev_vtx_count2 = graph->total, prev_edge_count2 = graph->edges->total;
1500
1501
cvClearGraph( graph );
1502
cvTsClearSimpleGraph( sgraph );
1503
1504
CV_TS_SEQ_CHECK_CONDITION( graph->active_count == 0 && graph->total == 0 &&
1505
graph->first == 0 && graph->free_elems == 0 &&
1506
(graph->free_blocks != 0 || prev_vtx_count2 == 0),
1507
"The graph is not empty after clearing" );
1508
1509
CV_TS_SEQ_CHECK_CONDITION( edges->active_count == 0 && edges->total == 0 &&
1510
edges->first == 0 && edges->free_elems == 0 &&
1511
(edges->free_blocks != 0 || prev_edge_count2 == 0),
1512
"The graph is not empty after clearing" );
1513
}
1514
else if( op == 0 ) // add vertex
1515
{
1516
if( sgraph->vtx->free_count == 0 )
1517
continue;
1518
1519
first_free = graph->free_elems;
1520
next_free = first_free ? first_free->next_free : 0;
1521
1522
if( pure_vtx_size )
1523
{
1524
elem_mat = Mat(1, graph->elem_size, CV_8U, &elem_buf[0]);
1525
cvtest::randUni( rng, elem_mat, cvScalarAll(0), cvScalarAll(255) );
1526
}
1527
1528
vtx = (CvGraphVtx*)&elem_buf[0];
1529
idx0 = cvTsSimpleGraphAddVertex( sgraph, vtx + 1 );
1530
1531
pass_data = cvtest::randInt(rng) % 2;
1532
idx = cvGraphAddVtx( graph, pass_data ? vtx : 0, &vtx2 );
1533
1534
if( !pass_data && pure_vtx_size > 0 )
1535
memcpy( vtx2 + 1, vtx + 1, pure_vtx_size );
1536
1537
vtx3 = cvGetGraphVtx( graph, idx );
1538
1539
CV_TS_SEQ_CHECK_CONDITION( (CV_IS_SET_ELEM(vtx3) && vtx3->flags == idx &&
1540
vtx3->first == 0) || (idx == idx0 && vtx3 == vtx2 &&
1541
(!pass_data || pure_vtx_size == 0 ||
1542
memcmp(vtx3 + 1, vtx + 1, pure_vtx_size) == 0)),
1543
"The added element is not correct" );
1544
1545
CV_TS_SEQ_CHECK_CONDITION( (!first_free || first_free == (CvSetElem*)vtx3) &&
1546
(!next_free || graph->free_elems == next_free) &&
1547
graph->active_count == prev_vtx_count + 1,
1548
"The free node list is modified incorrectly" );
1549
}
1550
else if( op == 1 ) // remove vertex
1551
{
1552
idx = cvtest::randInt(rng) % sgraph->vtx->max_count;
1553
if( sgraph->vtx->free_count == sgraph->vtx->max_count || idx >= sgraph->vtx->count )
1554
continue;
1555
1556
vtx_data = cvTsSimpleGraphFindVertex(sgraph, idx);
1557
if( vtx_data == 0 )
1558
continue;
1559
1560
vtx_degree0 = cvTsSimpleGraphVertexDegree( sgraph, idx );
1561
first_free = graph->free_elems;
1562
1563
vtx = cvGetGraphVtx( graph, idx );
1564
CV_TS_SEQ_CHECK_CONDITION( CV_IS_SET_ELEM(vtx) && vtx->flags == idx &&
1565
(pure_vtx_size == 0 || memcmp( vtx + 1, vtx_data, pure_vtx_size) == 0),
1566
"cvGetGraphVtx returned wrong element" );
1567
1568
if( cvtest::randInt(rng) % 2 )
1569
{
1570
vtx_degree = cvGraphVtxDegreeByPtr( graph, vtx );
1571
cvGraphRemoveVtxByPtr( graph, vtx );
1572
}
1573
else
1574
{
1575
vtx_degree = cvGraphVtxDegree( graph, idx );
1576
cvGraphRemoveVtx( graph, idx );
1577
}
1578
1579
cvTsSimpleGraphRemoveVertex( sgraph, idx );
1580
1581
CV_TS_SEQ_CHECK_CONDITION( vtx_degree == vtx_degree0,
1582
"Number of incident edges is different in two graph representations" );
1583
1584
CV_TS_SEQ_CHECK_CONDITION( !CV_IS_SET_ELEM(vtx) && !cvGetGraphVtx(graph, idx) &&
1585
(vtx->flags & CV_SET_ELEM_IDX_MASK) == idx,
1586
"cvGraphRemoveVtx[ByPtr] didn't release the vertex properly" );
1587
1588
CV_TS_SEQ_CHECK_CONDITION( graph->edges->active_count == prev_edge_count - vtx_degree,
1589
"cvGraphRemoveVtx[ByPtr] didn't remove all the incident edges "
1590
"(or removed some extra)" );
1591
1592
CV_TS_SEQ_CHECK_CONDITION( ((CvSetElem*)vtx)->next_free == first_free &&
1593
graph->free_elems == (CvSetElem*)vtx &&
1594
graph->active_count == prev_vtx_count - 1,
1595
"The free node list has not been updated properly" );
1596
}
1597
else if( op == 2 ) // add edge
1598
{
1599
int v_idx[2] = {0,0}, res = 0;
1600
int v_prev_degree[2] = {0,0}, v_degree[2] = {0,0};
1601
1602
if( sgraph->vtx->free_count >= sgraph->vtx->max_count-1 )
1603
continue;
1604
1605
for( i = 0, k = 0; i < 10; i++ )
1606
{
1607
int j = cvtest::randInt(rng) % sgraph->vtx->count;
1608
vtx_data = cvTsSimpleGraphFindVertex( sgraph, j );
1609
if( vtx_data )
1610
{
1611
v_idx[k] = j;
1612
if( k == 0 )
1613
k++;
1614
else if( v_idx[0] != v_idx[1] &&
1615
cvTsSimpleGraphFindEdge( sgraph, v_idx[0], v_idx[1] ) == 0 )
1616
{
1617
k++;
1618
break;
1619
}
1620
}
1621
}
1622
1623
if( k < 2 )
1624
continue;
1625
1626
first_free = graph->edges->free_elems;
1627
next_free = first_free ? first_free->next_free : 0;
1628
1629
edge = cvFindGraphEdge( graph, v_idx[0], v_idx[1] );
1630
CV_TS_SEQ_CHECK_CONDITION( edge == 0, "Extra edge appeared in the graph" );
1631
1632
if( pure_edge_size > 0 )
1633
{
1634
elem_mat = Mat(1, graph->edges->elem_size, CV_8U, &elem_buf[0]);
1635
cvtest::randUni( rng, elem_mat, cvScalarAll(0), cvScalarAll(255) );
1636
}
1637
edge = (CvGraphEdge*)&elem_buf[0];
1638
1639
// assign some default weight that is easy to check for
1640
// consistensy, 'cause an edge weight is not stored
1641
// in the simple graph
1642
edge->weight = (float)(v_idx[0] + v_idx[1]);
1643
pass_data = cvtest::randInt(rng) % 2;
1644
1645
vtx = cvGetGraphVtx( graph, v_idx[0] );
1646
vtx2 = cvGetGraphVtx( graph, v_idx[1] );
1647
CV_TS_SEQ_CHECK_CONDITION( vtx != 0 && vtx2 != 0 && vtx->flags == v_idx[0] &&
1648
vtx2->flags == v_idx[1], "Some of the vertices are missing" );
1649
1650
if( cvtest::randInt(rng) % 2 )
1651
{
1652
v_prev_degree[0] = cvGraphVtxDegreeByPtr( graph, vtx );
1653
v_prev_degree[1] = cvGraphVtxDegreeByPtr( graph, vtx2 );
1654
res = cvGraphAddEdgeByPtr(graph, vtx, vtx2, pass_data ? edge : 0, &edge2);
1655
v_degree[0] = cvGraphVtxDegreeByPtr( graph, vtx );
1656
v_degree[1] = cvGraphVtxDegreeByPtr( graph, vtx2 );
1657
}
1658
else
1659
{
1660
v_prev_degree[0] = cvGraphVtxDegree( graph, v_idx[0] );
1661
v_prev_degree[1] = cvGraphVtxDegree( graph, v_idx[1] );
1662
res = cvGraphAddEdge(graph, v_idx[0], v_idx[1], pass_data ? edge : 0, &edge2);
1663
v_degree[0] = cvGraphVtxDegree( graph, v_idx[0] );
1664
v_degree[1] = cvGraphVtxDegree( graph, v_idx[1] );
1665
}
1666
1667
//edge3 = (CvGraphEdge*)cvGetSetElem( graph->edges, idx );
1668
CV_TS_SEQ_CHECK_CONDITION( res == 1 && edge2 != 0 && CV_IS_SET_ELEM(edge2) &&
1669
((edge2->vtx[0] == vtx && edge2->vtx[1] == vtx2) ||
1670
(!CV_IS_GRAPH_ORIENTED(graph) && edge2->vtx[0] == vtx2 && edge2->vtx[1] == vtx)) &&
1671
(!pass_data || pure_edge_size == 0 || memcmp( edge2 + 1, edge + 1, pure_edge_size ) == 0),
1672
"The edge has been added incorrectly" );
1673
1674
if( !pass_data )
1675
{
1676
if( pure_edge_size > 0 )
1677
memcpy( edge2 + 1, edge + 1, pure_edge_size );
1678
edge2->weight = edge->weight;
1679
}
1680
1681
CV_TS_SEQ_CHECK_CONDITION( v_degree[0] == v_prev_degree[0] + 1 &&
1682
v_degree[1] == v_prev_degree[1] + 1,
1683
"The vertices lists have not been updated properly" );
1684
1685
cvTsSimpleGraphAddEdge( sgraph, v_idx[0], v_idx[1], edge + 1 );
1686
1687
CV_TS_SEQ_CHECK_CONDITION( (!first_free || first_free == (CvSetElem*)edge2) &&
1688
(!next_free || graph->edges->free_elems == next_free) &&
1689
graph->edges->active_count == prev_edge_count + 1,
1690
"The free node list is modified incorrectly" );
1691
}
1692
else if( op == 3 ) // find & remove edge
1693
{
1694
int v_idx[2] = {0,0}, by_ptr;
1695
int v_prev_degree[2] = {0,0}, v_degree[2] = {0,0};
1696
1697
if( sgraph->vtx->free_count >= sgraph->vtx->max_count-1 )
1698
continue;
1699
1700
edge_data = 0;
1701
for( i = 0, k = 0; i < 10; i++ )
1702
{
1703
int j = cvtest::randInt(rng) % sgraph->vtx->count;
1704
vtx_data = cvTsSimpleGraphFindVertex( sgraph, j );
1705
if( vtx_data )
1706
{
1707
v_idx[k] = j;
1708
if( k == 0 )
1709
k++;
1710
else
1711
{
1712
edge_data = cvTsSimpleGraphFindEdge( sgraph, v_idx[0], v_idx[1] );
1713
if( edge_data )
1714
{
1715
k++;
1716
break;
1717
}
1718
}
1719
}
1720
}
1721
1722
if( k < 2 )
1723
continue;
1724
1725
by_ptr = cvtest::randInt(rng) % 2;
1726
first_free = graph->edges->free_elems;
1727
1728
vtx = cvGetGraphVtx( graph, v_idx[0] );
1729
vtx2 = cvGetGraphVtx( graph, v_idx[1] );
1730
CV_TS_SEQ_CHECK_CONDITION( vtx != 0 && vtx2 != 0 && vtx->flags == v_idx[0] &&
1731
vtx2->flags == v_idx[1], "Some of the vertices are missing" );
1732
1733
if( by_ptr )
1734
{
1735
edge = cvFindGraphEdgeByPtr( graph, vtx, vtx2 );
1736
v_prev_degree[0] = cvGraphVtxDegreeByPtr( graph, vtx );
1737
v_prev_degree[1] = cvGraphVtxDegreeByPtr( graph, vtx2 );
1738
}
1739
else
1740
{
1741
edge = cvFindGraphEdge( graph, v_idx[0], v_idx[1] );
1742
v_prev_degree[0] = cvGraphVtxDegree( graph, v_idx[0] );
1743
v_prev_degree[1] = cvGraphVtxDegree( graph, v_idx[1] );
1744
}
1745
1746
idx = edge->flags;
1747
1748
CV_TS_SEQ_CHECK_CONDITION( edge != 0 && edge->weight == v_idx[0] + v_idx[1] &&
1749
((edge->vtx[0] == vtx && edge->vtx[1] == vtx2) ||
1750
(!CV_IS_GRAPH_ORIENTED(graph) && edge->vtx[1] == vtx && edge->vtx[0] == vtx2)) &&
1751
(pure_edge_size == 0 || memcmp(edge + 1, edge_data, pure_edge_size) == 0),
1752
"An edge is missing or incorrect" );
1753
1754
if( by_ptr )
1755
{
1756
cvGraphRemoveEdgeByPtr( graph, vtx, vtx2 );
1757
edge2 = cvFindGraphEdgeByPtr( graph, vtx, vtx2 );
1758
v_degree[0] = cvGraphVtxDegreeByPtr( graph, vtx );
1759
v_degree[1] = cvGraphVtxDegreeByPtr( graph, vtx2 );
1760
}
1761
else
1762
{
1763
cvGraphRemoveEdge(graph, v_idx[0], v_idx[1] );
1764
edge2 = cvFindGraphEdge( graph, v_idx[0], v_idx[1] );
1765
v_degree[0] = cvGraphVtxDegree( graph, v_idx[0] );
1766
v_degree[1] = cvGraphVtxDegree( graph, v_idx[1] );
1767
}
1768
1769
CV_TS_SEQ_CHECK_CONDITION( !edge2 && !CV_IS_SET_ELEM(edge),
1770
"The edge has not been removed from the edge set" );
1771
1772
CV_TS_SEQ_CHECK_CONDITION( v_degree[0] == v_prev_degree[0] - 1 &&
1773
v_degree[1] == v_prev_degree[1] - 1,
1774
"The vertices lists have not been updated properly" );
1775
1776
cvTsSimpleGraphRemoveEdge( sgraph, v_idx[0], v_idx[1] );
1777
1778
CV_TS_SEQ_CHECK_CONDITION( graph->edges->free_elems == (CvSetElem*)edge &&
1779
graph->edges->free_elems->next_free == first_free &&
1780
graph->edges->active_count == prev_edge_count - 1,
1781
"The free edge list has not been modified properly" );
1782
}
1783
1784
//max_active_count = MAX( max_active_count, graph->active_count );
1785
//mean_active_count += graph->active_count;
1786
1787
CV_TS_SEQ_CHECK_CONDITION( graph->active_count == sgraph->vtx->max_count - sgraph->vtx->free_count &&
1788
graph->total >= graph->active_count &&
1789
(graph->total == 0 || graph->total >= prev_vtx_total),
1790
"The total number of graph vertices is not correct" );
1791
1792
CV_TS_SEQ_CHECK_CONDITION( graph->edges->total >= graph->edges->active_count &&
1793
(graph->edges->total == 0 || graph->edges->total >= prev_edge_total),
1794
"The total number of graph vertices is not correct" );
1795
1796
// CvGraph and simple graph do not necessary have the same "total" (active & free) number,
1797
// so pass "graph->total" (or "graph->edges->total") to skip that check
1798
test_seq_block_consistence( struct_idx, (CvSeq*)graph, graph->total );
1799
test_seq_block_consistence( struct_idx, (CvSeq*)graph->edges, graph->edges->total );
1800
update_progressbar();
1801
}
1802
1803
return 0;
1804
}
1805
1806
1807
void Core_GraphTest::run( int )
1808
{
1809
try
1810
{
1811
RNG& rng = ts->get_rng();
1812
int i, k;
1813
double t;
1814
1815
clear();
1816
test_progress = -1;
1817
1818
simple_struct.resize(struct_count, 0);
1819
cxcore_struct.resize(struct_count, 0);
1820
1821
for( gen = 0; gen < generations; gen++ )
1822
{
1823
struct_idx = iter = -1;
1824
t = cvtest::randReal(rng)*(max_log_storage_block_size - min_log_storage_block_size) + min_log_storage_block_size;
1825
int block_size = cvRound( exp(t * CV_LOG2) );
1826
block_size = MAX(block_size, (int)(sizeof(CvGraph) + sizeof(CvMemBlock) + sizeof(CvSeqBlock)));
1827
1828
storage.reset(cvCreateMemStorage(block_size));
1829
1830
for( i = 0; i < struct_count; i++ )
1831
{
1832
int pure_elem_size[2], elem_size[2];
1833
int is_oriented = (gen + i) % 2;
1834
for( k = 0; k < 2; k++ )
1835
{
1836
t = cvtest::randReal(rng)*(max_log_elem_size - min_log_elem_size) + min_log_elem_size;
1837
int pe = cvRound( exp(t * CV_LOG2) ) - 1; // pure_elem_size==0 does also make sense
1838
int delta = k == 0 ? sizeof(CvGraphVtx) : sizeof(CvGraphEdge);
1839
int e = pe + delta;
1840
e = (e + sizeof(size_t) - 1) & ~(sizeof(size_t)-1);
1841
e = MIN( e, (int)(storage->block_size - sizeof(CvMemBlock) -
1842
sizeof(CvSeqBlock) - sizeof(void*)) );
1843
pe = MIN(pe, e - delta);
1844
pure_elem_size[k] = pe;
1845
elem_size[k] = e;
1846
}
1847
1848
cvTsReleaseSimpleGraph( (CvTsSimpleGraph**)&simple_struct[i] );
1849
simple_struct[i] = cvTsCreateSimpleGraph( max_struct_size/4, pure_elem_size[0],
1850
pure_elem_size[1], is_oriented );
1851
cxcore_struct[i] = cvCreateGraph( is_oriented ? CV_ORIENTED_GRAPH : CV_GRAPH,
1852
sizeof(CvGraph), elem_size[0], elem_size[1],
1853
storage );
1854
}
1855
1856
if( test_graph_ops( iterations*10 ) < 0 )
1857
return;
1858
1859
storage.release();
1860
}
1861
}
1862
catch(const int &)
1863
{
1864
}
1865
}
1866
1867
1868
//////////// graph scan test //////////////
1869
1870
class Core_GraphScanTest : public Core_DynStructBaseTest
1871
{
1872
public:
1873
Core_GraphScanTest();
1874
void run( int );
1875
1876
protected:
1877
//int test_seq_block_consistence( int struct_idx );
1878
int create_random_graph( int );
1879
};
1880
1881
1882
Core_GraphScanTest::Core_GraphScanTest()
1883
{
1884
iterations = 100;
1885
struct_count = 1;
1886
}
1887
1888
1889
int Core_GraphScanTest::create_random_graph( int _struct_idx )
1890
{
1891
RNG& rng = ts->get_rng();
1892
int is_oriented = cvtest::randInt(rng) % 2;
1893
int i, vtx_count = cvtest::randInt(rng) % max_struct_size;
1894
int edge_count = cvtest::randInt(rng) % MAX(vtx_count*20, 1);
1895
CvGraph* graph;
1896
1897
struct_idx = _struct_idx;
1898
cxcore_struct[_struct_idx] = graph =
1899
cvCreateGraph(is_oriented ? CV_ORIENTED_GRAPH : CV_GRAPH,
1900
sizeof(CvGraph), sizeof(CvGraphVtx),
1901
sizeof(CvGraphEdge), storage );
1902
1903
for( i = 0; i < vtx_count; i++ )
1904
cvGraphAddVtx( graph );
1905
1906
assert( graph->active_count == vtx_count );
1907
1908
for( i = 0; i < edge_count; i++ )
1909
{
1910
int j = cvtest::randInt(rng) % vtx_count;
1911
int k = cvtest::randInt(rng) % vtx_count;
1912
1913
if( j != k )
1914
cvGraphAddEdge( graph, j, k );
1915
}
1916
1917
assert( graph->active_count == vtx_count && graph->edges->active_count <= edge_count );
1918
1919
return 0;
1920
}
1921
1922
1923
void Core_GraphScanTest::run( int )
1924
{
1925
CvGraphScanner* scanner = 0;
1926
try
1927
{
1928
RNG& rng = ts->get_rng();
1929
vector<uchar> vtx_mask, edge_mask;
1930
double t;
1931
int i;
1932
1933
clear();
1934
test_progress = -1;
1935
1936
cxcore_struct.resize(struct_count, 0);
1937
1938
for( gen = 0; gen < generations; gen++ )
1939
{
1940
struct_idx = iter = -1;
1941
t = cvtest::randReal(rng)*(max_log_storage_block_size - min_log_storage_block_size) + min_log_storage_block_size;
1942
int storage_blocksize = cvRound( exp(t * CV_LOG2) );
1943
storage_blocksize = MAX(storage_blocksize, (int)(sizeof(CvGraph) + sizeof(CvMemBlock) + sizeof(CvSeqBlock)));
1944
storage_blocksize = MAX(storage_blocksize, (int)(sizeof(CvGraphEdge) + sizeof(CvMemBlock) + sizeof(CvSeqBlock)));
1945
storage_blocksize = MAX(storage_blocksize, (int)(sizeof(CvGraphVtx) + sizeof(CvMemBlock) + sizeof(CvSeqBlock)));
1946
storage.reset(cvCreateMemStorage(storage_blocksize));
1947
1948
if( gen == 0 )
1949
{
1950
// special regression test for one sample graph.
1951
// !!! ATTENTION !!! The test relies on the particular order of the inserted edges
1952
// (LIFO: the edge inserted last goes first in the list of incident edges).
1953
// if it is changed, the test will have to be modified.
1954
1955
int vtx_count = -1, edge_count = 0, edges[][3] =
1956
{
1957
{0,4,'f'}, {0,1,'t'}, {1,4,'t'}, {1,2,'t'}, {2,3,'t'}, {4,3,'c'}, {3,1,'b'},
1958
{5,7,'t'}, {7,5,'b'}, {5,6,'t'}, {6,0,'c'}, {7,6,'c'}, {6,4,'c'}, {-1,-1,0}
1959
};
1960
1961
CvGraph* graph = cvCreateGraph( CV_ORIENTED_GRAPH, sizeof(CvGraph),
1962
sizeof(CvGraphVtx), sizeof(CvGraphEdge), storage );
1963
1964
for( i = 0; edges[i][0] >= 0; i++ )
1965
{
1966
vtx_count = MAX( vtx_count, edges[i][0] );
1967
vtx_count = MAX( vtx_count, edges[i][1] );
1968
}
1969
vtx_count++;
1970
1971
for( i = 0; i < vtx_count; i++ )
1972
cvGraphAddVtx( graph );
1973
1974
for( i = 0; edges[i][0] >= 0; i++ )
1975
{
1976
CvGraphEdge* edge;
1977
cvGraphAddEdge( graph, edges[i][0], edges[i][1], 0, &edge );
1978
edge->weight = (float)edges[i][2];
1979
}
1980
1981
edge_count = i;
1982
scanner = cvCreateGraphScanner( graph, 0, CV_GRAPH_ALL_ITEMS );
1983
1984
for(;;)
1985
{
1986
int code, a = -1, b = -1;
1987
const char* event = "";
1988
code = cvNextGraphItem( scanner );
1989
1990
switch( code )
1991
{
1992
case CV_GRAPH_VERTEX:
1993
event = "Vertex";
1994
vtx_count--;
1995
a = cvGraphVtxIdx( graph, scanner->vtx );
1996
break;
1997
case CV_GRAPH_TREE_EDGE:
1998
event = "Tree Edge";
1999
edge_count--;
2000
CV_TS_SEQ_CHECK_CONDITION( scanner->edge->weight == (float)'t',
2001
"Invalid edge type" );
2002
a = cvGraphVtxIdx( graph, scanner->vtx );
2003
b = cvGraphVtxIdx( graph, scanner->dst );
2004
break;
2005
case CV_GRAPH_BACK_EDGE:
2006
event = "Back Edge";
2007
edge_count--;
2008
CV_TS_SEQ_CHECK_CONDITION( scanner->edge->weight == (float)'b',
2009
"Invalid edge type" );
2010
a = cvGraphVtxIdx( graph, scanner->vtx );
2011
b = cvGraphVtxIdx( graph, scanner->dst );
2012
break;
2013
case CV_GRAPH_CROSS_EDGE:
2014
event = "Cross Edge";
2015
edge_count--;
2016
CV_TS_SEQ_CHECK_CONDITION( scanner->edge->weight == (float)'c',
2017
"Invalid edge type" );
2018
a = cvGraphVtxIdx( graph, scanner->vtx );
2019
b = cvGraphVtxIdx( graph, scanner->dst );
2020
break;
2021
case CV_GRAPH_FORWARD_EDGE:
2022
event = "Forward Edge";
2023
edge_count--;
2024
CV_TS_SEQ_CHECK_CONDITION( scanner->edge->weight == (float)'f',
2025
"Invalid edge type" );
2026
a = cvGraphVtxIdx( graph, scanner->vtx );
2027
b = cvGraphVtxIdx( graph, scanner->dst );
2028
break;
2029
case CV_GRAPH_BACKTRACKING:
2030
event = "Backtracking";
2031
a = cvGraphVtxIdx( graph, scanner->vtx );
2032
break;
2033
case CV_GRAPH_NEW_TREE:
2034
event = "New search tree";
2035
break;
2036
case CV_GRAPH_OVER:
2037
event = "End of procedure";
2038
break;
2039
default:
2040
CV_TS_SEQ_CHECK_CONDITION( 0, "Invalid code appeared during graph scan" );
2041
}
2042
2043
ts->printf( cvtest::TS::LOG, "%s", event );
2044
if( a >= 0 )
2045
{
2046
if( b >= 0 )
2047
ts->printf( cvtest::TS::LOG, ": (%d,%d)", a, b );
2048
else
2049
ts->printf( cvtest::TS::LOG, ": %d", a );
2050
}
2051
2052
ts->printf( cvtest::TS::LOG, "\n" );
2053
2054
if( code < 0 )
2055
break;
2056
}
2057
2058
CV_TS_SEQ_CHECK_CONDITION( vtx_count == 0 && edge_count == 0,
2059
"Not every vertex/edge has been visited" );
2060
update_progressbar();
2061
2062
cvReleaseGraphScanner( &scanner );
2063
}
2064
2065
// for a random graph the test just checks that every graph vertex and
2066
// every edge is vitisted during the scan
2067
for( iter = 0; iter < iterations; iter++ )
2068
{
2069
create_random_graph(0);
2070
CvGraph* graph = (CvGraph*)cxcore_struct[0];
2071
2072
// iterate twice to check that scanner doesn't damage the graph
2073
for( i = 0; i < 2; i++ )
2074
{
2075
CvGraphVtx* start_vtx = cvtest::randInt(rng) % 2 || graph->active_count == 0 ? 0 :
2076
cvGetGraphVtx( graph, cvtest::randInt(rng) % graph->active_count );
2077
2078
scanner = cvCreateGraphScanner( graph, start_vtx, CV_GRAPH_ALL_ITEMS );
2079
2080
vtx_mask.resize(0);
2081
vtx_mask.resize(graph->active_count, 0);
2082
edge_mask.resize(0);
2083
edge_mask.resize(graph->edges->active_count, 0);
2084
2085
for(;;)
2086
{
2087
int code = cvNextGraphItem( scanner );
2088
2089
if( code == CV_GRAPH_OVER )
2090
break;
2091
else if( code & CV_GRAPH_ANY_EDGE )
2092
{
2093
int edge_idx = scanner->edge->flags & CV_SET_ELEM_IDX_MASK;
2094
2095
CV_TS_SEQ_CHECK_CONDITION( edge_idx < graph->edges->active_count &&
2096
edge_mask[edge_idx] == 0,
2097
"The edge is not found or visited for the second time" );
2098
edge_mask[edge_idx] = 1;
2099
}
2100
else if( code & CV_GRAPH_VERTEX )
2101
{
2102
int vtx_idx = scanner->vtx->flags & CV_SET_ELEM_IDX_MASK;
2103
2104
CV_TS_SEQ_CHECK_CONDITION( vtx_idx < graph->active_count &&
2105
vtx_mask[vtx_idx] == 0,
2106
"The vtx is not found or visited for the second time" );
2107
vtx_mask[vtx_idx] = 1;
2108
}
2109
}
2110
2111
cvReleaseGraphScanner( &scanner );
2112
2113
CV_TS_SEQ_CHECK_CONDITION( cvtest::norm(Mat(vtx_mask),CV_L1) == graph->active_count &&
2114
cvtest::norm(Mat(edge_mask),CV_L1) == graph->edges->active_count,
2115
"Some vertices or edges have not been visited" );
2116
update_progressbar();
2117
}
2118
cvClearMemStorage( storage );
2119
}
2120
2121
storage.release();
2122
}
2123
}
2124
catch(const int &)
2125
{
2126
}
2127
}
2128
2129
2130
TEST(Core_DS_Seq, basic_operations) { Core_SeqBaseTest test; test.safe_run(); }
2131
TEST(Core_DS_Seq, sort_invert) { Core_SeqSortInvTest test; test.safe_run(); }
2132
TEST(Core_DS_Set, basic_operations) { Core_SetTest test; test.safe_run(); }
2133
TEST(Core_DS_Graph, basic_operations) { Core_GraphTest test; test.safe_run(); }
2134
TEST(Core_DS_Graph, scan) { Core_GraphScanTest test; test.safe_run(); }
2135
2136
}} // namespace
2137
2138