簡體   English   中英

如何使用人造絲更新包含 Rust 數組的個人結構

[英]How to use rayon to update a personal struct containing an Array in Rust

語境

總體概述

(這里是github 頁面,其中包含我的問題的最小示例,以及我整個項目的頁面)我對 Rust 很陌生,我正在嘗試模擬 Rust 中流體的行為。 這很簡單:為每個時間步計算具有一些函數的大型數組。

我想使用人造絲並行化每個時間步完成的計算。 但是編譯器不希望我訪問包含我要修改的數組的可變結構,即使我確定每次修改都會在數組中的不同位置:這向我保證它是安全的。 (我認為?)。

所以我的問題是:我應該在這里使用不安全的生銹嗎? 如果是這樣,如何? 並且:是否有可能讓 Rust 明白它是安全的,或者在沒有不安全 Rust 的情況下正確地做到這一點? 我看到這篇文章有點像我的問題,但找不到使用該解決方案解決我的問題的方法。

我還嘗試在各處放置unsafe {...}關鍵字,但編譯器仍然抱怨...

您可能只需要閱讀“結構”小節即可理解問題,但我還會放一個“功能”小節,以防它很重要。 如果您認為可能沒有必要,可以跳到“主要功能”小節。

結構體

這是我的結構:我想保持這種方式,因為它們會給我(我認為)更多的 setter/getter 靈活性,但我願意改變它現在的實現方式。

#[derive(Debug, PartialEq)]
struct vec2D {pub x: f64, pub y: f64}

#[derive(Debug, PartialEq)]
 struct ScalarField2D {
     s: Array2<f64>,
}    

#[derive(Debug, PartialEq)]
 struct VectorField2D {
     x: ScalarField2D,
     y: ScalarField2D
}

impl ScalarField2D {

     // also a constructor new() but not shown for simplicity

     fn get_pos(&self, x: usize, y: usize) -> f64
    {return self.s[[y,x]];}

    fn set_pos(&mut self, x: usize, y: usize, f: f64)
    {self.s[[y,x]] = f;}
}

impl VectorField2D {

     // also a constructor new() but not shown for simplicity

     fn get_pos(&self, x: usize, y: usize) -> vec2D
    {let vec_at_pos = vec2D {
        x: self.x.get_pos(x, y),
        y: self.y.get_pos(x, y)};
     return vec_at_pos;}

    fn set_pos(&mut self, x: usize, y: usize, vec: &vec2D)
    {self.x.set_pos(x, y, vec.x);
     self.y.set_pos(x, y, vec.y);}

}

功能

這是我的函數:它采用 ScalarField2D 結構,並在 ScalarField2D 數組的特定位置計算稱為“梯度”的向量,然后將該向量作為“vec2D”結構返回。

// computes the gradient of a scalar field at a given position
fn grad_scalar(a: &ScalarField2D,
               x: i32, y: i32,
               x_max: i32, y_max: i32) -> vec2D
{
    let ip = ((x+1) % x_max) as usize;
    // i-1 with Periodic Boundaries
    let im = ((x - 1 + x_max) % x_max) as usize;
    // j+1 with Periodic Boundaries
    let jp = ((y+1) % y_max) as usize;
    // j-1 with Periodic Boundaries
    let jm = ((y - 1 + y_max) % y_max) as usize;
    let (i, j) = (x as usize, y as usize);

    let grad = vec2D {
        x: (a.get_pos(ip, j) - a.get_pos(im, j))/(2.),
        y: (a.get_pos(i, jp) - a.get_pos(i, jm))/(2.)};
        
    return grad;
}

主功能

這是我的問題:我嘗試使用 (0..x_max).into_par_iter()(或 y_max for y)遍歷所有可能的 x 和 y,計算與每個位置關聯的梯度,然后將值設置為 ScalarField2D使用 set_pos 方法的結構...這是主要功能和導入命令,我將在下一小節中向您展示我收到的錯誤消息

use ndarray::prelude::*;
use rayon::prelude::*;

