0

I am trying to find the saddle points of a matrix, a borrowed array of vectors. For the purposes of this, a saddle point is an element of the matrix that is either the smallest in its column and the largest in its row, or the largest in its column, and the smallest in its row.

use rayon::prelude::*;

pub fn find_saddle_points(input: &[Vec<u64>]) -> Vec<(usize, usize)> {
    let flattened_matrix: Vec<(&u64)> = input.into_par_iter().flatten().collect::<Vec<&u64>>();
    match flattened_matrix == vec![] { //Check for empty input
        true => vec![],
        false => {
            let num_rows: usize = input.len();
            let num_cols: usize = input[0].len();

            let row_minima: Vec<Option<&u64>> = (0_usize..(num_rows - 1_usize))
                .into_par_iter()
                .map(|row_index| input[row_index].iter().min())
                .collect::<Vec<Option<&u64>>>();

            let row_maxima: Vec<Option<&u64>> = (0_usize..(num_rows - 1_usize))
                .into_par_iter()
                .map(|row_index| input[row_index].iter().max())
                .collect::<Vec<Option<&u64>>>();

            let input_tranpose: Vec<Vec<u64>> = (0_usize..(num_cols - 1_usize)) //Transpose the matrix to make it easier to get column information
                .into_par_iter()
                .map(|col_index| {
                    (0_usize..(num_rows - 1_usize))
                        .map(|row_index| input[row_index][col_index])
                        .collect::<Vec<u64>>() //Individual column
                })
                .collect::<Vec<Vec<u64>>>();

            let col_minima: Vec<Option<&u64>> = (0_usize..(num_cols - 1_usize))
                .into_par_iter()
                .map(|col_index| input_tranpose[col_index].iter().min())
                .collect::<Vec<Option<&u64>>>();

            let col_maxima: Vec<Option<&u64>> = (0_usize..(num_cols - 1_usize))
                .into_par_iter()
                .map(|col_index| input_tranpose[col_index].iter().max())
                .collect::<Vec<Option<&u64>>>();

            //All fine up to this point

            (0_usize..(num_rows - 1_usize))
                .map(|row_index| {
                    (0_usize..(num_cols - 1_usize)).map(|col_index| {
                        match (Some(row_minima[row_index]) == Some(col_maxima[col_index])
                            || Some(row_maxima[row_index]) == Some(col_minima[col_index]))
                        {
                            true => Some((row_index, col_index)),
                            false => None,
                        }
                    })
                })
                .collect::<Vec<(usize, usize)>>()
        }
    }
}

The error is in the final .collect:

error[E0277]: a collection of type `std::vec::Vec<(usize, usize)>` cannot be built from an iterator over elements of type `std::iter::Map<std::ops::Range<usize>, [closure@src/lib.rs:45:57: 52:22 row_minima:_, row_index:_, col_maxima:_, row_maxima:_, col_minima:_]>`
  --> src/lib.rs:54:18
   |
54 |                 .collect::<Vec<(usize, usize)>>()
   |                  ^^^^^^^ a collection of type `std::vec::Vec<(usize, usize)>` cannot be built from `std::iter::Iterator<Item=std::iter::Map<std::ops::Range<usize>, [closure@src/lib.rs:45:57: 52:22 row_minima:_, row_index:_, col_maxima:_, row_maxima:_, col_minima:_]>>`
   |
   = help: the trait `std::iter::FromIterator<std::iter::Map<std::ops::Range<usize>, [closure@src/lib.rs:45:57: 52:22 row_minima:_, row_index:_, col_maxima:_, row_maxima:_, col_minima:_]>>` is not implemented for `std::vec::Vec<(usize, usize)>`

I know that this is caused by the iterator being subjected to the collect function not being of the expected type, but to me it should be correct, and I'm not clear on why it isn't.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Alex
  • 2,270
  • 3
  • 33
  • 65
  • Please try to shorten the code next time to the necessary part. – hellow Feb 08 '19 at 12:38
  • @hellow I'm very happy to edit it, but since I'm so new to rust, it's not impossible that I have made a mistake further up, so I thought it might be good to include it. – Alex Feb 08 '19 at 12:38
  • @hellow edited to highlight the important bit – Alex Feb 08 '19 at 12:41
  • As a note: [Don't use match to differentiate between true/false](https://rust-lang.github.io/rust-clippy/master/index.html#match_bool). You are doing some useless `Some` comparision: `Some(a) == Some(b) <==> a == b`. You don't need to specify the type of variables most of the time, try to leave them out. – hellow Feb 08 '19 at 12:45
  • Why do you always write `- 1_usize` for the iterator? `a..b` means [a, b), which means inclusive a, but exclusive b (if you want [a, b] you have to write `a..=b`). Is that on purpose? – hellow Feb 08 '19 at 12:47
  • The purpose of the _usize is to make sure I'm getting the types correct (I'm a python dev, so I'm trying to be super explicit about types while I learn, just to make sure I don't screw up). The reason I didn't use a..=b is because I didn't know about it. Thank you! :) – Alex Feb 08 '19 at 12:49
  • Please reread my comment. I told you , that `-1` seems wrong to me. `a..=b` is equal to `a..(b+1)`! Plus, not minus. – hellow Feb 08 '19 at 12:51
  • Sorry, I guess I thought that a..b meant inclusive, so I was correcting for the list being zero-indexed – Alex Feb 08 '19 at 12:53
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/188112/discussion-between-hellow-and-alex). – hellow Feb 08 '19 at 12:54
  • Read the information [in the Rust tag info page](https://stackoverflow.com/tags/rust/info) for tips on how to reduce your code. – Shepmaster Feb 08 '19 at 14:50

1 Answers1

1

(The chat transcript will guide you through the solution of this problem, because it's kind of complex)

TL;DR use a combination of Iterator::flat_map and Iterator::filter_map to solve the problem.

(0_usize..(num_rows - 1_usize))
    .flat_map(|row_index| {
        (0_usize..(num_cols - 1_usize)).flat_map(|col_index| {
            match row_minima[row_index] == col_maxima[col_index]
                || row_maxima[row_index] == col_minima[col_index]
            {
                true => Some((row_index, col_index)),
                false => None,
            }
        })
    })
    .collect::<Vec<(usize, usize)>>()

Please note, that this code is very unidiomatic, but shows the solution.

hellow
  • 12,430
  • 7
  • 56
  • 79
  • 2
    Please transcribe the relevant parts of the chat into the answer. **Why** do `flat_map` / `filter_map` have an effect here? – Shepmaster Feb 08 '19 at 14:50