1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2021 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16 /**@file pqueue.c
17 * @brief unit tests for priority queue
18 * @author Gregor Hendel
19 */
20
21 #include "scip/pub_misc.h"
22 #include "scip/scip.h"
23
24 #include "include/scip_test.h"
25
26 #define EPS 1e-04
27
28 struct TestContainer
29 {
30 int val;
31 int pos;
32 };
33
34 int values1[] = {
35 5,
36 4,
37 6,
38 7,
39 10
40 };
41
42 int n1 = (int)sizeof(values1) / (int)sizeof(int);
43
44 typedef struct TestContainer TC;
45
46 static
SCIP_DECL_SORTPTRCOMP(cmpTestContainer)47 SCIP_DECL_SORTPTRCOMP(cmpTestContainer)
48 {
49 TC* t1 = (TC*)elem1;
50 TC* t2 = (TC*)elem2;
51
52 return t1->val - t2->val;
53 }
54
55 static
SCIP_DECL_PQUEUEELEMCHGPOS(elemChgPosTestContainer)56 SCIP_DECL_PQUEUEELEMCHGPOS(elemChgPosTestContainer)
57 {
58 TC* t = (TC*)elem;
59 t->pos = newpos;
60 }
61
62 SCIP_PQUEUE* pqueue;
63 SCIP* scip;
64
65 /** initialize values of test containers */
66 static
initTestContainers(TC * tcs,int * vals,int nvals)67 void initTestContainers(
68 TC* tcs,
69 int* vals,
70 int nvals
71 )
72 {
73 int i;
74 /* initialize values and positions */
75 for( i = 0; i < nvals; ++i )
76 {
77 tcs[i].val = vals[i];
78 tcs[i].pos = -1;
79 }
80 }
81
82 /** find test container with minimum value, return position */
83 static
tcargmin(TC * tcs,int ntcs)84 int tcargmin(
85 TC* tcs,
86 int ntcs
87 )
88 {
89 int i;
90 int minidx = 0;
91
92 /* find minimum and store its index */
93 for( i = 1; i < ntcs; ++i )
94 {
95 if( tcs[i].val < tcs[minidx].val )
96 minidx = i;
97 }
98
99 return minidx;
100 }
101
102 /** insert elements into pqueue and assert that the length is correct */
103 static
insertIntoPQueue(SCIP_PQUEUE * pqueue_local,TC * tcs,int ntcs)104 SCIP_RETCODE insertIntoPQueue(
105 SCIP_PQUEUE* pqueue_local,
106 TC* tcs,
107 int ntcs
108 )
109 {
110 int i;
111
112 /* insert each element into the queue */
113 for( i = 0; i < ntcs; ++i )
114 {
115 int minidx;
116 SCIP_CALL( SCIPpqueueInsert(pqueue_local, (void *)(&tcs[i])) );
117
118 cr_assert_eq(SCIPpqueueNElems(pqueue_local), i + 1);
119 minidx = tcargmin(tcs, i + 1);
120 cr_assert_eq(tcs[minidx].val, ((TC*)SCIPpqueueFirst(pqueue_local))->val);
121 }
122
123 return SCIP_OKAY;
124 }
125
126 /** delete elements from pqueue by position */
127 static
deleteFromPQueue(SCIP_PQUEUE * pqueue_local,TC * tcs,int ntcs)128 void deleteFromPQueue(
129 SCIP_PQUEUE* pqueue_local,
130 TC* tcs,
131 int ntcs
132 )
133 {
134 int i;
135 /* remove elements in the same order in which they were inserted */
136 for( i = 0; i < ntcs; ++i )
137 {
138 int elempos = tcs[i].pos;
139 int minidx = tcargmin(&tcs[i], ntcs - i) + i;
140
141 /* ensure that the minimum element */
142 cr_assert_eq(tcs[minidx].val, ((TC*)SCIPpqueueFirst(pqueue_local))->val);
143 cr_assert(elempos < SCIPpqueueNElems(pqueue_local));
144 cr_assert_eq(SCIPpqueueElems(pqueue_local)[elempos], (void*)(&tcs[i]));
145 SCIPpqueueDelPos(pqueue_local, elempos);
146 }
147 }
148
149
150 /* TEST SUITE */
151 static
setup(void)152 void setup(void)
153 {
154 SCIP_CALL( SCIPcreate(&scip) );
155
156 SCIP_CALL( SCIPpqueueCreate(&pqueue, n1, 1.1, cmpTestContainer, elemChgPosTestContainer) );
157 }
158
159 static
teardown(void)160 void teardown(void)
161 {
162 SCIPpqueueFree(&pqueue);
163
164 SCIP_CALL( SCIPfree(&scip) );
165 }
166
167
168
169 TestSuite(pqueue, .init = setup, .fini = teardown);
170
171 /* TESTS */
Test(pqueue,create_and_free)172 Test(pqueue, create_and_free)
173 {
174 /* calls setup and teardown */
175 }
176
177
178 Test(pqueue, insert, .description="test insertion")
179 {
180 int i;
181 TC testc[n1];
182 TC* testc2[n1];
183
184 /* initialize values to those in values1 */
185 initTestContainers(testc, values1, n1);
186
187 /* insert test elements into pqueue */
188 SCIP_CALL( insertIntoPQueue(pqueue, testc, n1) );
189
190 /* remove elements from priority queue */
191 i = 0;
192 while( SCIPpqueueNElems(pqueue) )
193 testc2[i++] = (TC*)SCIPpqueueRemove(pqueue);
194
195 /* test if elements are sorted in increasing order */
196 for( i = 0; i < n1 - 1; ++i )
197 cr_assert(testc2[i]->val <= testc2[i+1]->val);
198 }
199
200 Test(pqueue, delpos, .description="test deletion using positions")
201 {
202 TC testc[n1];
203
204 /* initialize values to those in values1 */
205 initTestContainers(testc, values1, n1);
206
207 /* insert test elements into pqueue */
208 SCIP_CALL( insertIntoPQueue(pqueue, testc, n1) );
209
210 /* remove elements in the same order in which they were inserted */
211 deleteFromPQueue(pqueue, testc, n1);
212 }
213
214 #define N2 50
215 #define NSHUF 1000
216 Test(pqueue, insert_and_delete_random, .description="test random value permutations to cover extreme cases")
217 {
218 int i;
219 int s;
220 TC testc[N2];
221 int values2[N2];
222
223 SCIP_RANDNUMGEN* rng;
224
225 /* initialize values array */
226 for( i = 0; i < N2; ++i )
227 values2[i] = i + 1;
228
229 /* cover cases by shuffling the values array a couple of times */
230 SCIP_CALL( SCIPcreateRandom(scip, &rng, 42, TRUE) );
231 for( s = 0; s < NSHUF; ++s )
232 {
233 SCIPrandomPermuteIntArray(rng, values2, 0, N2);
234
235 /* initialize values to those in values2 */
236 initTestContainers(testc, values2, N2);
237
238 /* insert elements into pqueue */
239 SCIP_CALL( insertIntoPQueue(pqueue, testc, N2) );
240
241 /* remove elements in the same order in which they were inserted */
242 deleteFromPQueue(pqueue, testc, N2);
243 }
244
245 SCIPfreeRandom(scip, &rng);
246 }
247