fn main() {

    let (x_max, y_max) = (2usize, 50usize);
    let (x_maxi32, y_maxi32) = (x_max as i32, y_max as i32);

    let mut GD_grad_rho = VectorField2D::new(x_max, y_max);
    let mut GD_rho = ScalarField2D::new(x_max, y_max);    

    let x_iterator = (0..x_max).into_par_iter();
    x_iterator.map(|xi| {
        let y_iterator = (0..y_max).into_par_iter();
        y_iterator.map(|yi| {

            // unsafe here?
            GD_grad_rho
                .set_pos(xi, yi,
                         &grad_scalar(&GD_rho,
                                      xi as i32, yi as i32,
                                      x_maxi32, y_maxi32));
            
        });});
}

錯誤信息

這是我得到的編譯錯誤

error[E0596]: cannot borrow `GD_grad_rho` as mutable, as it is a captured variable in a `Fn` closure
   --> src/main.rs:104:13
    |
104 | /             GD_grad_rho
105 | |                 .set_pos(xi, yi,
106 | |                          &grad_scalar(&GD_rho,
107 | |                                       xi as i32, yi as i32,
108 | |                                       x_maxi32, y_maxi32));
    | |__________________________________________________________^ cannot borrow as mutable

error[E0596]: cannot borrow `GD_grad_rho` as mutable, as it is a captured variable in a `Fn` closure
   --> src/main.rs:101:24
    |
101 |         y_iterator.map(|yi| {
    |                        ^^^^ cannot borrow as mutable
...
104 |             GD_grad_rho
    |             ----------- mutable borrow occurs due to use of `GD_grad_rho` in closure

For more information about this error, try `rustc --explain E0596`.
error: could not compile `minimal_example_para` due to 2 previous errors

如果您想要完整的東西,我創建了一個包含所有內容的github 存儲庫

susitsm 回答后的測試

所以我做了這樣的事情:

use ndarray::prelude::*;
use rayon::prelude::*;

fn grad_scalar(a: &Array2<f64>,
          i: usize, j: usize) -> (f64, f64)
{
    let array_shape = a.shape();
    let imax = array_shape[0];
    let jmax = array_shape[1];

    // i-1 with Periodic Boundaries
    let ip = ((i + 1) % imax);
    // i-1 with Periodic Boundaries
    let im = ((i + imax) - 1) % imax;
    // j+1 with Periodic Boundaries
    let jp = ((j + 1) % jmax);
    // j-1 with Periodic Boundaries
    let jm = ((j + jmax) - 1) % jmax;

    let grad_i = (a[[ip, j]] - a[[im, j]])/2.;
    let grad_j = (a[[i, jp]] - a[[i, jm]])/2.;

    return (grad_i, grad_j);
}

fn main() {

    let a = Array::<f64, Ix2>::ones((dim, dim));

    let index_list: Vec<(_, _)> = (0..a.len())
        .into_par_iter()
        .map(|i| (i / a.dim().0, i % a.dim().1))
        .collect();

    let (r1, r2): (Vec<_>, Vec<_>) = (0..a.len())
        .into_par_iter()
        .map(|i| (index_list[i].0, index_list[i].1))
        .map(|(i, j)| grad_scalar(&a, i, j))
        .collect();

    let grad_row = Array2::from_shape_vec(a.dim(), r1).unwrap();
    let grad_col = Array2::from_shape_vec(a.dim(), r2).unwrap();

}

這給了我想要的結果,即使我想通過我的結構訪問這些值。 這不是我想要的,但我們越來越近了但我想知道更多陣列的效率,我會為此發布一個單獨的問題

你可以這樣做:

use ndarray::Array2;
use rayon::prelude::*;

fn main() {
    let a: Vec<u64> = (0..20000).collect();
    let a = Array2::from_shape_vec((100, 200), a).unwrap();

    let stuff = |arr, i, j| (i + j, i * j);
    let (x, y): (Vec<_>, Vec<_>) = (0..a.len())
        .into_par_iter()
        .map(|i| (i / a.dim().0, i % a.dim().1))
        .map(|(i, j)| stuff(&a, i, j))
        .collect();
    let grad_x = Array2::from_shape_vec(a.dim(), x);
    let grad_y = Array2::from_shape_vec(a.dim(), y);
}

您還可以為 VectorField2D 實現FromParallelIterator<vec2D> VectorField2D使其更易於使用`

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM