Vectors are not numbered correctly

So I'm trying to add vectors like this.. 5 elements into 2 groups so the result would be like [[0, 1,2], [3, 4]]..
However, I get [[0, 2], [0, 1]]
I can't seem to figure out why the output is printed this way..

 for _k in 0..num_partitions-1{
      let mut x_y : Vec<usize> = Vec::new();
      for i in 0..partition_size{
        x_y.push(v[ss]);
        if add <= ex && ex != 0 && ss != partition_size{
          //push extra to the first few
          x_i.push(v[ss]);
          //x_y.push(v[add]);
          increment(&mut ss);
          if add <= ex && ss != partition_size{
            x_i.push(v[ss]);
            //x_y.push(v[ss]);
            add+=1;
            increment(&mut ss);
          }
        }
        else if add >= ex && ss != partition_size{
          for i in 0..partition_size{
            x_i.push(v[ss]);
            increment(&mut ss);
          }
          /*x_i.push(v[ss]);
          increment(&mut ss);*/
        }
      }
      ks.push(x_y);
    }
    ks.push(x_i);

It is almost impossible to understand your code like this. You should try to provide a complete code example. Optimal would be either a playground link or, if this is part of a larger project, e.g. a link to a github repo. Try to create a test or a main function that calls into this code and prints the result (or uses assert_eq, etc), so that we can witness the result of "[[0, 2], [0, 1]]" the same way that you did.

1 Like

Here's the entire code (I ran it like this: ./main 5 2)

