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