2017-03-10 50 views
0

我試圖通過使用到parallelise的拉默 - 道格拉斯 - 普克線簡化算法麗陽par_iter,而不是iter如何在這裏滿足迭代器的綁定特性以便使用Rayon?

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 d SendSyncPoint<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

請提供[MCVE]。這裏有太多的代碼用於指定的錯誤。 –

+2

*我爲'Point '發送''''發送'和'同步'* - 你不應該**這樣做,因爲你不能保證'Point'跨線程邊界傳輸是安全的* *不論** T的具體類型如何。您只是爲您的程序添加不安全性。 – Shepmaster

回答

1

Rayon的並行迭代器實現ParallelIterator而不是Iterator。特別是,這意味着您不能只將par_iter()放在for-loop標頭中,並期望它突然平行。 for是順序的。

由於您的原始代碼不是按照迭代器函數編寫的,而是針對循環編寫的,因此您無法僅通過切換到par_iter()來並行編譯它,但必須重新設計代碼。

特別是,代碼的失敗部分似乎是實現max_by_key函數。

相關問題