use std::env; // to get arugments passed to the program
use std::thread;
//use std::time::Duration;
/*
* Print the number of partitions and the size of each partition
* @param vs A vector of vectors
*/
fn print_partition_info(vs: &Vec<Vec<usize>>){
    println!("Number of partitions = {}\n", vs.len());
    for i in 0..vs.len(){
        println!("\tsize of partition {} = {}", i, vs[i].len());
    }
}
/*
* Create a vector with integers from 0 to num_elements -1
* @param num_elements How many integers to generate
* @return A vector with integers from 0 to (num_elements - 1)
*/
fn generate_data(num_elements: usize) -> Vec<usize>{
    let mut v : Vec<usize> = Vec::new();
    for i in 0..num_elements {
        v.push(i);
    }
    return v;
}
/*
* Partition the data in the vector v into 2 vectors
* @param v Vector of integers
* @return A vector that contains 2 vectors of integers
*/
fn partition_data_in_two(v: &Vec<usize>) -> Vec<Vec<usize>>{
    let partition_size = v.len() / 2;
    // Create a vector that will contain vectors of integers
    let mut xs: Vec<Vec<usize>> = Vec::new();
    // Create the first vector of integers
    let mut x1 : Vec<usize> = Vec::new();
    // Add the first half of the integers in the input vector to x1
    for i in 0..partition_size{
        x1.push(v[i]);
    }
    // Add x1 to the vector that will be returned by this function
    xs.push(x1);
    // Create the second vector of integers
    let mut x2 : Vec<usize> = Vec::new();
    // Add the second half of the integers in the input vector to x2
    for i in partition_size..v.len(){
        x2.push(v[i]);
    }
    // Add x2 to the vector that will be returned by this function
    xs.push(x2);
    // Return the result vector
    xs
}
/*
* Sum up the all the integers in the given vector
* @param v Vector of integers
* @return Sum of integers in v
* Note: this function has the same code as the reduce_data function.
*       But don't change the code of map_data or reduce_data.
*/
fn map_data(v: &Vec<usize>) -> usize{
    let mut sum = 0;
    for i in v{
        sum += i;
    }
    sum
}
/*
* Sum up the all the integers in the given vector
* @param v Vector of integers
* @return Sum of integers in v
*/
fn reduce_data(v: &Vec<usize>) -> usize{
    let mut sum = 0;
    for i in v{
        sum += i;
    }
    sum
}
/*
* A single threaded map-reduce program
*/
fn main() {
    // Use std::env to get arguments passed to the program
    let args: Vec<String> = env::args().collect();
    if args.len() != 3 {
        println!("ERROR: Usage {} num_partitions num_elements", args[0]);
        return;
    }
    let num_partitions : usize = args[1].parse().unwrap();
    //println!("partitions {}", num_partitions);
    let num_elements : usize = args[2].parse().unwrap();
    //println!("elements {}", num_elements);
    if num_partitions < 1{
      println!("ERROR: num_partitions must be at least 1");
        return;
    }
    if num_elements < num_partitions{
        println!("ERROR: num_elements cannot be smaller than num_partitions");
        return;
    }
    // Generate data.
    let v = generate_data(num_elements);
    // PARTITION STEP: partition the data into 2 partitions
    let xs = partition_data_in_two(&v);
    // Print info about the partitions
    
    println!("VEC {:?}", xs);
    print_partition_info(&xs);
    let mut intermediate_sums : Vec<usize> = Vec::new();
    // MAP STEP: Process each partition
    // CHANGE CODE START: Don't change any code above this line
    // Change the following code to create 2 threads that run concurrently and each of which uses map_data() function to process one of the two partitions
    let part1 = xs[0].clone();
    let t1 = thread::spawn(move || {map_data(&part1)});
    let part2 = xs[1].clone();
    let t2 = thread::spawn(move || {map_data(&part2)});
    let res1 = t1.join().unwrap();
    let res2 = t2.join().unwrap();
    intermediate_sums.push(res1);
    intermediate_sums.push(res2);
    // CHANGE CODE END: Don't change any code below this line until the next CHANGE CODE comment
    // Print the vector with the intermediate sums
    println!("Intermediate sums = {:?}", intermediate_sums);
    // REDUCE STEP: Process the intermediate result to produce the final result
    let sum = reduce_data(&intermediate_sums);
    println!("Sum = {}\n", sum);
     // CHANGE CODE: Add code that does the following:
    // 1. Calls partition_data to partition the data into equal partitions
    // 2. Calls print_partition_info to print info on the partitions that have been created
    // 3. Creates one thread per partition and uses each thread to concurrently process one partition
    // 4. Collects the intermediate sums from all the threads
    // 5. Prints information about the intermediate sums
    // 5. Calls reduce_data to process the intermediate sums
    // 6. Prints the final sum computed by reduce_data
    //clear the vector (removing the 2 intermediate sums before)
    intermediate_sums.clear();
    println!("PIE");
    let _ks = partition_data(num_partitions,&v);
    //create new threads
    //x starts at 0
    //let numb : usize = args[1].parse().unwrap();
    //thread::spawn(move || {map_data(&part1)});   
    let nn = 0;
    //let mut vv : Vec<usize> = Vec::new();
    let mut vv=Vec::new();
    for _i in 0..num_partitions{
      let p2 = _ks[nn].clone();
      let tt2 = thread::spawn(move || {map_data(&p2)});
      vv.push(tt2)
    }
    for entry in vv{
        intermediate_sums.push(entry.join().unwrap());
        //println!("Intermediate sums = {:?}", intermediate_sums);
    }
    println!("Intermediate sums = {:?}", intermediate_sums);
    let fin = reduce_data(&intermediate_sums);
    println!("Final Sum =  {:?}\n", fin);
}
fn increment(n: &mut usize) {
    *n += 1;
}
/*
* CHANGE CODE: code this function
* Note: Don't change the signature of this function
*
* Partitions the data into a number of partitions such that
* - the returned partitions contain all elements that are in the input vector
* - if num_elements is a multiple of num_partitions, then all partitions must have equal number of elements
* - if num_elements is not a multiple of num_partitions, some partitions can have one more element than other partitions
*
* @param num_partitions The number of partitions to create
* @param v The data to be partitioned
* @return A vector that contains vectors of integers
* 
*/
fn partition_data(num_partitions: usize, v: &Vec<usize>) -> Vec<Vec<usize>>{
    // Remove the following line which has been added to remove a compiler error
    println!("Number of Partitions: {:?}\n", num_partitions);
    println!("VECTOR {:?}", v.len());
    //num = partition_data_in_two(v)
    let partition_size = v.len() / num_partitions;
    let ex = v.len() % num_partitions;
    //println!("{}",ex);
    let mut ss = 0;
    let mut add = 0;
    println!("EX {}", ex);
    for i in 0..num_partitions{
        //let pie = partition_size + extra;
        if i < ex{
          println!("\tsize of partition {} = {}", i, partition_size+1);
        }
        else{
          println!("\tsize of partition {} = {}", i, partition_size);
        }
    }
    // Create a vector that will contain vectors of integers
    let mut ks: Vec<Vec<usize>> = Vec::new();
    // Add the first half of the integers in the input vector to x1
    let mut x_i : Vec<usize> = Vec::new();
   

   
   
    for _k in 0..num_partitions-1{
      let mut x_y : Vec<usize> = Vec::new();
      for i in 0..partition_size{
        x_y.push(v[ss]);
        if add <= ex && ex != 0 && ss != partition_size{
          //push extra to the first few
          x_i.push(v[ss]);
          //x_y.push(v[add]);
          increment(&mut ss);
          if add <= ex && ss != partition_size{
            x_i.push(v[ss]);
            //x_y.push(v[ss]);
            add+=1;
            increment(&mut ss);
          }
        }
        else if add >= ex && ss != partition_size{
          for i in 0..partition_size{
            x_i.push(v[ss]);
            increment(&mut ss);
          }
          /*x_i.push(v[ss]);
          increment(&mut ss);*/
        }
      }
      ks.push(x_y);
    }
    ks.push(x_i);
    
    println!("VEC {:?}", ks);
    ks
}

