1*9e3b08aeSAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2*9e3b08aeSAndroid Build Coastguard Worker // -*- mode: C++ -*-
3*9e3b08aeSAndroid Build Coastguard Worker //
4*9e3b08aeSAndroid Build Coastguard Worker // Copyright 2021-2024 Google LLC
5*9e3b08aeSAndroid Build Coastguard Worker //
6*9e3b08aeSAndroid Build Coastguard Worker // Licensed under the Apache License v2.0 with LLVM Exceptions (the
7*9e3b08aeSAndroid Build Coastguard Worker // "License"); you may not use this file except in compliance with the
8*9e3b08aeSAndroid Build Coastguard Worker // License. You may obtain a copy of the License at
9*9e3b08aeSAndroid Build Coastguard Worker //
10*9e3b08aeSAndroid Build Coastguard Worker // https://llvm.org/LICENSE.txt
11*9e3b08aeSAndroid Build Coastguard Worker //
12*9e3b08aeSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
13*9e3b08aeSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
14*9e3b08aeSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15*9e3b08aeSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
16*9e3b08aeSAndroid Build Coastguard Worker // limitations under the License.
17*9e3b08aeSAndroid Build Coastguard Worker //
18*9e3b08aeSAndroid Build Coastguard Worker // Author: Giuliano Procida
19*9e3b08aeSAndroid Build Coastguard Worker
20*9e3b08aeSAndroid Build Coastguard Worker #include "order.h"
21*9e3b08aeSAndroid Build Coastguard Worker
22*9e3b08aeSAndroid Build Coastguard Worker #include <cstddef>
23*9e3b08aeSAndroid Build Coastguard Worker #include <optional>
24*9e3b08aeSAndroid Build Coastguard Worker #include <random>
25*9e3b08aeSAndroid Build Coastguard Worker #include <sstream>
26*9e3b08aeSAndroid Build Coastguard Worker #include <string>
27*9e3b08aeSAndroid Build Coastguard Worker #include <tuple>
28*9e3b08aeSAndroid Build Coastguard Worker #include <utility>
29*9e3b08aeSAndroid Build Coastguard Worker #include <vector>
30*9e3b08aeSAndroid Build Coastguard Worker
31*9e3b08aeSAndroid Build Coastguard Worker #include <catch2/catch.hpp>
32*9e3b08aeSAndroid Build Coastguard Worker
33*9e3b08aeSAndroid Build Coastguard Worker namespace Test {
34*9e3b08aeSAndroid Build Coastguard Worker
35*9e3b08aeSAndroid Build Coastguard Worker // Safe for small k!
Factorial(size_t k)36*9e3b08aeSAndroid Build Coastguard Worker size_t Factorial(size_t k) {
37*9e3b08aeSAndroid Build Coastguard Worker size_t count = 1;
38*9e3b08aeSAndroid Build Coastguard Worker for (size_t i = 1; i <= k; ++i) {
39*9e3b08aeSAndroid Build Coastguard Worker count *= i;
40*9e3b08aeSAndroid Build Coastguard Worker }
41*9e3b08aeSAndroid Build Coastguard Worker return count;
42*9e3b08aeSAndroid Build Coastguard Worker }
43*9e3b08aeSAndroid Build Coastguard Worker
44*9e3b08aeSAndroid Build Coastguard Worker TEST_CASE("hand-curated permutation") {
45*9e3b08aeSAndroid Build Coastguard Worker std::vector<std::string> data = {"emily", "george", "rose", "ted"};
46*9e3b08aeSAndroid Build Coastguard Worker std::vector<size_t> permutation = {2, 1, 3, 0};
47*9e3b08aeSAndroid Build Coastguard Worker const std::vector<std::string> expected = {"rose", "george", "ted", "emily"};
48*9e3b08aeSAndroid Build Coastguard Worker const std::vector<size_t> identity = {0, 1, 2, 3};
49*9e3b08aeSAndroid Build Coastguard Worker stg::Permute(data, permutation);
50*9e3b08aeSAndroid Build Coastguard Worker CHECK(data == expected);
51*9e3b08aeSAndroid Build Coastguard Worker CHECK(permutation == identity);
52*9e3b08aeSAndroid Build Coastguard Worker }
53*9e3b08aeSAndroid Build Coastguard Worker
54*9e3b08aeSAndroid Build Coastguard Worker template <typename G>
MakePermutation(size_t k,G & gen)55*9e3b08aeSAndroid Build Coastguard Worker std::vector<size_t> MakePermutation(size_t k, G& gen) {
56*9e3b08aeSAndroid Build Coastguard Worker std::vector<size_t> result(k);
57*9e3b08aeSAndroid Build Coastguard Worker for (size_t i = 0; i < k; ++i) {
58*9e3b08aeSAndroid Build Coastguard Worker result[i] = i;
59*9e3b08aeSAndroid Build Coastguard Worker }
60*9e3b08aeSAndroid Build Coastguard Worker for (size_t i = 0; i < k; ++i) {
61*9e3b08aeSAndroid Build Coastguard Worker // pick one of [i, k)
62*9e3b08aeSAndroid Build Coastguard Worker std::uniform_int_distribution<size_t> toss(i, k - 1);
63*9e3b08aeSAndroid Build Coastguard Worker const auto pick = toss(gen);
64*9e3b08aeSAndroid Build Coastguard Worker using std::swap;
65*9e3b08aeSAndroid Build Coastguard Worker swap(result[i], result[pick]);
66*9e3b08aeSAndroid Build Coastguard Worker }
67*9e3b08aeSAndroid Build Coastguard Worker return result;
68*9e3b08aeSAndroid Build Coastguard Worker }
69*9e3b08aeSAndroid Build Coastguard Worker
70*9e3b08aeSAndroid Build Coastguard Worker TEST_CASE("randomly-generated permutations") {
71*9e3b08aeSAndroid Build Coastguard Worker std::ranlux48 gen;
72*9e3b08aeSAndroid Build Coastguard Worker auto seed = gen();
73*9e3b08aeSAndroid Build Coastguard Worker // NOTES:
74*9e3b08aeSAndroid Build Coastguard Worker // Permutations of size 6 are plenty big enough to shake out bugs.
75*9e3b08aeSAndroid Build Coastguard Worker /// There are k! permutations of size k. Testing costs are O(k).
76*9e3b08aeSAndroid Build Coastguard Worker for (size_t k = 0; k < 7; ++k) {
77*9e3b08aeSAndroid Build Coastguard Worker const auto count = Factorial(k);
78*9e3b08aeSAndroid Build Coastguard Worker INFO("testing with " << count << " permutations of size " << k);
79*9e3b08aeSAndroid Build Coastguard Worker std::vector<size_t> identity(k);
80*9e3b08aeSAndroid Build Coastguard Worker for (size_t i = 0; i < k; ++i) {
81*9e3b08aeSAndroid Build Coastguard Worker identity[i] = i;
82*9e3b08aeSAndroid Build Coastguard Worker }
83*9e3b08aeSAndroid Build Coastguard Worker for (size_t n = 0; n < count; ++n, ++seed) {
84*9e3b08aeSAndroid Build Coastguard Worker gen.seed(seed);
85*9e3b08aeSAndroid Build Coastguard Worker auto permutation = MakePermutation(k, gen);
86*9e3b08aeSAndroid Build Coastguard Worker std::ostringstream os;
87*9e3b08aeSAndroid Build Coastguard Worker os << "permutation of " << k << " numbers generated using seed " << seed;
88*9e3b08aeSAndroid Build Coastguard Worker GIVEN(os.str()) {
89*9e3b08aeSAndroid Build Coastguard Worker // NOTE: We could test with something other than [0, k) as the data, but
90*9e3b08aeSAndroid Build Coastguard Worker // let's just say "parametric polymorphism" and move on.
91*9e3b08aeSAndroid Build Coastguard Worker auto permutation_copy = permutation;
92*9e3b08aeSAndroid Build Coastguard Worker auto identity_copy = identity;
93*9e3b08aeSAndroid Build Coastguard Worker stg::Permute(identity_copy, permutation_copy);
94*9e3b08aeSAndroid Build Coastguard Worker for (size_t i = 0; i < k; ++i) {
95*9e3b08aeSAndroid Build Coastguard Worker // permutation_copy should be the identity
96*9e3b08aeSAndroid Build Coastguard Worker CHECK(permutation_copy[i] == i);
97*9e3b08aeSAndroid Build Coastguard Worker // identity_copy should now be the same as permutation
98*9e3b08aeSAndroid Build Coastguard Worker CHECK(identity_copy[i] == permutation[i]);
99*9e3b08aeSAndroid Build Coastguard Worker }
100*9e3b08aeSAndroid Build Coastguard Worker }
101*9e3b08aeSAndroid Build Coastguard Worker }
102*9e3b08aeSAndroid Build Coastguard Worker }
103*9e3b08aeSAndroid Build Coastguard Worker }
104*9e3b08aeSAndroid Build Coastguard Worker
105*9e3b08aeSAndroid Build Coastguard Worker TEST_CASE("randomly-generating ordering sequences, fully-matching") {
106*9e3b08aeSAndroid Build Coastguard Worker std::ranlux48 gen;
107*9e3b08aeSAndroid Build Coastguard Worker auto seed = gen();
108*9e3b08aeSAndroid Build Coastguard Worker // NOTES:
109*9e3b08aeSAndroid Build Coastguard Worker // Permutations of size 6 are plenty big enough to shake out bugs.
110*9e3b08aeSAndroid Build Coastguard Worker /// There are k! permutations of size k. Testing costs are O(k^2).
111*9e3b08aeSAndroid Build Coastguard Worker for (size_t k = 0; k < 7; ++k) {
112*9e3b08aeSAndroid Build Coastguard Worker const auto count = Factorial(k);
113*9e3b08aeSAndroid Build Coastguard Worker INFO("testing with " << count << " random orderings of size " << k);
114*9e3b08aeSAndroid Build Coastguard Worker for (size_t n = 0; n < count; ++n, ++seed) {
115*9e3b08aeSAndroid Build Coastguard Worker gen.seed(seed);
116*9e3b08aeSAndroid Build Coastguard Worker const auto order1 = MakePermutation(k, gen);
117*9e3b08aeSAndroid Build Coastguard Worker const auto order2 = MakePermutation(k, gen);
118*9e3b08aeSAndroid Build Coastguard Worker std::ostringstream os;
119*9e3b08aeSAndroid Build Coastguard Worker os << "orderings of " << k << " numbers generated using seed " << seed;
120*9e3b08aeSAndroid Build Coastguard Worker GIVEN(os.str()) {
121*9e3b08aeSAndroid Build Coastguard Worker const auto combined = stg::CombineOrders(order1, order2, k);
122*9e3b08aeSAndroid Build Coastguard Worker // combined should be identical to order2
123*9e3b08aeSAndroid Build Coastguard Worker CHECK(combined == order2);
124*9e3b08aeSAndroid Build Coastguard Worker }
125*9e3b08aeSAndroid Build Coastguard Worker }
126*9e3b08aeSAndroid Build Coastguard Worker }
127*9e3b08aeSAndroid Build Coastguard Worker }
128*9e3b08aeSAndroid Build Coastguard Worker
129*9e3b08aeSAndroid Build Coastguard Worker TEST_CASE("randomly-generating ordering sequences, disjoint") {
130*9e3b08aeSAndroid Build Coastguard Worker std::ranlux48 gen;
131*9e3b08aeSAndroid Build Coastguard Worker auto seed = gen();
132*9e3b08aeSAndroid Build Coastguard Worker // NOTES:
133*9e3b08aeSAndroid Build Coastguard Worker // Orderings of size 4 are plenty big enough to shake out bugs.
134*9e3b08aeSAndroid Build Coastguard Worker /// There are k! permutations of size k. Testing costs are O(k^2).
135*9e3b08aeSAndroid Build Coastguard Worker for (size_t k = 0; k < 5; ++k) {
136*9e3b08aeSAndroid Build Coastguard Worker const auto count = Factorial(k);
137*9e3b08aeSAndroid Build Coastguard Worker INFO("testing with " << count << " random orderings of size " << k);
138*9e3b08aeSAndroid Build Coastguard Worker for (size_t n = 0; n < count; ++n, ++seed) {
139*9e3b08aeSAndroid Build Coastguard Worker gen.seed(seed);
140*9e3b08aeSAndroid Build Coastguard Worker const auto order1 = MakePermutation(k, gen);
141*9e3b08aeSAndroid Build Coastguard Worker auto order2 = MakePermutation(k, gen);
142*9e3b08aeSAndroid Build Coastguard Worker for (size_t i = 0; i < k; ++i) {
143*9e3b08aeSAndroid Build Coastguard Worker order2[i] += k;
144*9e3b08aeSAndroid Build Coastguard Worker }
145*9e3b08aeSAndroid Build Coastguard Worker std::ostringstream os;
146*9e3b08aeSAndroid Build Coastguard Worker os << "orderings of " << k << " numbers generated using seed " << seed;
147*9e3b08aeSAndroid Build Coastguard Worker GIVEN(os.str()) {
148*9e3b08aeSAndroid Build Coastguard Worker const auto combined = stg::CombineOrders(order1, order2, 2 * k);
149*9e3b08aeSAndroid Build Coastguard Worker for (size_t i = 0; i < k; ++i) {
150*9e3b08aeSAndroid Build Coastguard Worker // order1 should appear as the first part
151*9e3b08aeSAndroid Build Coastguard Worker CHECK(combined[i] == order1[i]);
152*9e3b08aeSAndroid Build Coastguard Worker // order2 should appear as the second part
153*9e3b08aeSAndroid Build Coastguard Worker CHECK(combined[i + k] == order2[i]);
154*9e3b08aeSAndroid Build Coastguard Worker }
155*9e3b08aeSAndroid Build Coastguard Worker }
156*9e3b08aeSAndroid Build Coastguard Worker }
157*9e3b08aeSAndroid Build Coastguard Worker }
158*9e3b08aeSAndroid Build Coastguard Worker }
159*9e3b08aeSAndroid Build Coastguard Worker
160*9e3b08aeSAndroid Build Coastguard Worker TEST_CASE("randomly-generating ordering sequences, single overlap") {
161*9e3b08aeSAndroid Build Coastguard Worker std::ranlux48 gen;
162*9e3b08aeSAndroid Build Coastguard Worker auto seed = gen();
163*9e3b08aeSAndroid Build Coastguard Worker // NOTES:
164*9e3b08aeSAndroid Build Coastguard Worker // Orderings of size 4 are plenty big enough to shake out bugs.
165*9e3b08aeSAndroid Build Coastguard Worker /// There are k! permutations of size k. Testing costs are O(k^2).
166*9e3b08aeSAndroid Build Coastguard Worker for (size_t k = 1; k < 5; ++k) {
167*9e3b08aeSAndroid Build Coastguard Worker const auto count = Factorial(k);
168*9e3b08aeSAndroid Build Coastguard Worker INFO("testing with " << count << " random orderings of size " << k);
169*9e3b08aeSAndroid Build Coastguard Worker for (size_t n = 0; n < count; ++n, ++seed) {
170*9e3b08aeSAndroid Build Coastguard Worker gen.seed(seed);
171*9e3b08aeSAndroid Build Coastguard Worker const auto order1 = MakePermutation(k, gen);
172*9e3b08aeSAndroid Build Coastguard Worker auto order2 = MakePermutation(k, gen);
173*9e3b08aeSAndroid Build Coastguard Worker for (size_t i = 0; i < k; ++i) {
174*9e3b08aeSAndroid Build Coastguard Worker order2[i] += k - 1;
175*9e3b08aeSAndroid Build Coastguard Worker }
176*9e3b08aeSAndroid Build Coastguard Worker const auto pivot = k - 1;
177*9e3b08aeSAndroid Build Coastguard Worker std::ostringstream os;
178*9e3b08aeSAndroid Build Coastguard Worker os << "orderings of " << k << " numbers generated using seed " << seed;
179*9e3b08aeSAndroid Build Coastguard Worker GIVEN(os.str()) {
180*9e3b08aeSAndroid Build Coastguard Worker const auto combined = stg::CombineOrders(order1, order2, 2 * k - 1);
181*9e3b08aeSAndroid Build Coastguard Worker CHECK(combined.size() == 2 * k - 1);
182*9e3b08aeSAndroid Build Coastguard Worker // order1 pre, order2 pre, pivot, order1 post, order2 post
183*9e3b08aeSAndroid Build Coastguard Worker size_t ix = 0;
184*9e3b08aeSAndroid Build Coastguard Worker size_t ix1 = 0;
185*9e3b08aeSAndroid Build Coastguard Worker size_t ix2 = 0;
186*9e3b08aeSAndroid Build Coastguard Worker while (order1[ix1] != pivot) {
187*9e3b08aeSAndroid Build Coastguard Worker CHECK(combined[ix++] == order1[ix1++]);
188*9e3b08aeSAndroid Build Coastguard Worker }
189*9e3b08aeSAndroid Build Coastguard Worker while (order2[ix2] != pivot) {
190*9e3b08aeSAndroid Build Coastguard Worker CHECK(combined[ix++] == order2[ix2++]);
191*9e3b08aeSAndroid Build Coastguard Worker }
192*9e3b08aeSAndroid Build Coastguard Worker ++ix1;
193*9e3b08aeSAndroid Build Coastguard Worker ++ix2;
194*9e3b08aeSAndroid Build Coastguard Worker CHECK(combined[ix++] == pivot);
195*9e3b08aeSAndroid Build Coastguard Worker while (ix1 < k) {
196*9e3b08aeSAndroid Build Coastguard Worker CHECK(combined[ix++] == order1[ix1++]);
197*9e3b08aeSAndroid Build Coastguard Worker }
198*9e3b08aeSAndroid Build Coastguard Worker while (ix2 < k) {
199*9e3b08aeSAndroid Build Coastguard Worker CHECK(combined[ix++] == order2[ix2++]);
200*9e3b08aeSAndroid Build Coastguard Worker }
201*9e3b08aeSAndroid Build Coastguard Worker }
202*9e3b08aeSAndroid Build Coastguard Worker }
203*9e3b08aeSAndroid Build Coastguard Worker }
204*9e3b08aeSAndroid Build Coastguard Worker }
205*9e3b08aeSAndroid Build Coastguard Worker
206*9e3b08aeSAndroid Build Coastguard Worker TEST_CASE("hand-curated ordering sequences") {
207*9e3b08aeSAndroid Build Coastguard Worker using Sequence = std::vector<std::string>;
208*9e3b08aeSAndroid Build Coastguard Worker // NOTES:
209*9e3b08aeSAndroid Build Coastguard Worker // The output sequence MUST include the second sequence as a subsequence.
210*9e3b08aeSAndroid Build Coastguard Worker // The first sequence's ordering is respected as far as possible.
211*9e3b08aeSAndroid Build Coastguard Worker const std::vector<std::tuple<Sequence, Sequence, Sequence>> cases = {
212*9e3b08aeSAndroid Build Coastguard Worker {{"rose", "george", "emily"}, {"george", "ted", "emily"},
213*9e3b08aeSAndroid Build Coastguard Worker {"rose", "george", "ted", "emily"}},
214*9e3b08aeSAndroid Build Coastguard Worker {{}, {}, {}},
215*9e3b08aeSAndroid Build Coastguard Worker {{"a"}, {}, {"a"}},
216*9e3b08aeSAndroid Build Coastguard Worker {{}, {"a"}, {"a"}},
217*9e3b08aeSAndroid Build Coastguard Worker {{"a", "z"}, {}, {"a", "z"}},
218*9e3b08aeSAndroid Build Coastguard Worker {{}, {"a", "z"}, {"a", "z"}},
219*9e3b08aeSAndroid Build Coastguard Worker {{"a", "b", "c"}, {"c", "d"}, {"a", "b", "c", "d"}},
220*9e3b08aeSAndroid Build Coastguard Worker {{"a", "b", "d"}, {"b", "c", "d"}, {"a", "b", "c", "d"}},
221*9e3b08aeSAndroid Build Coastguard Worker {{"a", "c", "d"}, {"a", "b", "c"}, {"a", "b", "c", "d"}},
222*9e3b08aeSAndroid Build Coastguard Worker {{"b", "c", "d"}, {"a", "b"}, {"a", "b", "c", "d"}},
223*9e3b08aeSAndroid Build Coastguard Worker {{"z", "a", "q"}, {"a", "z"}, {"a", "z", "q"}},
224*9e3b08aeSAndroid Build Coastguard Worker };
225*9e3b08aeSAndroid Build Coastguard Worker for (const auto& [order1, order2, expected] : cases) {
226*9e3b08aeSAndroid Build Coastguard Worker const auto combined = stg::CombineOrders(order1, order2, expected.size());
227*9e3b08aeSAndroid Build Coastguard Worker CHECK(combined == expected);
228*9e3b08aeSAndroid Build Coastguard Worker }
229*9e3b08aeSAndroid Build Coastguard Worker }
230*9e3b08aeSAndroid Build Coastguard Worker
231*9e3b08aeSAndroid Build Coastguard Worker TEST_CASE("hand-curated reorderings with input order randomisation") {
232*9e3b08aeSAndroid Build Coastguard Worker using Constraint = std::pair<std::optional<size_t>, std::optional<size_t>>;
233*9e3b08aeSAndroid Build Coastguard Worker using Constraints = std::vector<Constraint>;
234*9e3b08aeSAndroid Build Coastguard Worker // NOTES:
235*9e3b08aeSAndroid Build Coastguard Worker // item removed at position x: {x}, {}
236*9e3b08aeSAndroid Build Coastguard Worker // item added at position y: {}, {y}
237*9e3b08aeSAndroid Build Coastguard Worker // item modified at positions x and y: {x}, {y}
238*9e3b08aeSAndroid Build Coastguard Worker // input item order should be irrelevant to output order
239*9e3b08aeSAndroid Build Coastguard Worker const std::vector<std::pair<Constraints, Constraints>> cases = {
240*9e3b08aeSAndroid Build Coastguard Worker {
241*9e3b08aeSAndroid Build Coastguard Worker {
242*9e3b08aeSAndroid Build Coastguard Worker {{2}, {2}}, // emily
243*9e3b08aeSAndroid Build Coastguard Worker {{1}, {0}}, // george
244*9e3b08aeSAndroid Build Coastguard Worker {{0}, {}}, // rose
245*9e3b08aeSAndroid Build Coastguard Worker {{}, {1}}, // ted
246*9e3b08aeSAndroid Build Coastguard Worker },
247*9e3b08aeSAndroid Build Coastguard Worker {
248*9e3b08aeSAndroid Build Coastguard Worker {{0}, {}}, // rose
249*9e3b08aeSAndroid Build Coastguard Worker {{1}, {0}}, // george
250*9e3b08aeSAndroid Build Coastguard Worker {{}, {1}}, // ted
251*9e3b08aeSAndroid Build Coastguard Worker {{2}, {2}}, // emily
252*9e3b08aeSAndroid Build Coastguard Worker },
253*9e3b08aeSAndroid Build Coastguard Worker },
254*9e3b08aeSAndroid Build Coastguard Worker {{}, {}},
255*9e3b08aeSAndroid Build Coastguard Worker {{{{0}, {0}}}, {{{0}, {0}}}},
256*9e3b08aeSAndroid Build Coastguard Worker {{{{0}, {}}}, {{{0}, {}}}},
257*9e3b08aeSAndroid Build Coastguard Worker {{{{}, {0}}}, {{{}, {0}}}},
258*9e3b08aeSAndroid Build Coastguard Worker {{{{}, {2}}, {{}, {1}}, {{}, {0}}},
259*9e3b08aeSAndroid Build Coastguard Worker {{{}, {0}}, {{}, {1}}, {{}, {2}}}},
260*9e3b08aeSAndroid Build Coastguard Worker {{{{2}, {}}, {{1}, {}}, {{0}, {}}},
261*9e3b08aeSAndroid Build Coastguard Worker {{{0}, {}}, {{1}, {}}, {{2}, {}}}},
262*9e3b08aeSAndroid Build Coastguard Worker // int b; int c; -> int b; int a; int c
263*9e3b08aeSAndroid Build Coastguard Worker {{{{}, {1}}, {{0}, {0}}, {{1}, {2}}},
264*9e3b08aeSAndroid Build Coastguard Worker {{{0}, {0}}, {{}, {1}}, {{1}, {2}}}},
265*9e3b08aeSAndroid Build Coastguard Worker };
266*9e3b08aeSAndroid Build Coastguard Worker std::ranlux48 gen;
267*9e3b08aeSAndroid Build Coastguard Worker auto seed = gen();
268*9e3b08aeSAndroid Build Coastguard Worker for (const auto& [given, expected] : cases) {
269*9e3b08aeSAndroid Build Coastguard Worker const auto k = given.size();
270*9e3b08aeSAndroid Build Coastguard Worker const auto count = Factorial(k);
271*9e3b08aeSAndroid Build Coastguard Worker INFO("testing with " << count << " random input orderings");
272*9e3b08aeSAndroid Build Coastguard Worker for (size_t n = 0; n < count; ++n, ++seed) {
273*9e3b08aeSAndroid Build Coastguard Worker gen.seed(seed);
274*9e3b08aeSAndroid Build Coastguard Worker std::ostringstream os;
275*9e3b08aeSAndroid Build Coastguard Worker os << "permutation of " << k << " items generated using seed " << seed;
276*9e3b08aeSAndroid Build Coastguard Worker GIVEN(os.str()) {
277*9e3b08aeSAndroid Build Coastguard Worker auto permutation = MakePermutation(k, gen);
278*9e3b08aeSAndroid Build Coastguard Worker auto copy = given;
279*9e3b08aeSAndroid Build Coastguard Worker stg::Permute(copy, permutation);
280*9e3b08aeSAndroid Build Coastguard Worker stg::Reorder(copy);
281*9e3b08aeSAndroid Build Coastguard Worker CHECK(copy == expected);
282*9e3b08aeSAndroid Build Coastguard Worker }
283*9e3b08aeSAndroid Build Coastguard Worker }
284*9e3b08aeSAndroid Build Coastguard Worker }
285*9e3b08aeSAndroid Build Coastguard Worker }
286*9e3b08aeSAndroid Build Coastguard Worker
287*9e3b08aeSAndroid Build Coastguard Worker } // namespace Test
288