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