/*    for j in 0..num_partitions{
      let mut x_y : Vec<usize> = Vec::new();
      x_y.push(v[ss]);
      if ex == 0{
        increment(&mut ss);
        x_y.push(v[ss]);
        x_i.push(v[ss]);
      }
      else{
        increment(&mut ss);
        x_i.push(v[ss]);
      }
      increment(&mut ss);
      ks.push(x_y);
    }*/
/*
        else if _y > ex && ss != partition_size{
          x_i.push(v[ss]);
          increment(&mut ss);
          println!{"HI1 {}",ss}
        }
*/
/*
    for _i in 0..partition_size{
      let mut x_i : Vec<usize> = Vec::new();
      //let mut exx : Vec<usize> = Vec::new();
      for _y in 0..partition_size{
        //x_i.push(v[ss]);
        if _y < ex && ss != partition_size+1{
          //push extra to the first few
          x_i.push(v[ss]);
          println!{"HI {}",ss}
          increment(&mut ss);
        }
        else if _y > ex && ss != partition_size+1{
          x_i.push(v[ss]);
          println!{"HI1 {}",ss}
          increment(&mut ss);
        }
        else{
          println!{"HI21 {}",ss}
          //increment(&mut ss);
        }
      }
      ks.push(x_i);
    }
*/


1 Like

Okay, this is the most obvious problem:

    for _k in 0..num_partitions - 1 {
        let mut x_y: Vec<usize> = Vec::new();
        for i in 0..partition_size {
            x_y.push(v[ss]);
+           increment(&mut ss);
            if add <= ex && ex != 0 && ss != partition_size {
                //push extra to the first few
                x_i.push(v[ss]);
                //x_y.push(v[add]);
                increment(&mut ss);
                if add <= ex && ss != partition_size {
                    x_i.push(v[ss]);
                    //x_y.push(v[ss]);
                    add += 1;
                    increment(&mut ss);
                }
            } else if add >= ex && ss != partition_size {
                for i in 0..partition_size {
                    x_i.push(v[ss]);
                    increment(&mut ss);
                }
                /*x_i.push(v[ss]);
                increment(&mut ss);*/
            }
        }
        ks.push(x_y);
    }
1 Like

For some simplified, alternative implementation, look at this:

fn partition_data(num_partitions: usize, v: &[usize]) -> Vec<Vec<usize>> {
    let partition_size = v.len() / num_partitions;
    let extra = v.len() % num_partitions;
    let (v1, v2) = v.split_at(extra * (partition_size + 1));
    v1.chunks(partition_size + 1)
        .chain(v2.chunks(partition_size))
        .map(|chunk| chunk.to_vec())
        .collect()
}

(Note that you can still pass an &Vec<usize> to a function expecting &[usize].)

(example playground)

1 Like