Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Safe lax::vec_uninit #334

Merged
merged 2 commits into from Sep 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
62 changes: 62 additions & 0 deletions lax/src/alloc.rs
@@ -0,0 +1,62 @@
use cauchy::*;
use std::mem::MaybeUninit;

/// Helper for getting pointer of slice
pub(crate) trait AsPtr: Sized {
type Elem;
fn as_ptr(vec: &[Self]) -> *const Self::Elem;
fn as_mut_ptr(vec: &mut [Self]) -> *mut Self::Elem;
}

macro_rules! impl_as_ptr {
($target:ty, $elem:ty) => {
impl AsPtr for $target {
type Elem = $elem;
fn as_ptr(vec: &[Self]) -> *const Self::Elem {
vec.as_ptr() as *const _
}
fn as_mut_ptr(vec: &mut [Self]) -> *mut Self::Elem {
vec.as_mut_ptr() as *mut _
}
}
};
}
impl_as_ptr!(i32, i32);
impl_as_ptr!(f32, f32);
impl_as_ptr!(f64, f64);
impl_as_ptr!(c32, lapack_sys::__BindgenComplex<f32>);
impl_as_ptr!(c64, lapack_sys::__BindgenComplex<f64>);
impl_as_ptr!(MaybeUninit<i32>, i32);
impl_as_ptr!(MaybeUninit<f32>, f32);
impl_as_ptr!(MaybeUninit<f64>, f64);
impl_as_ptr!(MaybeUninit<c32>, lapack_sys::__BindgenComplex<f32>);
impl_as_ptr!(MaybeUninit<c64>, lapack_sys::__BindgenComplex<f64>);

pub(crate) trait VecAssumeInit {
type Target;
unsafe fn assume_init(self) -> Self::Target;
}

impl<T> VecAssumeInit for Vec<MaybeUninit<T>> {
type Target = Vec<T>;
unsafe fn assume_init(self) -> Self::Target {
// FIXME use Vec::into_raw_parts instead after stablized
// https://doc.rust-lang.org/std/vec/struct.Vec.html#method.into_raw_parts
let mut me = std::mem::ManuallyDrop::new(self);
Vec::from_raw_parts(me.as_mut_ptr() as *mut T, me.len(), me.capacity())
}
}

/// Create a vector without initialization
///
/// Safety
/// ------
/// - Memory is not initialized. Do not read the memory before write.
///
pub(crate) fn vec_uninit<T: Sized>(n: usize) -> Vec<MaybeUninit<T>> {
let mut v = Vec::with_capacity(n);
unsafe {
v.set_len(n);
}
v
}
22 changes: 11 additions & 11 deletions lax/src/eig.rs
Expand Up @@ -48,13 +48,13 @@ macro_rules! impl_eig_complex {
} else {
(JobEv::None, JobEv::None)
};
let mut eigs: Vec<MaybeUninit<Self>> = unsafe { vec_uninit(n as usize) };
let mut rwork: Vec<MaybeUninit<Self::Real>> = unsafe { vec_uninit(2 * n as usize) };
let mut eigs: Vec<MaybeUninit<Self>> = vec_uninit(n as usize);
let mut rwork: Vec<MaybeUninit<Self::Real>> = vec_uninit(2 * n as usize);

let mut vl: Option<Vec<MaybeUninit<Self>>> =
jobvl.then(|| unsafe { vec_uninit((n * n) as usize) });
jobvl.then(|| vec_uninit((n * n) as usize));
let mut vr: Option<Vec<MaybeUninit<Self>>> =
jobvr.then(|| unsafe { vec_uninit((n * n) as usize) });
jobvr.then(|| vec_uninit((n * n) as usize));

