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}