extern crate libc;
use self::libc::{c_double, c_int, c_uint};
use crate::array::Array;
use crate::defines::{AfError, MatProp, NormType};
use crate::error::HANDLE_ERROR;
use crate::util::{to_u32, AfArray, MutAfArray, MutDouble};
use crate::util::{FloatingPoint, HasAfEnum};
#[allow(dead_code)]
extern "C" {
fn af_svd(u: MutAfArray, s: MutAfArray, vt: MutAfArray, input: AfArray) -> c_int;
fn af_svd_inplace(u: MutAfArray, s: MutAfArray, vt: MutAfArray, input: AfArray) -> c_int;
fn af_lu(lower: MutAfArray, upper: MutAfArray, pivot: MutAfArray, input: AfArray) -> c_int;
fn af_lu_inplace(pivot: MutAfArray, input: AfArray, is_lapack_piv: c_int) -> c_int;
fn af_qr(q: MutAfArray, r: MutAfArray, tau: MutAfArray, input: AfArray) -> c_int;
fn af_qr_inplace(tau: MutAfArray, input: AfArray) -> c_int;
fn af_cholesky(out: MutAfArray, info: *mut c_int, input: AfArray, is_upper: c_int) -> c_int;
fn af_cholesky_inplace(info: *mut c_int, input: AfArray, is_upper: c_int) -> c_int;
fn af_solve(x: MutAfArray, a: AfArray, b: AfArray, options: c_uint) -> c_int;
fn af_solve_lu(x: MutAfArray, a: AfArray, piv: AfArray, b: AfArray, options: c_uint) -> c_int;
fn af_inverse(out: MutAfArray, input: AfArray, options: c_uint) -> c_int;
fn af_rank(rank: *mut c_uint, input: AfArray, tol: c_double) -> c_int;
fn af_det(det_real: MutDouble, det_imag: MutDouble, input: AfArray) -> c_int;
fn af_norm(out: MutDouble, input: AfArray, ntype: c_uint, p: c_double, q: c_double) -> c_int;
fn af_is_lapack_available(out: *mut c_int) -> c_int;
}
#[allow(unused_mut)]
pub fn svd<T>(input: &Array<T>) -> (Array<T>, Array<T::BaseType>, Array<T>)
where
T: HasAfEnum + FloatingPoint,
T::BaseType: HasAfEnum,
{
let mut u: i64 = 0;
let mut s: i64 = 0;
let mut vt: i64 = 0;
unsafe {
let err_val = af_svd(
&mut u as MutAfArray,
&mut s as MutAfArray,
&mut vt as MutAfArray,
input.get() as AfArray,
);
HANDLE_ERROR(AfError::from(err_val));
}
(u.into(), s.into(), vt.into())
}
#[allow(unused_mut)]
pub fn svd_inplace<T>(input: &mut Array<T>) -> (Array<T>, Array<T::BaseType>, Array<T>)
where
T: HasAfEnum + FloatingPoint,
T::BaseType: HasAfEnum,
{
let mut u: i64 = 0;
let mut s: i64 = 0;
let mut vt: i64 = 0;
unsafe {
let err_val = af_svd_inplace(
&mut u as MutAfArray,
&mut s as MutAfArray,
&mut vt as MutAfArray,
input.get() as AfArray,
);
HANDLE_ERROR(AfError::from(err_val));
}
(u.into(), s.into(), vt.into())
}
#[allow(unused_mut)]
pub fn lu<T>(input: &Array<T>) -> (Array<T>, Array<T>, Array<i32>)
where
T: HasAfEnum + FloatingPoint,
{
let mut lower: i64 = 0;
let mut upper: i64 = 0;
let mut pivot: i64 = 0;
unsafe {
let err_val = af_lu(
&mut lower as MutAfArray,
&mut upper as MutAfArray,
&mut pivot as MutAfArray,
input.get() as AfArray,
);
HANDLE_ERROR(AfError::from(err_val));
}
(lower.into(), upper.into(), pivot.into())
}
#[allow(unused_mut)]
pub fn lu_inplace<T>(input: &mut Array<T>, is_lapack_piv: bool) -> Array<i32>
where
T: HasAfEnum + FloatingPoint,
{
let mut pivot: i64 = 0;
unsafe {
let err_val = af_lu_inplace(
&mut pivot as MutAfArray,
input.get() as AfArray,
is_lapack_piv as c_int,
);
HANDLE_ERROR(AfError::from(err_val));
}
pivot.into()
}
#[allow(unused_mut)]
pub fn qr<T>(input: &Array<T>) -> (Array<T>, Array<T>, Array<T>)
where
T: HasAfEnum + FloatingPoint,
{
let mut q: i64 = 0;
let mut r: i64 = 0;
let mut tau: i64 = 0;
unsafe {
let err_val = af_qr(
&mut q as MutAfArray,
&mut r as MutAfArray,
&mut tau as MutAfArray,
input.get() as AfArray,
);
HANDLE_ERROR(AfError::from(err_val));
}
(q.into(), r.into(), tau.into())
}
#[allow(unused_mut)]
pub fn qr_inplace<T>(input: &mut Array<T>) -> Array<T>
where
T: HasAfEnum + FloatingPoint,
{
let mut tau: i64 = 0;
unsafe {
let err_val = af_qr_inplace(&mut tau as MutAfArray, input.get() as AfArray);
HANDLE_ERROR(AfError::from(err_val));
}
tau.into()
}
#[allow(unused_mut)]
pub fn cholesky<T>(input: &Array<T>, is_upper: bool) -> (Array<T>, i32)
where
T: HasAfEnum + FloatingPoint,
{
let mut temp: i64 = 0;
let mut info: i32 = 0;
unsafe {
let err_val = af_cholesky(
&mut temp as MutAfArray,
&mut info as *mut c_int,
input.get() as AfArray,
is_upper as c_int,
);
HANDLE_ERROR(AfError::from(err_val));
}
(temp.into(), info)
}
#[allow(unused_mut)]
pub fn cholesky_inplace<T>(input: &mut Array<T>, is_upper: bool) -> i32
where
T: HasAfEnum + FloatingPoint,
{
let mut info: i32 = 0;
unsafe {
let err_val = af_cholesky_inplace(
&mut info as *mut c_int,
input.get() as AfArray,
is_upper as c_int,
);
HANDLE_ERROR(AfError::from(err_val));
}
info
}
#[allow(unused_mut)]
pub fn solve<T>(a: &Array<T>, b: &Array<T>, options: MatProp) -> Array<T>
where
T: HasAfEnum + FloatingPoint,
{
let mut temp: i64 = 0;
unsafe {
let err_val = af_solve(
&mut temp as MutAfArray,
a.get() as AfArray,
b.get() as AfArray,
to_u32(options) as c_uint,
);
HANDLE_ERROR(AfError::from(err_val));
}
temp.into()
}
#[allow(unused_mut)]
pub fn solve_lu<T>(a: &Array<T>, piv: &Array<i32>, b: &Array<T>, options: MatProp) -> Array<T>
where
T: HasAfEnum + FloatingPoint,
{
let mut temp: i64 = 0;
unsafe {
let err_val = af_solve_lu(
&mut temp as MutAfArray,
a.get() as AfArray,
piv.get() as AfArray,
b.get() as AfArray,
to_u32(options) as c_uint,
);
HANDLE_ERROR(AfError::from(err_val));
}
temp.into()
}
#[allow(unused_mut)]
pub fn inverse<T>(input: &Array<T>, options: MatProp) -> Array<T>
where
T: HasAfEnum + FloatingPoint,
{
let mut temp: i64 = 0;
unsafe {
let err_val = af_inverse(
&mut temp as MutAfArray,
input.get() as AfArray,
to_u32(options) as c_uint,
);
HANDLE_ERROR(AfError::from(err_val));
}
temp.into()
}
#[allow(unused_mut)]
pub fn rank<T>(input: &Array<T>, tol: f64) -> u32
where
T: HasAfEnum + FloatingPoint,
{
let mut temp: u32 = 0;
unsafe {
let err_val = af_rank(
&mut temp as *mut c_uint,
input.get() as AfArray,
tol as c_double,
);
HANDLE_ERROR(AfError::from(err_val));
}
temp
}
#[allow(unused_mut)]
pub fn det<T>(input: &Array<T>) -> (f64, f64)
where
T: HasAfEnum + FloatingPoint,
{
let mut real: f64 = 0.0;
let mut imag: f64 = 0.0;
unsafe {
let err_val = af_det(
&mut real as MutDouble,
&mut imag as MutDouble,
input.get() as AfArray,
);
HANDLE_ERROR(AfError::from(err_val));
}
(real, imag)
}
#[allow(unused_mut)]
pub fn norm<T>(input: &Array<T>, ntype: NormType, p: f64, q: f64) -> f64
where
T: HasAfEnum + FloatingPoint,
{
let mut out: f64 = 0.0;
unsafe {
let err_val = af_norm(
&mut out as MutDouble,
input.get() as AfArray,
ntype as c_uint,
p as c_double,
q as c_double,
);
HANDLE_ERROR(AfError::from(err_val));
}
out
}
pub fn is_lapack_available() -> bool {
let mut temp: i32 = 0;
unsafe {
af_is_lapack_available(&mut temp as *mut c_int);
}
temp > 0 }