Rust NdArray 距离矩阵

亚历克斯·尼

我正在尝试编写使用ndarray以下方法计算距离矩阵的函数

extern crate ndarray;

use ndarray::{s, Array2, ArrayView1, indices_of, azip, array};
use ndarray::parallel::par_azip;
use std::f64;

type M = Array2<f64>;

fn main() {
    // make some arbitrary data
    let points = array!([0.,23.], [12., 13.], [15., 2.], [16., 145.], [42., 11.], [12., 12.], [11., 12.], [56., 18.], [34., 12.]);
    // calculate matrix
    let dist_arr = dist_to_mat(&points, &l2);
    println!("{}", dist_arr.mapv(|x| (100. * x).round() / 100.))
}

// as an example, use l2 distance
fn l2(x: &ArrayView1<f64>, y: &ArrayView1<f64>) -> f64 {
    let diff = x - y;
    let result = (&diff * &diff).sum();
    return result.sqrt()
}

pub fn dist_to_mat(
    points: &Array2<f64>,
    dist_fn: &dyn Fn(&ArrayView1<f64>, &ArrayView1<f64>) -> f64,
) -> M {
    // initialize array
    let mut distances = Array2::zeros((points.nrows(), points.nrows()));
    let idx = indices_of(&distances);
    // helper function to get the entries of points
    let func = |i: usize, j: usize| -> f64 {
        dist_fn(&points.slice(s![i, ..]), &points.slice(s![j, ..]))
    };
    // apply function to matrix with index array in lock-step
    par_azip!((c in &mut distances, (i,j) in idx){*c = func(i,j)}); // <- error here; works if par_azip is replaced with azip.
    return distances
}

虽然这适用于单线程azip,但par_azip我收到错误消息:

`dyn for<'r, 's, 't0, 't1> std::ops::Fn(&'r ndarray::ArrayBase<ndarray::ViewRepr<&'s f64>, ndarray::Dim<[usize; 1]>>, &'t0 ndarray::ArrayBase<ndarray::ViewRepr<&'t1 f64>, ndarray::Dim<[usize; 1]>>) -> f64` cannot be shared between threads safely

`dyn for<'r, 's, 't0, 't1> std::ops::Fn(&'r ndarray::ArrayBase<ndarray::ViewRepr<&'s f64>, ndarray::Dim<[usize; 1]>>, &'t0 ndarray::ArrayBase<ndarray::ViewRepr<&'t1 f64>, ndarray::Dim<[usize; 1]>>) -> f64` cannot be shared between threads safely

