如何在这里使用人造丝满足Iterator特性限制?

时间:2017-03-10 15:01:44

标签: rust rayon

我试图通过使用Rayon的par_iter代替iter来并行化Ramer-Douglas-Peucker线简化算法:

extern crate num_traits;
use num_traits::{Float, ToPrimitive};
extern crate rayon;
use self::rayon::prelude::*;

#[derive(PartialEq, Clone, Copy, Debug)]
pub struct Coordinate<T>
    where T: Float
{
    pub x: T,
    pub y: T,
}

#[derive(PartialEq, Clone, Copy, Debug)]
pub struct Point<T>(pub Coordinate<T>) where T: Float;

impl<T> Point<T>
    where T: Float + ToPrimitive
{
    pub fn new(x: T, y: T) -> Point<T> {
        Point(Coordinate { x: x, y: y })
    }
    pub fn x(&self) -> T {
        self.0.x
    }
    pub fn y(&self) -> T {
        self.0.y
    }
}

unsafe impl<T> Send for Point<T> where T: Float {}
unsafe impl<T> Sync for Point<T> where T: Float {}

fn distance<T>(a: &Point<T>, p: &Point<T>) -> T 
    where T: Float
{
    let (dx, dy) = (a.x() - p.x(), a.y() - p.y());
    dx.hypot(dy)
}

// perpendicular distance from a point to a line
fn point_line_distance<T>(point: &Point<T>, start: &Point<T>, end: &Point<T>) -> T
    where T: Float
{
    if start == end {
        distance(point, start)
    } else {
        let numerator = ((end.x() - start.x()) * (start.y() - point.y()) -
                         (start.x() - point.x()) * (end.y() - start.y()))
            .abs();
        let denominator = distance(start, end);
        numerator / denominator
    }
}

// Ramer–Douglas-Peucker line simplification algorithm
fn rdp<T>(points: &[Point<T>], epsilon: &T) -> Vec<Point<T>>
    where T: Float + Send + Sync
{
    if points.is_empty() {
        return points.to_vec();
    }
    let mut dmax = T::zero();
    let mut index: usize = 0;
    let mut distance: T;

    for (i, _) in points.par_iter().enumerate().take(points.len() - 1).skip(1) {
        distance = point_line_distance(&points[i], &points[0], &*points.last().unwrap());
        if distance > dmax {
            index = i;
            dmax = distance;
        }
    }
    if dmax > *epsilon {
        let mut intermediate = rdp(&points[..index + 1], &*epsilon);
        intermediate.pop();
        intermediate.extend_from_slice(&rdp(&points[index..], &*epsilon));
        intermediate
    } else {
        vec![*points.first().unwrap(), *points.last().unwrap()]
    }
}

#[cfg(test)]
mod test {
    use super::{Point};
    use super::{rdp};
        #[test]
    fn rdp_test() {
        let mut vec = Vec::new();
        vec.push(Point::new(0.0, 0.0));
        vec.push(Point::new(5.0, 4.0));
        vec.push(Point::new(11.0, 5.5));
        vec.push(Point::new(17.3, 3.2));
        vec.push(Point::new(27.8, 0.1));
        let mut compare = Vec::new();
        compare.push(Point::new(0.0, 0.0));
        compare.push(Point::new(5.0, 4.0));
        compare.push(Point::new(11.0, 5.5));
        compare.push(Point::new(27.8, 0.1));
        let simplified = rdp(&vec, &1.0);
        assert_eq!(simplified, compare);
    }
}

我为impl Send d SyncPoint<T>,但当我切换到par_iter时,我收到以下错误:

error[E0277]: the trait bound rayon::par_iter::skip::Skip<rayon::par_iter::take::Take<rayon::par_iter::enumerate::Enumerate<rayon::par_iter::slice::SliceIter<'_, Point<T>>>>>: std::iter::Iterator is not satisfied
   --> lib.rs:107:5

= note: rayon::par_iter::skip::Skip<rayon::par_iter::take::Take<rayon::par_iter::enumerate::Enumerate<rayon::par_iter::slice::SliceIter<'_, Point<T>>>>> is not an iterator; maybe try calling .iter() or a similar method
= note: required by std::iter::IntoIterator::into_iter

我不明白它的要求。问题是我在元组上运行吗?

1 个答案:

答案 0 :(得分:2)

Rayon的并行迭代器实现Iterator,而不是par_iter()。特别是,这意味着您不能只将for置于for循环标头中并期望它突然并行。 par_iter()是顺序的。

由于您的原始代码不是根据迭代器函数编写的,而是针对循环编写的,因此只需切换到{{1}}即可将其并行化,但必须实际重新设计代码。

特别是,代码的失败部分似乎正在实现max_by_key函数。