// calc work size
let mut info = 0;
Expand All @@ -81,7 +81,7 @@ macro_rules! impl_eig_complex {

// actal ev
let lwork = work_size[0].to_usize().unwrap();
let mut work: Vec<MaybeUninit<Self>> = unsafe { vec_uninit(lwork) };
let mut work: Vec<MaybeUninit<Self>> = vec_uninit(lwork);
let lwork = lwork as i32;
unsafe {
$ev(
Expand Down Expand Up @@ -156,13 +156,13 @@ macro_rules! impl_eig_real {
} else {
(JobEv::None, JobEv::None)
};
let mut eig_re: Vec<MaybeUninit<Self>> = unsafe { vec_uninit(n as usize) };
let mut eig_im: Vec<MaybeUninit<Self>> = unsafe { vec_uninit(n as usize) };
let mut eig_re: Vec<MaybeUninit<Self>> = vec_uninit(n as usize);
let mut eig_im: Vec<MaybeUninit<Self>> = vec_uninit(n as usize);

let mut vl: Option<Vec<MaybeUninit<Self>>> =
jobvl.then(|| unsafe { vec_uninit((n * n) as usize) });
jobvl.then(|| vec_uninit((n * n) as usize));
let mut vr: Option<Vec<MaybeUninit<Self>>> =
jobvr.then(|| unsafe { vec_uninit((n * n) as usize) });
jobvr.then(|| vec_uninit((n * n) as usize));

// calc work size
let mut info = 0;
Expand All @@ -189,7 +189,7 @@ macro_rules! impl_eig_real {

// actual ev
let lwork = work_size[0].to_usize().unwrap();
let mut work: Vec<MaybeUninit<Self>> = unsafe { vec_uninit(lwork) };
let mut work: Vec<MaybeUninit<Self>> = vec_uninit(lwork);
let lwork = lwork as i32;
unsafe {
$ev(
Expand Down Expand Up @@ -244,7 +244,7 @@ macro_rules! impl_eig_real {

let n = n as usize;
let v = vr.or(vl).unwrap();
let mut eigvecs: Vec<MaybeUninit<Self::Complex>> = unsafe { vec_uninit(n * n) };
let mut eigvecs: Vec<MaybeUninit<Self::Complex>> = vec_uninit(n * n);
let mut col = 0;
while col < n {
if eig_im[col] == 0. {
Expand Down
12 changes: 6 additions & 6 deletions lax/src/eigh.rs
Expand Up @@ -58,10 +58,10 @@ macro_rules! impl_eigh {
assert_eq!(layout.len(), layout.lda());
let n = layout.len();
let jobz = if calc_v { JobEv::All } else { JobEv::None };
let mut eigs: Vec<MaybeUninit<Self::Real>> = unsafe { vec_uninit(n as usize) };
let mut eigs: Vec<MaybeUninit<Self::Real>> = vec_uninit(n as usize);

$(
let mut $rwork_ident: Vec<MaybeUninit<Self::Real>> = unsafe { vec_uninit(3 * n as usize - 2 as usize) };
let mut $rwork_ident: Vec<MaybeUninit<Self::Real>> = vec_uninit(3 * n as usize - 2 as usize);
)*

// calc work size
Expand All @@ -85,7 +85,7 @@ macro_rules! impl_eigh {

// actual ev
let lwork = work_size[0].to_usize().unwrap();
let mut work: Vec<MaybeUninit<Self>> = unsafe { vec_uninit(lwork) };
let mut work: Vec<MaybeUninit<Self>> = vec_uninit(lwork);
let lwork = lwork as i32;
unsafe {
$ev(
Expand Down Expand Up @@ -117,10 +117,10 @@ macro_rules! impl_eigh {
assert_eq!(layout.len(), layout.lda());
let n = layout.len();
let jobz = if calc_v { JobEv::All } else { JobEv::None };
let mut eigs: Vec<MaybeUninit<Self::Real>> = unsafe { vec_uninit(n as usize) };
let mut eigs: Vec<MaybeUninit<Self::Real>> = vec_uninit(n as usize);

$(
let mut $rwork_ident: Vec<MaybeUninit<Self::Real>> = unsafe { vec_uninit(3 * n as usize - 2) };
let mut $rwork_ident: Vec<MaybeUninit<Self::Real>> = vec_uninit(3 * n as usize - 2);
)*

// calc work size
Expand All @@ -147,7 +147,7 @@ macro_rules! impl_eigh {

// actual evg
let lwork = work_size[0].to_usize().unwrap();
let mut work: Vec<MaybeUninit<Self>> = unsafe { vec_uninit(lwork) };
let mut work: Vec<MaybeUninit<Self>> = vec_uninit(lwork);
let lwork = lwork as i32;
unsafe {
$evg(
Expand Down
2 changes: 1 addition & 1 deletion lax/src/layout.rs
Expand Up @@ -202,7 +202,7 @@ pub fn transpose<T: Copy>(layout: MatrixLayout, input: &[T]) -> (MatrixLayout, V
let n = n as usize;
assert_eq!(input.len(), m * n);

let mut out: Vec<MaybeUninit<T>> = unsafe { vec_uninit(m * n) };
let mut out: Vec<MaybeUninit<T>> = vec_uninit(m * n);

match layout {
MatrixLayout::C { .. } => {
Expand Down
8 changes: 4 additions & 4 deletions lax/src/least_squares.rs
Expand Up @@ -91,7 +91,7 @@ macro_rules! impl_least_squares {
};

let rcond: Self::Real = -1.;
let mut singular_values: Vec<MaybeUninit<Self::Real>> = unsafe { vec_uninit( k as usize) };
let mut singular_values: Vec<MaybeUninit<Self::Real>> = vec_uninit( k as usize);
let mut rank: i32 = 0;

// eval work size
Expand Down Expand Up @@ -124,12 +124,12 @@ macro_rules! impl_least_squares {

// calc
let lwork = work_size[0].to_usize().unwrap();
let mut work: Vec<MaybeUninit<Self>> = unsafe { vec_uninit(lwork) };
let mut work: Vec<MaybeUninit<Self>> = vec_uninit(lwork);
let liwork = iwork_size[0].to_usize().unwrap();
let mut iwork: Vec<MaybeUninit<i32>> = unsafe { vec_uninit(liwork) };
let mut iwork: Vec<MaybeUninit<i32>> = vec_uninit(liwork);
$(
let lrwork = $rwork[0].to_usize().unwrap();
let mut $rwork: Vec<MaybeUninit<Self::Real>> = unsafe { vec_uninit(lrwork) };
let mut $rwork: Vec<MaybeUninit<Self::Real>> = vec_uninit(lrwork);
)*
unsafe {
$gelsd(
Expand Down
60 changes: 2 additions & 58 deletions lax/src/lib.rs
Expand Up @@ -84,6 +84,7 @@ pub mod error;
pub mod flags;
pub mod layout;

mod alloc;
mod cholesky;
mod eig;
mod eigh;
Expand Down Expand Up @@ -113,6 +114,7 @@ pub use self::svddc::*;
pub use self::triangular::*;
pub use self::tridiagonal::*;

use self::alloc::*;
use cauchy::*;
use std::mem::MaybeUninit;

Expand Down Expand Up @@ -140,61 +142,3 @@ impl Lapack for f32 {}
impl Lapack for f64 {}
impl Lapack for c32 {}
impl Lapack for c64 {}

/// Helper for getting pointer of slice
pub(crate) trait AsPtr: Sized {
type Elem;
fn as_ptr(vec: &[Self]) -> *const Self::Elem;
fn as_mut_ptr(vec: &mut [Self]) -> *mut Self::Elem;
}

macro_rules! impl_as_ptr {
($target:ty, $elem:ty) => {
impl AsPtr for $target {
type Elem = $elem;
fn as_ptr(vec: &[Self]) -> *const Self::Elem {
vec.as_ptr() as *const _
}
fn as_mut_ptr(vec: &mut [Self]) -> *mut Self::Elem {
vec.as_mut_ptr() as *mut _
}
}
};
}
impl_as_ptr!(i32, i32);
impl_as_ptr!(f32, f32);
impl_as_ptr!(f64, f64);
impl_as_ptr!(c32, lapack_sys::__BindgenComplex<f32>);
impl_as_ptr!(c64, lapack_sys::__BindgenComplex<f64>);
impl_as_ptr!(MaybeUninit<i32>, i32);
impl_as_ptr!(MaybeUninit<f32>, f32);
impl_as_ptr!(MaybeUninit<f64>, f64);
impl_as_ptr!(MaybeUninit<c32>, lapack_sys::__BindgenComplex<f32>);
impl_as_ptr!(MaybeUninit<c64>, lapack_sys::__BindgenComplex<f64>);

pub(crate) trait VecAssumeInit {
type Target;
unsafe fn assume_init(self) -> Self::Target;
}

impl<T> VecAssumeInit for Vec<MaybeUninit<T>> {
type Target = Vec<T>;
unsafe fn assume_init(self) -> Self::Target {
// FIXME use Vec::into_raw_parts instead after stablized
// https://doc.rust-lang.org/std/vec/struct.Vec.html#method.into_raw_parts
let mut me = std::mem::ManuallyDrop::new(self);
Vec::from_raw_parts(me.as_mut_ptr() as *mut T, me.len(), me.capacity())
}
}

/// Create a vector without initialization
///
/// Safety
/// ------
/// - Memory is not initialized. Do not read the memory before write.
///
unsafe fn vec_uninit<T: Sized>(n: usize) -> Vec<MaybeUninit<T>> {
let mut v = Vec::with_capacity(n);
v.set_len(n);
v
}
2 changes: 1 addition & 1 deletion lax/src/opnorm.rs
Expand Up @@ -19,7 +19,7 @@ macro_rules! impl_opnorm {
MatrixLayout::C { .. } => t.transpose(),
};
let mut work: Vec<MaybeUninit<Self::Real>> = if matches!(t, NormType::Infinity) {
unsafe { vec_uninit(m as usize) }
vec_uninit(m as usize)
} else {
Vec::new()
};
Expand Down
6 changes: 3 additions & 3 deletions lax/src/qr.rs
Expand Up @@ -25,7 +25,7 @@ macro_rules! impl_qr {
let m = l.lda();
let n = l.len();
let k = m.min(n);
let mut tau = unsafe { vec_uninit(k as usize) };
let mut tau = vec_uninit(k as usize);

// eval work size
let mut info = 0;
Expand Down Expand Up @@ -62,7 +62,7 @@ macro_rules! impl_qr {

// calc
let lwork = work_size[0].to_usize().unwrap();
let mut work: Vec<MaybeUninit<Self>> = unsafe { vec_uninit(lwork) };
let mut work: Vec<MaybeUninit<Self>> = vec_uninit(lwork);
unsafe {
match l {
MatrixLayout::F { .. } => {
Expand Down Expand Up @@ -136,7 +136,7 @@ macro_rules! impl_qr {

// calc
let lwork = work_size[0].to_usize().unwrap();
let mut work: Vec<MaybeUninit<Self>> = unsafe { vec_uninit(lwork) };
let mut work: Vec<MaybeUninit<Self>> = vec_uninit(lwork);
unsafe {
match l {
MatrixLayout::F { .. } => $gqr(
Expand Down
8 changes: 4 additions & 4 deletions lax/src/rcond.rs
Expand Up @@ -17,8 +17,8 @@ macro_rules! impl_rcond_real {
let mut rcond = Self::Real::zero();
let mut info = 0;

let mut work: Vec<MaybeUninit<Self>> = unsafe { vec_uninit(4 * n as usize) };
let mut iwork: Vec<MaybeUninit<i32>> = unsafe { vec_uninit(n as usize) };
let mut work: Vec<MaybeUninit<Self>> = vec_uninit(4 * n as usize);
let mut iwork: Vec<MaybeUninit<i32>> = vec_uninit(n as usize);
let norm_type = match l {
MatrixLayout::C { .. } => NormType::Infinity,
MatrixLayout::F { .. } => NormType::One,
Expand Down Expand Up @@ -54,8 +54,8 @@ macro_rules! impl_rcond_complex {
let (n, _) = l.size();
let mut rcond = Self::Real::zero();
let mut info = 0;
let mut work: Vec<MaybeUninit<Self>> = unsafe { vec_uninit(2 * n as usize) };
let mut rwork: Vec<MaybeUninit<Self::Real>> = unsafe { vec_uninit(2 * n as usize) };
let mut work: Vec<MaybeUninit<Self>> = vec_uninit(2 * n as usize);
let mut rwork: Vec<MaybeUninit<Self::Real>> = vec_uninit(2 * n as usize);
let norm_type = match l {
MatrixLayout::C { .. } => NormType::Infinity,
MatrixLayout::F { .. } => NormType::One,
Expand Down
4 changes: 2 additions & 2 deletions lax/src/solve.rs
Expand Up @@ -75,7 +75,7 @@ macro_rules! impl_solve {
return Ok(Vec::new());
}
let k = ::std::cmp::min(row, col);
let mut ipiv = unsafe { vec_uninit(k as usize) };
let mut ipiv = vec_uninit(k as usize);
let mut info = 0;
unsafe {
$getrf(
Expand Down Expand Up @@ -117,7 +117,7 @@ macro_rules! impl_solve {

// actual
let lwork = work_size[0].to_usize().unwrap();
let mut work: Vec<MaybeUninit<Self>> = unsafe { vec_uninit(lwork) };
let mut work: Vec<MaybeUninit<Self>> = vec_uninit(lwork);
unsafe {
$getri(
&l.len(),
Expand Down
6 changes: 3 additions & 3 deletions lax/src/solveh.rs
Expand Up @@ -58,7 +58,7 @@ macro_rules! impl_solveh {
impl Solveh_ for $scalar {
fn bk(l: MatrixLayout, uplo: UPLO, a: &mut [Self]) -> Result<Pivot> {
let (n, _) = l.size();
let mut ipiv = unsafe { vec_uninit(n as usize) };
let mut ipiv = vec_uninit(n as usize);
if n == 0 {
return Ok(Vec::new());
}
Expand All @@ -82,7 +82,7 @@ macro_rules! impl_solveh {

// actual
let lwork = work_size[0].to_usize().unwrap();
let mut work: Vec<MaybeUninit<Self>> = unsafe { vec_uninit(lwork) };
let mut work: Vec<MaybeUninit<Self>> = vec_uninit(lwork);
unsafe {
$trf(
uplo.as_ptr(),
Expand All @@ -103,7 +103,7 @@ macro_rules! impl_solveh {
fn invh(l: MatrixLayout, uplo: UPLO, a: &mut [Self], ipiv: &Pivot) -> Result<()> {
let (n, _) = l.size();
let mut info = 0;
let mut work: Vec<MaybeUninit<Self>> = unsafe { vec_uninit(n as usize) };
let mut work: Vec<MaybeUninit<Self>> = vec_uninit(n as usize);
unsafe {
$tri(
uplo.as_ptr(),
Expand Down