help: within `[closure@<::ndarray::zip::zipmacro::azip macros>:23:6: 23:7 func:&[closure@src/main.rs:27:16: 29:6 dist_fn:&&dyn for<'r, 's, 't0, 't1> std::ops::Fn(&'r ndarray::ArrayBase<ndarray::ViewRepr<&'s f64>, ndarray::Dim<[usize; 1]>>, &'t0 ndarray::ArrayBase<ndarray::ViewRepr<&'t1 f64>, ndarray::Dim<[usize; 1]>>) -> f64, points:&&ndarray::ArrayBase<ndarray::OwnedRepr<f64>, ndarray::Dim<[usize; 2]>>]]`, the trait `std::marker::Sync` is not implemented for `dyn for<'r, 's, 't0, 't1> std::ops::Fn(&'r ndarray::ArrayBase<ndarray::ViewRepr<&'s f64>, ndarray::Dim<[usize; 1]>>, &'t0 ndarray::ArrayBase<ndarray::ViewRepr<&'t1 f64>, ndarray::Dim<[usize; 1]>>) -> f64`
note: required because it appears within the type `&dyn for<'r, 's, 't0, 't1> std::ops::Fn(&'r ndarray::ArrayBase<ndarray::ViewRepr<&'s f64>, ndarray::Dim<[usize; 1]>>, &'t0 ndarray::ArrayBase<ndarray::ViewRepr<&'t1 f64>, ndarray::Dim<[usize; 1]>>) -> f64`
note: required because it appears within the type `&&dyn for<'r, 's, 't0, 't1> std::ops::Fn(&'r ndarray::ArrayBase<ndarray::ViewRepr<&'s f64>, ndarray::Dim<[usize; 1]>>, &'t0 ndarray::ArrayBase<ndarray::ViewRepr<&'t1 f64>, ndarray::Dim<[usize; 1]>>) -> f64`
note: required because it appears within the type `[closure@src/main.rs:27:16: 29:6 dist_fn:&&dyn for<'r, 's, 't0, 't1> std::ops::Fn(&'r ndarray::ArrayBase<ndarray::ViewRepr<&'s f64>, ndarray::Dim<[usize; 1]>>, &'t0 ndarray::ArrayBase<ndarray::ViewRepr<&'t1 f64>, ndarray::Dim<[usize; 1]>>) -> f64, points:&&ndarray::ArrayBase<ndarray::OwnedRepr<f64>, ndarray::Dim<[usize; 2]>>]`
note: required because it appears within the type `&[closure@src/main.rs:27:16: 29:6 dist_fn:&&dyn for<'r, 's, 't0, 't1> std::ops::Fn(&'r ndarray::ArrayBase<ndarray::ViewRepr<&'s f64>, ndarray::Dim<[usize; 1]>>, &'t0 ndarray::ArrayBase<ndarray::ViewRepr<&'t1 f64>, ndarray::Dim<[usize; 1]>>) -> f64, points:&&ndarray::ArrayBase<ndarray::OwnedRepr<f64>, ndarray::Dim<[usize; 2]>>]`
note: required because it appears within the type `[closure@<::ndarray::zip::zipmacro::azip macros>:23:6: 23:7 func:&[closure@src/main.rs:27:16: 29:6 dist_fn:&&dyn for<'r, 's, 't0, 't1> std::ops::Fn(&'r ndarray::ArrayBase<ndarray::ViewRepr<&'s f64>, ndarray::Dim<[usize; 1]>>, &'t0 ndarray::ArrayBase<ndarray::ViewRepr<&'t1 f64>, ndarray::Dim<[usize; 1]>>) -> f64, points:&&ndarray::ArrayBase<ndarray::OwnedRepr<f64>, ndarray::Dim<[usize; 2]>>]]`rustc(E0277)
<::ndarray::parallel::zipmacro::par_azip macros>(1, 50): `dyn for<'r, 's, 't0, 't1> std::ops::Fn(&'r ndarray::ArrayBase<ndarray::ViewRepr<&'s f64>, ndarray::Dim<[usize; 1]>>, &'t0 ndarray::ArrayBase<ndarray::ViewRepr<&'t1 f64>, ndarray::Dim<[usize; 1]>>) -> f64` cannot be shared between threads safely

哪个对象不能在线程之间安全地共享:dist_funor的返回值dist_fun我该如何解决?

亚历克斯·尼

固定它。<-

extern crate ndarray;

use ndarray::{s, Array2, ArrayView1, indices_of, azip, array};
use ndarray::parallel::par_azip;
use std::f64;

type M = Array2<f64>;

fn main() {
    // make some arbitrary data
    let points = array!([0.,23.], [12., 13.], [15., 2.], [16., 145.], [42., 11.], [12., 12.], [11., 12.], [56., 18.], [34., 12.]);
    // calculate matrix
    let dist_arr = dist_to_mat(&points, &l2);
    println!("{}", dist_arr.mapv(|x| (100. * x).round() / 100.))
}

// as an example, use l2 distance
fn l2(x: &ArrayView1<f64>, y: &ArrayView1<f64>) -> f64 {
    let diff = x - y;
    let result = (&diff * &diff).sum();
    return result.sqrt()
}

pub fn dist_to_mat(
    points: &Array2<f64>,
    dist_fn: &fn(&ArrayView1<f64>, &ArrayView1<f64>) -> f64, // <- different signature
) -> M {
    // initialize array
    let mut distances = Array2::zeros((points.nrows(), points.nrows()));
    let idx = indices_of(&distances);
    // helper function to get the entries of points
    let func = |i: usize, j: usize| -> f64 {
        dist_fn(&points.slice(s![i, ..]), &points.slice(s![j, ..]))
    };
    // apply function to matrix with index array in lock-step
    par_azip!((c in &mut distances, (i,j) in idx){*c = func(i,j)});
    return distances
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章