在Rust

时间:2017-04-08 12:00:38

标签: arrays rust iteration slice

我通过移植一个用C编写的小程序来学习Rust。它的工作性能与C版本相当。尽管如此,我仍然无法帮助,但感觉我的代码可能更好,因此这篇文章。

以下代码使用高斯消元法求解矩阵方程,这需要迭代数组的部分。

pub struct MatrixEquation {
    vec: Vec<f64>,
    mat: Vec<Vec<f64>>,
}

impl MatrixEquation {
    fn solve(&mut self) {
        let size = self.vec.len();
        // Transform matrix to upper triangular
        for row in 0..size {
            let mut rfabs = self.mat[row][row].abs();
            let mut pivot = row;

            for trow in row + 1..size {
                let tfabs = self.mat[trow][row].abs();
                if tfabs > rfabs {
                    pivot = trow;
                    rfabs = tfabs;
                }
            }

            if pivot != row {
                self.vec.swap(pivot, row);
                self.mat.swap(pivot, row);
            }

            if !self.mat[row][row].is_normal() {
                die!("Matrix is singular");
            }

            for elem in row + 1..size {
                if self.mat[elem][row] != 0.0 {
                    let scale = self.mat[elem][row] / self.mat[row][row];
                    for tcol in row..size {
                        self.mat[elem][tcol] -= self.mat[row][tcol] * scale;
                    }
                    self.vec[elem] -= self.vec[row] * scale;
                }
            }
        }

        for row in (0..size).rev() {
            self.vec[row] /= self.mat[row][row];
            let backsub = self.vec[row];
            for trow in 0..row {
                self.vec[trow] -= self.mat[trow][row] * backsub;
            }
        }
    }
}

我的第一个问题是最后的替代循环。我必须向后循环行。似乎有一种直接的方式来做到这一点。构造一个范围并调用rev()似乎是一种可以接受的方式,但它似乎很重要。做这样的事情被视为最佳做法?

我的另一个担心是我使用数字索引而不是迭代器,我不想做任何迫使编译器进行边界检查的事情。我找到了zip()方法,它可能对我尝试做的事情很有用,但由于我在遍历它时没有从行的开头开始,所以我必须调用skip( )我认为效率低于数字索引到行的中间。如果你在上面的程序中编写elem循环,你会怎么做?

1 个答案:

答案 0 :(得分:0)

您的问题和代码表明您的工作处于错误的抽象层次。要编写专注于手头问题而不会迷失在内存表示细节中的优雅代码,您应该将其基于提供适当抽象的包。

经常需要密集的N维数组,因此您可以选择实现它们的多个包 - 例如,rust-ndarray提供以下功能:

  • 通用N维数组
  • 拥有的数组和数组视图
  • 也可以使用任意步长进行切片,使用负数索引来表示轴末端的元素。
  • 数组的视图和子视图;产生子视图的迭代器。

这些正是您认为代码中缺少的内容。