Closed
Description
I tried this code:
use std::ops::{DivAssign, SubAssign};
use ndarray::{s, Array2, ArrayView1, Axis, Zip};
use num::{Zero, One};
use rayon::prelude::*;
pub fn gaussian_elimination<T>(mut a: Array2<T>) -> Array2<T>
where
T: One + Zero + Clone + Send + Sync + DivAssign + SubAssign,
{
let (n, m) = a.dim();
assert!(n > 0);
let mut pivots = vec![];
let mut pivot = 0;
for i in 0..n {
if a[[i, pivot]].is_zero() {
if let Some((new_pivot, row)) = (pivot..m)
.into_par_iter()
.flat_map(|pivot| {
let a: ArrayView1<_> = a.slice(s![i.., pivot]);
a.axis_iter(Axis(0))
.into_par_iter()
.enumerate()
.flat_map(|(j, x)| {
if x.into_scalar().is_zero() {
None
} else {
Some(j)
}
})
.find_any(|_| true)
.map(|row| (pivot, row))
})
.find_first(|_| true)
{
pivot = new_pivot;
if row > 0 {
let mut a = a.slice_mut(s![i..; row, ..]);
let mut it = a.axis_iter_mut(Axis(0));
let this_row = it.next().expect("this row exists");
let that_row = it.next().expect("that row exists");
Zip::from(this_row).and(that_row).par_apply(std::mem::swap);
}
} else {
break;
}
}
pivots.push((i, pivot));
let (mut this_equation, mut rest_equations) = a.slice_mut(s![i.., ..]).split_at(Axis(0), 1);
let mut this_equation = this_equation.index_axis_mut(Axis(0), 0);
let scale = this_equation[pivot].clone();
assert!(!scale.is_zero());
this_equation.iter_mut().for_each(|a| {
*a /= scale.clone();
});
rest_equations
.axis_iter_mut(Axis(0))
.into_par_iter()
.for_each(|mut eqn| {
let scale = eqn[pivot].clone();
if !scale.is_zero() {
eqn.iter_mut()
.zip(this_equation.iter())
.for_each(|(e, e_)| *e -= e_.clone() * scale.clone());
}
});
pivot += 1;
if pivot >= m {
break;
}
}
// a is in row echelon form now
if pivots.len() > 1 {
for (i, pivot) in pivots[1..].iter().rev() {
let (mut rest_equations, this_equation) =
a.slice_mut(s![..=*i, ..]).split_at(Axis(0), *i);
let this_equation = this_equation.index_axis(Axis(0), 0);
rest_equations.axis_iter_mut(Axis(0)).for_each(|eqn| {
if eqn[*pivot].is_zero() {
return;
}
let scale = eqn[*pivot].clone();
Zip::from(eqn)
.and(this_equation)
.par_apply(|e, e_| *e -= e_.clone() * scale.clone());
});
}
}
a
}
I expected to see this happen:
On Rust 1.44.0, this compiles.
Instead, this happened:
error[E0311]: the parameter type `T` may not live long enough
--> src/lib.rs:85:17
|
85 | / Zip::from(eqn)
86 | | .and(this_equation)
| |_______________________________________^
|
= note: the parameter type `T` must be valid for the empty lifetime...
= note: ...so that the reference type `&T` does not outlive the data it points at
error: aborting due to previous error
Meta
rustc --version --verbose
:
rustc 1.46.0-nightly (346aec9b0 2020-07-11)
binary: rustc
commit-hash: 346aec9b02f3c74f3fce97fd6bda24709d220e49
commit-date: 2020-07-11
host: x86_64-unknown-linux-gnu
release: 1.46.0-nightly
LLVM version: 10.0
Metadata
Metadata
Assignees
Labels
Area: The borrow checkerCategory: This is a bug.Call for participation: This issue has a repro, but needs a Minimal Complete and Verifiable ExampleHelping to "clean up" bugs with minimal examples and bisectionsCritical priorityRelevant to the compiler team, which will review and decide on the PR/issue.Performance or correctness regression from one stable version to another.