Search code examples
rustclosurespolynomials

Is there a way to create a closure that computes an nth degree polynomial with random coefficients in Rust?


So the idea is to have a function that returns a closure of degree n with random coefficients. This might be useful for comparing root finding methods, as we can automate the creation of a function to evaluate, for example. Appending any operations to a closure's return would be an even more powerful resource, so let me know if there is some way to do that.

The code should look as following:

use rand::Rng;
fn create_func(n: u8) -> impl Fn(f64) -> f64 { 
    let mut cst = vec![];
    for _ in 0..n{
        cst.push(rand::thread_rng().gen_range(0..=20)  as f64);
        // establish the coefficients by randomly generating them
    }
    move |x| cst[0]*x + cst[1]*x.powf(1.) + /*...*/ cst[n- 1]*x.powf(n as f64)
}

So obviously the last part isn't really a valid way of expressing the rest of the closure we want to return, but I hope you get the idea.


Solution

  • You're looking for a sum, so turn your sequence into an iterator that will be summed.

    move |x| {
        cst.iter()
            .zip(0..=n as i32)
            .map(|(&c, exp)| c * x.powi(exp))
            .sum()
    }
    

    For each item, you need the element from cst (iter) and its exponent (zip). You can construct terms one at a time from those (map), and then sum all terms together (sum).

    I've also fixed your number of terms (yours doesn't have the x^0 term) and used sample_iter, which is faster than calling thread_rng every time. And I've switched to powi since all the exponents are integers.

    pub fn create_func(n: u8) -> impl Fn(f64) -> f64 {
        let cst: Vec<f64> = rand::thread_rng()
            .sample_iter(rand::distributions::Uniform::new_inclusive(0, 20))
            .map(|n| n as f64)
            .take(n as usize + 1)
            .collect();
    
        move |x| {
            cst.iter()
                .zip(0..=n as i32)
                .map(|(&c, exp)| c * x.powi(exp))
                .sum()
        }
    }