Rust NdArray Расстояние Матрица - PullRequest
0 голосов
/ 17 февраля 2020

Я пытаюсь написать функцию, которая вычисляет матрицы расстояний, используя 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_fun или dist_fun? Как мне это исправить?

1 Ответ

0 голосов
/ 18 февраля 2020

Исправлено. см <-

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
}
...