1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.hipparchus.util;
23
24 import org.hipparchus.exception.MathIllegalArgumentException;
25 import org.junit.jupiter.api.Test;
26
27 import java.lang.reflect.Constructor;
28 import java.lang.reflect.InvocationTargetException;
29 import java.lang.reflect.Method;
30 import java.util.Comparator;
31 import java.util.Iterator;
32 import java.util.NoSuchElementException;
33
34 import static org.junit.jupiter.api.Assertions.assertEquals;
35 import static org.junit.jupiter.api.Assertions.assertFalse;
36 import static org.junit.jupiter.api.Assertions.assertThrows;
37 import static org.junit.jupiter.api.Assertions.assertTrue;
38 import static org.junit.jupiter.api.Assertions.fail;
39
40
41
42
43 class CombinationsTest {
44 @Test
45 void testAccessor1() {
46 final int n = 5;
47 final int k = 3;
48 assertEquals(n, new Combinations(n, k).getN());
49 }
50
51 @Test
52 void testAccessor2() {
53 final int n = 5;
54 final int k = 3;
55 assertEquals(k, new Combinations(n, k).getK());
56 }
57
58 @Test
59 void testLexicographicIterator() {
60 checkLexicographicIterator(new Combinations(5, 3));
61 checkLexicographicIterator(new Combinations(6, 4));
62 checkLexicographicIterator(new Combinations(8, 2));
63 checkLexicographicIterator(new Combinations(6, 1));
64 checkLexicographicIterator(new Combinations(3, 3));
65 checkLexicographicIterator(new Combinations(1, 1));
66 checkLexicographicIterator(new Combinations(1, 0));
67 checkLexicographicIterator(new Combinations(0, 0));
68 checkLexicographicIterator(new Combinations(4, 2));
69 checkLexicographicIterator(new Combinations(123, 2));
70 }
71
72 @Test
73 void testLexicographicComparatorWrongIterate1() {
74 assertThrows(MathIllegalArgumentException.class, () -> {
75 final int n = 5;
76 final int k = 3;
77 final Comparator<int[]> comp = new Combinations(n, k).comparator();
78 comp.compare(new int[]{1}, new int[]{0, 1, 2});
79 });
80 }
81
82 @Test
83 void testLexicographicComparatorWrongIterate2() {
84 assertThrows(MathIllegalArgumentException.class, () -> {
85 final int n = 5;
86 final int k = 3;
87 final Comparator<int[]> comp = new Combinations(n, k).comparator();
88 comp.compare(new int[]{0, 1, 2}, new int[]{0, 1, 2, 3});
89 });
90 }
91
92 @Test
93 void testLexicographicComparatorWrongIterate3() {
94 assertThrows(MathIllegalArgumentException.class, () -> {
95 final int n = 5;
96 final int k = 3;
97 final Comparator<int[]> comp = new Combinations(n, k).comparator();
98 comp.compare(new int[]{1, 2, 5}, new int[]{0, 1, 2});
99 });
100 }
101
102 @Test
103 void testLexicographicComparatorWrongIterate4() {
104 assertThrows(MathIllegalArgumentException.class, () -> {
105 final int n = 5;
106 final int k = 3;
107 final Comparator<int[]> comp = new Combinations(n, k).comparator();
108 comp.compare(new int[]{1, 2, 4}, new int[]{-1, 1, 2});
109 });
110 }
111
112 @Test
113 void testLexicographicComparator() {
114 final int n = 5;
115 final int k = 3;
116 final Comparator<int[]> comp = new Combinations(n, k).comparator();
117 assertEquals(1, comp.compare(new int[] {1, 2, 4},
118 new int[] {1, 2, 3}));
119 assertEquals(-1, comp.compare(new int[] {0, 1, 4},
120 new int[] {0, 2, 4}));
121 assertEquals(0, comp.compare(new int[] {1, 3, 4},
122 new int[] {1, 3, 4}));
123 }
124
125
126
127
128 @Test
129 void testLexicographicComparatorUnsorted() {
130 final int n = 5;
131 final int k = 3;
132 final Comparator<int[]> comp = new Combinations(n, k).comparator();
133 assertEquals(1, comp.compare(new int[] {1, 4, 2},
134 new int[] {1, 3, 2}));
135 assertEquals(-1, comp.compare(new int[] {0, 4, 1},
136 new int[] {0, 4, 2}));
137 assertEquals(0, comp.compare(new int[] {1, 4, 3},
138 new int[] {1, 3, 4}));
139 }
140
141 @Test
142 void testEmptyCombination() {
143 final Iterator<int[]> iter = new Combinations(12345, 0).iterator();
144 assertTrue(iter.hasNext());
145 final int[] c = iter.next();
146 assertEquals(0, c.length);
147 assertFalse(iter.hasNext());
148 }
149
150 @Test
151 void testFullSetCombination() {
152 final int n = 67;
153 final Iterator<int[]> iter = new Combinations(n, n).iterator();
154 assertTrue(iter.hasNext());
155 final int[] c = iter.next();
156 assertEquals(n, c.length);
157
158 for (int i = 0; i < n; i++) {
159 assertEquals(i, c[i]);
160 }
161
162 assertFalse(iter.hasNext());
163 }
164
165
166
167
168
169
170
171
172 private void checkLexicographicIterator(Combinations c) {
173 final Comparator<int[]> comp = c.comparator();
174 final int n = c.getN();
175 final int k = c.getK();
176
177 int[] lastIterate = null;
178
179 long numIterates = 0;
180 for (int[] iterate : c) {
181 assertEquals(k, iterate.length);
182
183
184 if (lastIterate != null) {
185 assertEquals(1, comp.compare(iterate, lastIterate));
186 }
187
188
189 for (int i = 1; i < iterate.length; i++) {
190 assertTrue(iterate[i] > iterate[i - 1]);
191 }
192
193 lastIterate = iterate;
194 ++numIterates;
195 }
196
197
198 assertEquals(CombinatoricsUtils.binomialCoefficient(n, k),
199 numIterates);
200 }
201
202 @Test
203 void testCombinationsIteratorFail() {
204 try {
205 new Combinations(4, 5).iterator();
206 fail("expecting MathIllegalArgumentException");
207 } catch (MathIllegalArgumentException ex) {
208
209 }
210
211 try {
212 new Combinations(-1, -2).iterator();
213 fail("expecting MathIllegalArgumentException");
214 } catch (MathIllegalArgumentException ex) {
215
216 }
217 }
218
219 @Test
220 void testLexicographicIteratorUnreachable() {
221
222
223
224 try {
225 Class<?> lexicographicIteratorClass = null;
226 for (Class<?> c : Combinations.class.getDeclaredClasses()) {
227 if (c.getCanonicalName().endsWith(".LexicographicIterator")) {
228 lexicographicIteratorClass = c;
229 }
230 }
231 Constructor<?> ctr = lexicographicIteratorClass.getDeclaredConstructor(Integer.TYPE, Integer.TYPE);
232 Method hasNext = lexicographicIteratorClass.getDeclaredMethod("hasNext");
233 Method next = lexicographicIteratorClass.getDeclaredMethod("next");
234 Method remove = lexicographicIteratorClass.getDeclaredMethod("remove");
235 assertFalse((Boolean) hasNext.invoke(ctr.newInstance(3, 0)));
236 assertFalse((Boolean) hasNext.invoke(ctr.newInstance(3, 3)));
237 assertTrue((Boolean) hasNext.invoke(ctr.newInstance(3, 2)));
238 try {
239 next.invoke(ctr.newInstance(3, 0));
240 fail("an exception should have been thrown");
241 } catch (InvocationTargetException ite) {
242 assertTrue(ite.getCause() instanceof NoSuchElementException);
243 }
244 try {
245 remove.invoke(ctr.newInstance(3, 2));
246 fail("an exception should have been thrown");
247 } catch (InvocationTargetException ite) {
248 assertTrue(ite.getCause() instanceof UnsupportedOperationException);
249 }
250 } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException |
251 InvocationTargetException | InstantiationException e) {
252 fail(e.getLocalizedMessage());
253 }
254 }
255
256 @Test
257 void testSingletonIteratorUnreachable() {
258
259 try {
260 Class<?> singletonIteratorClass = null;
261 for (Class<?> c : Combinations.class.getDeclaredClasses()) {
262 if (c.getCanonicalName().endsWith(".SingletonIterator")) {
263 singletonIteratorClass = c;
264 }
265 }
266 Constructor<?> ctr = singletonIteratorClass.getDeclaredConstructor(Integer.TYPE);
267 Method hasNext = singletonIteratorClass.getDeclaredMethod("hasNext");
268 Method next = singletonIteratorClass.getDeclaredMethod("next");
269 Method remove = singletonIteratorClass.getDeclaredMethod("remove");
270 Object iterator = ctr.newInstance(3);
271 assertTrue((Boolean) hasNext.invoke(iterator));
272 int[] ret = (int[]) next.invoke(iterator);
273 assertEquals(3, ret.length);
274 assertEquals(0, ret[0]);
275 assertEquals(1, ret[1]);
276 assertEquals(2, ret[2]);
277 assertFalse((Boolean) hasNext.invoke(iterator));
278 try {
279 next.invoke(iterator);
280 fail("an exception should have been thrown");
281 } catch (InvocationTargetException ite) {
282 assertTrue(ite.getCause() instanceof NoSuchElementException);
283 }
284 try {
285 remove.invoke(iterator);
286 fail("an exception should have been thrown");
287 } catch (InvocationTargetException ite) {
288 assertTrue(ite.getCause() instanceof UnsupportedOperationException);
289 }
290 } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException |
291 InvocationTargetException | InstantiationException e) {
292 fail(e.getLocalizedMessage());
293 }
294 }
295
296 }