You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: speelpenning.rs
    path of file: ./repos/RustQuant/examples
    
    the code of the file until where you have to start completion: // This is "Speelpenning's Example" used in the AD literature to
// demonstrate the efficiency of Algorithmic Adjoint Differentiation.
// Speelpenning helped develop AD in the 1980s, hence the name of the
// function f(x) = x_1 * x_2 * ... * x_n.

// /usr/bin/time cargo run --release --example speelpenning 100

use finitediff::*;
use std::time::Instant;
use RustQuant::autodiff::*;

fn main() {
    let n = std::env::args()
        .nth(1)
        .unwrap_or_else(|| "170".to_string())
        .parse::<usize>()
        .unwrap();

    // 170 is the largest number of variables that can be used since
    // we'll overflow otherwise (we end up with elements > f64::MAX).
    for i in 1..=n {
        // std::env::set_var("RUST_BACKTRACE", "full");

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // Finite Difference Method
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        let prod = |x: &Vec<f64>| -> f64 { x.iter().copied().product() };
        let params: Vec<f64> = (1..=i).map(|x| x as f64).collect();

        let start_finite_diff = Instant::now();
        params.central_diff(&prod);
        let duration_fdm = start_finite_diff.elapsed();

        // println!("FDM: {:?}", grad_fdm);

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // Algorithmic Adjoint
    
fn main() {
    let n = std::env::args()
        .nth(1)
        .unwrap_or_else(|| "170".to_string())
        .parse::<usize>()
        .unwrap();

    // 170 is the largest number of variables that can be used since
    // we'll overflow otherwise (we end up with elements > f64::MAX).
    for i in 1..=n {
        // std::env::set_var("RUST_BACKTRACE", "full");

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // Finite Difference Method
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        let prod = |x: &Vec<f64>| -> f64 { x.iter().copied().product() };
        let params: Vec<f64> = (1..=i).map(|x| x as f64).collect();

        let start_finite_diff = Instant::now();
        params.central_diff(&prod);
        let duration_fdm = start_finite_diff.elapsed();

        // println!("FDM: {:?}", grad_fdm);

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // Algorithmic Adjoint Differentiation
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        let t = Graph::new();
        let params = (1..=i).map(|x| t.var(x as f64)).collect::<Vec<_>>();
        let prod = params.iter().copied().product::<Variable>();

        let start_aad = Instant::now();
        prod.accumulate();
        let duration_aad = start_aad.elapsed();

        // println!("AAD: {:?}", grad_aad.wrt(&params));

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // RESULTS
        //
        // AAD quickly becomes much faster than FDM.
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        println!(
            // "TIMINGS {{ FDM = {} \u{03BC}s, AAD = {} \u{03BC}s }}",
            // "TIMINGS {{ FDM = {} ns, AAD = {} ns }}",
            "{},{}",
            duration_fdm.as_nanos(),
            duration_aad.as_nanos()
        )
    }
}