lds_rs/ilds.rs
1// #![feature(unboxed_closures)]
2//! Low-Discrepancy Sequence (LDS) Generator (specific for integer output)
3//!
4//! This code implements two low-discrepancy sequence generators: the Van der Corput sequence and the Halton sequence (specific for integer output). These sequences are used to generate evenly distributed points in a space, which can be useful for various applications like sampling, optimization, or numerical integration.
5//!
6//! The code defines three main components: a function called vdc_i, and two classes named VdCorput and Halton.
7//!
8//! The vdc_i function is the core of the Van der Corput sequence generation. It takes an integer k, a base (default 2), and a scale (default 10) as inputs. It converts the number k from the given base to a decimal number, using the specified scale for integer output. This function is used to generate individual elements of the Van der Corput sequence.
9//!
10//! The VdCorput class is a wrapper around the vdc_i function. It keeps track of the current count and allows you to generate successive elements of the Van der Corput sequence by calling its pop method. You can also reset the sequence to a specific starting point using the reseed method.
11//!
12//! The Halton class generates points in a 2-dimensional space using two Van der Corput sequences with different bases. It creates two VdCorput objects internally and uses them to generate pairs of numbers. The pop method of the Halton class returns a list of two integers, representing a point in 2D space.
13//!
14//! The main logic flow in this code is the generation of these low-discrepancy sequences. For the Van der Corput sequence, it works by repeatedly dividing the input number by the base and using the remainders to construct the output number. This process creates a sequence of numbers that are well-distributed between 0 and N (when properly scaled).
15//!
16//! The Halton sequence extends this idea to multiple dimensions by using different bases for each dimension. In this implementation, it generates 2D points by combining two Van der Corput sequences.
17//!
18//! The code doesn't take any direct input from the user. Instead, it provides classes and functions that can be used in other programs to generate these sequences. The output of these generators are individual numbers (for Van der Corput) or pairs of numbers (for Halton) that form the respective sequences.
19//!
20//! This code is particularly useful for applications that need well-distributed random-like numbers, but with more uniformity than typical pseudo-random number generators provide. It's a building block that can be used in more complex algorithms and simulations.
21
22/// The function `vdc_i` calculates the van der Corput sequence for a given base and scale.
23///
24/// Arguments:
25///
26/// * `k`: The parameter `k` represents the number that we want to convert to variable digit code (VDC)
27/// representation.
28/// * `base`: The `base` parameter represents the base of the number system being used. It determines
29/// the number of unique digits that can be used to represent numbers. For example, in base 10, the
30/// digits range from 0 to 9.
31/// * `scale`: The `scale` parameter in the `vdc_i` function represents the power to which the `base` is
32/// raised. It determines the number of digits in the resulting VDC (Van der Corput) number.
33///
34/// Returns:
35///
36/// The function `vdc_i` returns an unsigned integer value of type `usize`.
37///
38/// # Examples
39///
40/// ```rust
41/// use lds_rs::ilds::vdc_i;
42///
43/// assert_eq!(vdc_i(10, 2, 2), 1);
44/// assert_eq!(vdc_i(10, 2, 3), 2);
45/// ```
46pub const fn vdc_i(k: usize, base: usize, scale: u32) -> usize {
47 let mut res = 0;
48 let mut factor = base.pow(scale);
49 let mut k = k;
50 while k != 0 {
51 let remainder = k % base;
52 factor /= base;
53 k /= base;
54 res += remainder * factor;
55 }
56 res
57}
58
59/// The `VdCorput` struct is a generator for Van der Corput sequences.
60///
61/// Properties:
62///
63/// * `count`: The `count` property represents the number of elements that have been generated from the
64/// Van der Corput sequence so far.
65/// * `base`: The `base` property represents the base of the Van der Corput sequence. It determines the
66/// distribution of the generated numbers.
67/// * `scale`: The `scale` property determines the precision of the generated Van der Corput sequence.
68/// It represents the number of bits used to represent the fractional part of the sequence. A higher
69/// scale value will result in a more precise sequence, but will also require more memory and
70/// computation.
71///
72/// # Examples
73///
74/// ```rust
75/// use lds_rs::VdCorput;
76///
77/// let mut vgen = VdCorput::new(2);
78/// vgen.reseed(10);
79/// let result = vgen.pop();
80///
81/// assert_eq!(result, 0.8125);
82/// ```
83#[derive(Debug)]
84pub struct VdCorput {
85 count: usize,
86 base: usize,
87 scale: u32,
88}
89
90impl VdCorput {
91 /// Creates a new [`VdCorput`].
92 ///
93 /// The `new` function creates a new `VdCorput` struct with the specified base and scale values.
94 ///
95 /// Arguments:
96 ///
97 /// * `base`: The `base` parameter represents the base of the Van der Corput sequence. It determines the
98 /// number of unique values that can be generated by the sequence.
99 /// * `scale`: The `scale` parameter in the `new` function is of type `u32`, which stands for unsigned
100 /// 32-bit integer. It represents the scale factor used in the `VdCorput` struct.
101 ///
102 /// Returns:
103 ///
104 /// The `new` function returns an instance of the `VdCorput` struct.
105 pub const fn new(base: usize, scale: u32) -> Self {
106 VdCorput {
107 count: 0,
108 base,
109 scale,
110 }
111 }
112
113 /// Returns the pop of this [`VdCorput`].
114 ///
115 /// The `pop` method of the [`VdCorput`] struct returns the next element in the Van der Corput
116 /// sequence. It increments the `count` property of the struct and uses the `vdc_i` function to
117 /// calculate the corresponding Van der Corput value based on the current count, base, and scale. In
118 /// the example provided, a `VdCorput` instance is created with a base of 2 and a scale of 10. The
119 /// `pop` method is then called, which returns the Van der Corput value for the current count (which
120 /// is initially 0). In this case, the returned value is 512.
121 ///
122 /// # Examples
123 ///
124 /// ```rust
125 /// use lds_rs::ilds::VdCorput;
126 ///
127 /// let mut vd_corput = VdCorput::new(2, 10);
128 /// assert_eq!(vd_corput.pop(), 512);
129 /// ```
130 pub fn pop(&mut self) -> usize {
131 self.count += 1;
132 vdc_i(self.count, self.base, self.scale)
133 }
134
135 /// The below code is a Rust function called `reseed` that is used to reset the state of a sequence
136 /// generator to a specific seed value. This allows the sequence generator to start generating the
137 /// sequence from the beginning or from a specific point in the sequence, depending on the value of the
138 /// seed.
139 pub fn reseed(&mut self, seed: usize) {
140 self.count = seed;
141 }
142}
143
144// impl FnOnce<()> for VdCorput {
145// type Output = f64;
146// extern "rust-call" fn call_once(self, _arg: ()) -> Self::Output {
147// self.count += 1;
148// vdc(self.count, self.base)
149// }
150// }
151
152/// The [`Halton`] struct is a generator for the Halton sequence.
153///
154/// Properties:
155///
156/// * `vdc0`: An instance of the VdCorput struct used for generating the first dimension of the Halton sequence.
157/// * `vdc1`: The `vdc1` property is an instance of the [`VdCorput`] struct. It is used to generate the
158/// Van der Corput sequence for the second dimension of the Halton sequence.
159///
160/// # Examples
161///
162/// ```rust
163/// use lds_rs::ilds::Halton;
164///
165/// let mut hgen = Halton::new(&[2, 3], &[11, 7]);
166/// hgen.reseed(0);
167/// let result = hgen.pop();
168///
169/// assert_eq!(result[0], 1024);
170/// ```
171#[derive(Debug)]
172pub struct Halton {
173 vdc0: VdCorput,
174 vdc1: VdCorput,
175}
176
177impl Halton {
178 /// Creates a new [`Halton`].
179 ///
180 /// The `new` function creates a new `Halton` struct with specified base and scale values for two
181 /// VdCorput sequences.
182 ///
183 /// Arguments:
184 ///
185 /// * `base`: The `base` parameter is an array of `usize` values that represents the base for each
186 /// dimension of the Halton sequence. Each element in the `base` array corresponds to a dimension in
187 /// the sequence.
188 /// * `scale`: The `scale` parameter is an array of `u32` values that determine the scale or
189 /// precision of the Halton sequence for each dimension. Each element in the `scale` array
190 /// corresponds to a dimension in the Halton sequence. The larger the value of `scale`, the more
191 /// precise the Halton sequence.
192 ///
193 /// Returns:
194 ///
195 /// The `new` function is returning an instance of the `Halton` struct.
196 pub fn new(base: &[usize], scale: &[u32]) -> Self {
197 Halton {
198 vdc0: VdCorput::new(base[0], scale[0]),
199 vdc1: VdCorput::new(base[1], scale[1]),
200 }
201 }
202
203 /// The `pop` function returns an array containing the pop values of two [`Halton`] instances.
204 ///
205 /// Returns:
206 ///
207 /// An array of two `usize` values is being returned.
208 pub fn pop(&mut self) -> [usize; 2] {
209 [self.vdc0.pop(), self.vdc1.pop()]
210 }
211
212 /// The below code is a Rust function called `reseed` that is used to reset the state of a sequence
213 /// generator to a specific seed value. This allows the sequence generator to start generating the
214 /// sequence from the beginning or from a specific point in the sequence, depending on the value of the
215 /// seed.
216 #[allow(dead_code)]
217 pub fn reseed(&mut self, seed: usize) {
218 self.vdc0.reseed(seed);
219 self.vdc1.reseed(seed);
220 }
221}
222
223macro_rules! div_mod_3_iter {
224 ($input:expr) => {{
225 let q = $input >> 2; // Equivalent to extracting upper bits
226 let r = $input & 0x03; // Equivalent to extracting lower 2 bits
227 (q, q + r) // Return the sum of q and r
228 }};
229}
230
231pub fn div_mod_3_u8(n: u8) -> (u8, u8) {
232 // Perform the iterations using the macro
233 let (q1, rem1) = div_mod_3_iter!(n); // First iteration
234 let (q2, rem2) = div_mod_3_iter!(rem1); // Second iteration
235 let (q3, rem3) = div_mod_3_iter!(rem2); // Third iteration
236 let (q4, rem4) = div_mod_3_iter!(rem3); // Fourth iteration
237
238 // Calculate the final quotient sum
239 let quotient_sum = q1 + q2 + q3 + q4;
240
241 // Final check and output assignment
242 if rem4 == 0x03 {
243 // Equivalent to rem4 == 2'b11
244 (quotient_sum + 1, 0x00) // Equivalent to quotient_sum + 1 and remainder 2'b00
245 } else {
246 (quotient_sum, rem4) // Equivalent to quotient_sum and rem4[1:0]
247 }
248}
249
250pub fn div_mod_3_u16(n: u16) -> (u16, u16) {
251 // Perform the iterations using the macro
252 let (q1, rem1) = div_mod_3_iter!(n); // First iteration
253 let (q2, rem2) = div_mod_3_iter!(rem1); // Second iteration
254 let (q3, rem3) = div_mod_3_iter!(rem2); // Third iteration
255 let (q4, rem4) = div_mod_3_iter!(rem3); // Fourth iteration
256 let (q5, rem5) = div_mod_3_iter!(rem4); // 5th iteration
257 let (q6, rem6) = div_mod_3_iter!(rem5); // 6th iteration
258 let (q7, rem7) = div_mod_3_iter!(rem6); // 7th iteration
259 let (q8, rem8) = div_mod_3_iter!(rem7); // 8th iteration
260
261 // Calculate the final quotient sum
262 let quotient_sum = q1 + q2 + q3 + q4 + q5 + q6 + q7 + q8;
263
264 // Final check and output assignment
265 if rem8 == 0x03 {
266 // Equivalent to rem4 == 2'b11
267 (quotient_sum + 1, 0x00) // Equivalent to quotient_sum + 1 and remainder 2'b00
268 } else {
269 (quotient_sum, rem8) // Equivalent to quotient_sum and rem8[1:0]
270 }
271}
272
273macro_rules! div_mod_7_iter {
274 ($input:expr) => {{
275 let q = $input >> 3; // Equivalent to extracting upper bits
276 let r = $input & 0x07; // Equivalent to extracting lower 3 bits
277 (q, q + r) // Return the sum of q and r
278 }};
279}
280
281pub fn div_mod_7_u8(n: u8) -> (u8, u8) {
282 // Perform the iterations using the macro
283 let (q1, rem1) = div_mod_7_iter!(n); // First iteration
284 let (q2, rem2) = div_mod_7_iter!(rem1); // Second iteration
285 let (q3, rem3) = div_mod_7_iter!(rem2); // Third iteration
286
287 // Calculate the final quotient sum
288 let quotient_sum = q1 + q2 + q3;
289
290 // Final check and output assignment
291 if rem3 == 0x07 {
292 // Equivalent to rem3 == 3'b111
293 (quotient_sum + 1, 0x000) // Equivalent to quotient_sum + 1 and remainder 3'b000
294 } else {
295 (quotient_sum, rem3) // Equivalent to quotient_sum and rem3[1:0]
296 }
297}
298
299pub fn div_mod_7_u16(n: u16) -> (u16, u16) {
300 // Perform the iterations using the macro
301 let (q1, rem1) = div_mod_7_iter!(n); // First iteration
302 let (q2, rem2) = div_mod_7_iter!(rem1); // Second iteration
303 let (q3, rem3) = div_mod_7_iter!(rem2); // Third iteration
304 let (q4, rem4) = div_mod_7_iter!(rem3); // Fourth iteration
305 let (q5, rem5) = div_mod_7_iter!(rem4); // 5th iteration
306
307 // Calculate the final quotient sum
308 let quotient_sum = q1 + q2 + q3 + q4 + q5;
309
310 // Final check and output assignment
311 if rem5 == 0x07 {
312 // Equivalent to rem5 == 3'b111
313 (quotient_sum + 1, 0x000) // Equivalent to quotient_sum + 1 and remainder 3'b000
314 } else {
315 (quotient_sum, rem5) // Equivalent to quotient_sum and rem5[1:0]
316 }
317}
318
319#[cfg(test)]
320mod tests {
321 use super::*;
322
323 #[test]
324 fn test_vdc() {
325 let base = 2;
326 let scale = 10;
327 let k = 10;
328 let res = vdc_i(k, base, scale);
329 assert_eq!(res, 320);
330 assert_eq!(vdc_i(1, 2, 10), 512);
331 assert_eq!(vdc_i(2, 2, 10), 256);
332 assert_eq!(vdc_i(3, 2, 10), 768);
333 }
334
335 #[test]
336 fn test_vdcorput() {
337 let mut vgen = VdCorput::new(2, 10);
338 vgen.reseed(0);
339 assert_eq!(vgen.pop(), 512);
340 assert_eq!(vgen.pop(), 256);
341 assert_eq!(vgen.pop(), 768);
342
343 let mut vgen2 = VdCorput::new(3, 7);
344 vgen2.reseed(0);
345 assert_eq!(vgen2.pop(), 729);
346 assert_eq!(vgen2.pop(), 1458);
347 assert_eq!(vgen2.pop(), 243);
348 }
349
350 #[test]
351 fn test_halton() {
352 let mut hgen = Halton::new(&[2, 3], &[11, 7]);
353 hgen.reseed(0);
354 let result = hgen.pop();
355 assert_eq!(result, [1024, 729]);
356 let result = hgen.pop();
357 assert_eq!(result, [512, 1458]);
358 }
359
360 #[test]
361 fn test_div_mod_3_u8() {
362 let (q, r) = div_mod_3_u8(10);
363 assert_eq!(q, 3);
364 assert_eq!(r, 1);
365
366 let (q, r) = div_mod_3_u8(12);
367 assert_eq!(q, 4);
368 assert_eq!(r, 0);
369 }
370
371 #[test]
372 fn test_div_mod_3_u16() {
373 let (q, r) = div_mod_3_u16(10000);
374 assert_eq!(q, 3333);
375 assert_eq!(r, 1);
376
377 let (q, r) = div_mod_3_u16(10002);
378 assert_eq!(q, 3334);
379 assert_eq!(r, 0);
380 }
381
382 #[test]
383 fn test_div_mod_7_u8() {
384 let (q, r) = div_mod_7_u8(10);
385 assert_eq!(q, 1);
386 assert_eq!(r, 3);
387
388 let (q, r) = div_mod_7_u8(14);
389 assert_eq!(q, 2);
390 assert_eq!(r, 0);
391 }
392
393 #[test]
394 fn test_div_mod_7_u16() {
395 let (q, r) = div_mod_7_u16(10000);
396 assert_eq!(q, 1428);
397 assert_eq!(r, 4);
398
399 let (q, r) = div_mod_7_u16(14000);
400 assert_eq!(q, 2000);
401 assert_eq!(r, 0);
402 }
403}