Having trouble with dynamic arrays

The code snippet below is annotated to indicate the problem(s)

#![allow(non_snake_case)]

use num_complex::Complex64;

fn main() {
    let one= Complex64::new(1.0, 0.0); let zz= Complex64::new(0.0, 0.0);
    let mut data: [Complex64; 8] = [one,one,one,one, zz,zz,zz,zz,];
    fft  (&mut data);
   //.. subsequent code after fcn call omitted...

}

const PI: f64 = 3.14159265358979323846264338327950288_f64;

fn fft (x: &mut [Complex64] )
{
    let N : usize = x.len(); if N <= 1 { return; }

// The problem:
// How do I set up array even[]= all x[k] values for k an even index, and array odd[] = all x[k] values for k an odd index

    // this panics
    // let mut even = Vec::<Complex64>::with_capacity(N/2);  let mut odd  = Vec::<Complex64>::with_capacity(N/2);

    // this wont work
    // const n2 : usize= N/2; let even : [Complex64; n2];   let odd  : [Complex64; n2];

    // nor does this
    //let even : [Complex64; 20];   let odd  : [Complex64; 20];

    // another stab in the dark
    // let mut even= &[zz; N/2] ;  let mut odd = &[zz; N/2] ;

    // unsafe solution since my calls to this fcn commonly requires N > 4096
    let zz= Complex64::new(0.0, 0.0); let mut even= [zz; 20] ;  let mut odd = [zz; 20] ;

    // my bottom line
    for k in 0..N/2 { even[k]= x[2*k]; odd[k]= x[2*k+1]; }
    for k in 0..N/2
    {   let t= odd[k]* (Complex64::from_polar(1.0, -2.0*PI*(k as f64)/(N as f64)) ).exp();
        x[k]     = even[k] +t;
        x[k +N/2]= even[k] -t;
    }
}

This works:

fn fft (x: &mut [Complex64] )
{
    let N : usize = x.len(); if N <= 1 { return; }
    let mut even = Vec::with_capacity(N/2);
    let mut odd = Vec::with_capacity(N/2);

    for k in 0..N/2 { even.push(x[2*k]); odd.push(x[2*k+1]); }
    for k in 0..N/2
    {   let t= odd[k]* (Complex64::from_polar(1.0, -2.0*PI*(k as f64)/(N as f64)) ).exp();
        x[k]     = even[k] +t;
        x[k +N/2]= even[k] -t;
    }
}

Is using Vec:: the preferred way Rust folks implement dynamic arrays ??...I get the impression reading Rust docs that slices are preferred

Your vector solution panics because, in safe code, you're not allowed to access elements before they are initialized. Doing so would drop an uninitialized element as you overwrite it. You might want to default initialize the vectors instead:

    let mut even = vec![Complex64::default(); N/2];
    let mut odd  = vec![Complex64::default(); N/2];

    for k in 0..N/2 { even[k]= x[2*k]; odd[k]= x[2*k+1]; }
    for k in 0..N/2
    {   let t= odd[k]* (Complex64::from_polar(1.0, -2.0*PI*(k as f64)/(N as f64)) ).exp();
        x[k]     = even[k] +t;
        x[k +N/2]= even[k] -t;
    }

Alternatively, if the allocation turns out to be a bottle-neck, you could even let your caller provide a buffer and only initiailize the missing elements.

fn fft (
    x: &mut [Complex64],
    even_buf: &mut Vec<Complex64>,
    odd_buf: &mut Vec<Complex64>,
) {
    let N : usize = x.len(); if N <= 1 { return; }

    // This is practically for free if the `fft` method is called a second
    // time with the same buffer size and the same buffers.
    even_buf.resize_with(N/2, Complex64::default);
    odd_buf.resize_with(N/2, Complex64::default);
    let mut even = &mut even_buf[..N/2];
    let mut odd  = &mut odd_buf[..N/2];

    for k in 0..N/2 { even[k]= x[2*k]; odd[k]= x[2*k+1]; }
    for k in 0..N/2
    {   let t= odd[k]* (Complex64::from_polar(1.0, -2.0*PI*(k as f64)/(N as f64)) ).exp();
        x[k]     = even[k] +t;
        x[k +N/2]= even[k] -t;
    }

A slice is the preferred way to pass data around if the receiver just needs a view of the data. But when you want to create an array, your choice is usually between Vec<T> if the size is dynamic, or [T; N] if the size is static.

Slice types like &[T] are just borrowed views of memory, which is usually owned by an array or vector.

1 Like

..many thanks ..I'm beginning to catch onto Rust lang subtleties that went over my head