1
2 //
3 // This source file is part of appleseed.
4 // Visit https://appleseedhq.net/ for additional information and resources.
5 //
6 // This software is released under the MIT license.
7 //
8 // Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
9 // Copyright (c) 2014-2018 Francois Beaune, The appleseedhq Organization
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 // THE SOFTWARE.
28 //
29
30 #pragma once
31
32 // appleseed.foundation headers.
33 #include "foundation/math/rng/distribution.h"
34 #include "foundation/platform/compiler.h"
35 #include "foundation/platform/types.h"
36
37 // appleseed.main headers.
38 #include "main/dllsymbol.h"
39
40 // Standard headers.
41 #include <cassert>
42 #include <cstddef>
43
44 namespace foundation
45 {
46
47 //
48 // General purpose permutation generators.
49 //
50
51 // Generate the identity permutation.
52 void identity_permutation(
53 const size_t size, // size of the permutation
54 size_t perm[]); // [out] permutation
55
56 // Generate a random permutation using Knuth algorithm.
57 template <typename RNG>
58 void random_permutation(
59 const size_t size, // size of the permutation
60 size_t perm[], // [out] permutation
61 RNG& rng); // random number generator
62
63
64 //
65 // Permutation generators suitable for digits scrambling in QMC.
66 //
67 // These permutations P satisfy P(0) = 0, i.e. the value 0 stays at position 0.
68 //
69
70 // Generate a reverse permutation.
71 void reverse_qmc_permutation(
72 const size_t size, // size of the permutation
73 size_t perm[]); // [out] permutation
74
75 // Generate a Faure permutation.
76 void faure_qmc_permutation(
77 const size_t size, // size of the permutation
78 size_t perm[]); // [out] permutation
79
80
81 //
82 // Precomputed Faure permutations.
83 //
84
85 const size_t FaurePermutationTableSize = 100;
86 APPLESEED_DLLSYMBOL extern const size_t* FaurePermutations[FaurePermutationTableSize];
87
88 struct PrimePermutationPair
89 {
90 size_t m_prime;
91 const size_t* m_perm;
92 };
93
94 APPLESEED_DLLSYMBOL extern const PrimePermutationPair APPLESEED_ALIGN(16) PrimesFaurePermutations[FaurePermutationTableSize];
95
96
97 //
98 // Permutation operations.
99 //
100
101 // Test whether a given vector is a valid permutation.
102 bool is_permutation(
103 const size_t size, // size of the vector
104 const size_t v[]); // vector
105
106
107 //
108 // Reordering functions.
109 //
110
111 // Shuffle items in a vector according to a given permutation.
112 // Use small_item_reorder() if items are 32 bytes wide or less.
113 // To reorder larger items, use large_item_reorder().
114 template <typename Item, typename Index>
115 void small_item_reorder(
116 Item items[],
117 Item temp[],
118 const Index order[],
119 const Index count);
120 template <typename Item, typename Index>
121 void large_item_reorder(
122 Item items[],
123 Index tags[],
124 const Index order[],
125 const Index count);
126 template <typename Item, typename Index>
127 void large_item_reorder(
128 Item items[],
129 Index order[],
130 const Index count);
131
132
133 //
134 // Permutation generators implementation.
135 //
136
identity_permutation(const size_t size,size_t perm[])137 inline void identity_permutation(
138 const size_t size,
139 size_t perm[])
140 {
141 for (size_t i = 0; i < size; ++i)
142 perm[i] = i;
143 }
144
145 template <typename RNG>
random_permutation(const size_t size,size_t perm[],RNG & rng)146 inline void random_permutation(
147 const size_t size,
148 size_t perm[],
149 RNG& rng)
150 {
151 assert(size > 0);
152
153 // Start with identity permutation.
154 for (size_t i = 0; i < size; ++i)
155 perm[i] = i;
156
157 // Shuffle.
158 for (size_t i = 0; i < size - 1; ++i)
159 {
160 const size_t j = rand_int1(
161 rng,
162 static_cast<int32>(i),
163 static_cast<int32>(size - 1));
164
165 const size_t tmp = perm[i];
166 perm[i] = perm[j];
167 perm[j] = tmp;
168 }
169 }
170
reverse_qmc_permutation(const size_t size,size_t perm[])171 inline void reverse_qmc_permutation(
172 const size_t size,
173 size_t perm[])
174 {
175 assert(size > 0);
176
177 perm[0] = 0;
178
179 for (size_t i = 1, n = size; i < size; ++i)
180 perm[i] = --n;
181 }
182
183
184 //
185 // Permutation operations implementation.
186 //
187
is_permutation(const size_t size,const size_t v[])188 inline bool is_permutation(
189 const size_t size,
190 const size_t v[])
191 {
192 for (size_t value = 0; value < size; ++value)
193 {
194 bool found_value = false;
195
196 for (size_t rank = 0; rank < size; ++rank)
197 {
198 if (v[rank] == value)
199 {
200 found_value = true;
201 break;
202 }
203 }
204
205 if (!found_value)
206 return false;
207 }
208
209 return true;
210 }
211
212
213 //
214 // Reordering functions implementation.
215 //
216
217 template <typename Item, typename Index>
small_item_reorder(Item items[],Item temp[],const Index order[],const Index count)218 inline void small_item_reorder(
219 Item items[],
220 Item temp[],
221 const Index order[],
222 const Index count)
223 {
224 assert(items);
225 assert(temp);
226 assert(order);
227
228 for (Index i = 0; i < count; ++i)
229 temp[i] = items[order[i]];
230
231 for (Index i = 0; i < count; ++i)
232 items[i] = temp[i];
233 }
234
235 template <typename Item, typename Index>
large_item_reorder(Item items[],Index tags[],const Index order[],const Index count)236 inline void large_item_reorder(
237 Item items[],
238 Index tags[],
239 const Index order[],
240 const Index count)
241 {
242 assert(items);
243 assert(tags);
244 assert(order);
245
246 for (Index i = 0; i < count; ++i)
247 tags[i] = 0;
248
249 for (Index i = 0; i < count; ++i)
250 {
251 if (tags[i])
252 continue;
253
254 const Item temp = items[i];
255 Index next = order[i];
256 Index j = i;
257
258 while (next != i)
259 {
260 items[j] = items[next];
261 j = next;
262 next = order[j];
263 tags[j] = 1;
264 }
265
266 items[j] = temp;
267 }
268 }
269
270 template <typename Item, typename Index>
large_item_reorder(Item items[],Index order[],const Index count)271 inline void large_item_reorder(
272 Item items[],
273 Index order[],
274 const Index count)
275 {
276 assert(items);
277 assert(order);
278
279 for (Index i = 0; i < count; ++i)
280 {
281 if (order[i] == ~Index(0))
282 continue;
283
284 const Item temp = items[i];
285 Index next = order[i];
286 Index j = i;
287
288 while (next != i)
289 {
290 items[j] = items[next];
291 j = next;
292 next = order[j];
293 order[j] = ~Index(0);
294 }
295
296 items[j] = temp;
297 }
298 }
299
300 } // namespace foundation
301