forked from M-Labs/nac3
standalone: move linalg functions to demo
This commit is contained in:
parent
4bb00c52e3
commit
540b35ec84
|
@ -553,7 +553,7 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linalg_externfns"
|
name = "linalg"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cslice",
|
"cslice",
|
||||||
|
@ -688,7 +688,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"inkwell",
|
"inkwell",
|
||||||
"linalg_externfns",
|
"linalg",
|
||||||
"nac3core",
|
"nac3core",
|
||||||
"nac3parser",
|
"nac3parser",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
|
|
|
@ -4,7 +4,6 @@ members = [
|
||||||
"nac3ast",
|
"nac3ast",
|
||||||
"nac3parser",
|
"nac3parser",
|
||||||
"nac3core",
|
"nac3core",
|
||||||
"nac3standalone/linalg_externfns",
|
|
||||||
"nac3standalone",
|
"nac3standalone",
|
||||||
"nac3artiq",
|
"nac3artiq",
|
||||||
"runkernel",
|
"runkernel",
|
||||||
|
|
|
@ -8,7 +8,7 @@ edition = "2021"
|
||||||
parking_lot = "0.12"
|
parking_lot = "0.12"
|
||||||
nac3parser = { path = "../nac3parser" }
|
nac3parser = { path = "../nac3parser" }
|
||||||
nac3core = { path = "../nac3core" }
|
nac3core = { path = "../nac3core" }
|
||||||
linalg_externfns = { path = "./linalg_externfns" }
|
linalg = { path = "./demo/linalg" }
|
||||||
|
|
||||||
[dependencies.clap]
|
[dependencies.clap]
|
||||||
version = "4.5"
|
version = "4.5"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
name = "linalg_externfns"
|
name = "linalg"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
|
@ -1,36 +1,27 @@
|
||||||
/// Uses `nalgebra` crate to invoke `np_linalg` and `sp_linalg` functions
|
// Uses `nalgebra` crate to invoke `np_linalg` and `sp_linalg` functions
|
||||||
/// When converting between `nalgebra::Matrix` and `NDArray` following considerations are necessary
|
// When converting between `nalgebra::Matrix` and `NDArray` following considerations are necessary
|
||||||
///
|
//
|
||||||
/// * Both `nalgebra::Matrix` and `NDArray` require their content to be stored in row-major order
|
// * Both `nalgebra::Matrix` and `NDArray` require their content to be stored in row-major order
|
||||||
/// * `NDArray` data pointer can be directly read and converted to `nalgebra::Matrix` (row and column number must be known)
|
// * `NDArray` data pointer can be directly read and converted to `nalgebra::Matrix` (row and column number must be known)
|
||||||
/// * `nalgebra::Matrix::as_slice` returns the content of matrix in column-major order and initial data needs to be transposed before storing it in `NDArray` data pointer
|
// * `nalgebra::Matrix::as_slice` returns the content of matrix in column-major order and initial data needs to be transposed before storing it in `NDArray` data pointer
|
||||||
mod runtime_exception;
|
|
||||||
use core::slice;
|
use core::slice;
|
||||||
use nalgebra::DMatrix;
|
use nalgebra::DMatrix;
|
||||||
|
|
||||||
macro_rules! raise_exn {
|
fn report_error(
|
||||||
($name:expr, $fn_name:expr, $message:expr, $param0:expr, $param1:expr, $param2:expr) => {{
|
error_name: &str,
|
||||||
use cslice::AsCSlice;
|
fn_name: &str,
|
||||||
let name_id = $crate::runtime_exception::get_exception_id($name);
|
file_name: &str,
|
||||||
let exn = $crate::runtime_exception::Exception {
|
line_num: u32,
|
||||||
id: name_id,
|
col_num: u32,
|
||||||
file: file!().as_c_slice(),
|
err_msg: &str,
|
||||||
line: line!(),
|
) -> ! {
|
||||||
column: column!(),
|
panic!(
|
||||||
// https://github.com/rust-lang/rfcs/pull/1719
|
"Exception {} from {} in {}:{}:{}, message: {}",
|
||||||
function: $fn_name.as_c_slice(),
|
error_name, fn_name, file_name, line_num, col_num, err_msg
|
||||||
message: $message.as_c_slice(),
|
);
|
||||||
param: [$param0, $param1, $param2],
|
|
||||||
};
|
|
||||||
#[allow(unused_unsafe)]
|
|
||||||
unsafe {
|
|
||||||
$crate::runtime_exception::raise(&exn)
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
($name:expr, $fn_name:expr, $message:expr) => {{
|
|
||||||
raise_exn!($name, $fn_name, $message, 0, 0, 0)
|
|
||||||
}};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct InputMatrix {
|
pub struct InputMatrix {
|
||||||
pub ndims: usize,
|
pub ndims: usize,
|
||||||
pub dims: *const usize,
|
pub dims: *const usize,
|
||||||
|
@ -56,7 +47,7 @@ pub unsafe extern "C" fn np_dot(mat1: *mut InputMatrix, mat2: *mut InputMatrix)
|
||||||
"expected 1D Vector Input, but received {}D and {}D input",
|
"expected 1D Vector Input, but received {}D and {}D input",
|
||||||
mat1.ndims, mat2.ndims
|
mat1.ndims, mat2.ndims
|
||||||
);
|
);
|
||||||
raise_exn!("ValueError", "np_dot", err_msg);
|
report_error("ValueError", "np_dot", file!(), line!(), column!(), &err_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
let dim1 = (*mat1).get_dims();
|
let dim1 = (*mat1).get_dims();
|
||||||
|
@ -64,7 +55,7 @@ pub unsafe extern "C" fn np_dot(mat1: *mut InputMatrix, mat2: *mut InputMatrix)
|
||||||
|
|
||||||
if dim1[0] != dim2[0] {
|
if dim1[0] != dim2[0] {
|
||||||
let err_msg = format!("shapes ({},) and ({},) not aligned", dim1[0], dim2[0]);
|
let err_msg = format!("shapes ({},) and ({},) not aligned", dim1[0], dim2[0]);
|
||||||
raise_exn!("ValueError", "np_dot", err_msg);
|
report_error("ValueError", "np_dot", file!(), line!(), column!(), &err_msg);
|
||||||
}
|
}
|
||||||
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0]) };
|
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0]) };
|
||||||
let data_slice2 = unsafe { slice::from_raw_parts_mut(mat2.data, dim2[0]) };
|
let data_slice2 = unsafe { slice::from_raw_parts_mut(mat2.data, dim2[0]) };
|
||||||
|
@ -93,7 +84,7 @@ pub unsafe extern "C" fn np_linalg_matmul(
|
||||||
"expected 2D Vector Input, but received {}D and {}D input",
|
"expected 2D Vector Input, but received {}D and {}D input",
|
||||||
mat1.ndims, mat2.ndims
|
mat1.ndims, mat2.ndims
|
||||||
);
|
);
|
||||||
raise_exn!("ValueError", "np_matmul", err_msg);
|
report_error("ValueError", "np_matmul", file!(), line!(), column!(), &err_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
let dim1 = (*mat1).get_dims();
|
let dim1 = (*mat1).get_dims();
|
||||||
|
@ -104,7 +95,7 @@ pub unsafe extern "C" fn np_linalg_matmul(
|
||||||
"shapes ({},{}) and ({},{}) not aligned: {} (dim 1) != {} (dim 0)",
|
"shapes ({},{}) and ({},{}) not aligned: {} (dim 1) != {} (dim 0)",
|
||||||
dim1[0], dim1[1], dim2[0], dim2[1], dim1[1], dim2[0]
|
dim1[0], dim1[1], dim2[0], dim2[1], dim1[1], dim2[0]
|
||||||
);
|
);
|
||||||
raise_exn!("ValueError", "np_matmul", err_msg);
|
report_error("ValueError", "np_matmul", file!(), line!(), column!(), &err_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
let outdim = out.get_dims();
|
let outdim = out.get_dims();
|
||||||
|
@ -130,14 +121,14 @@ pub unsafe extern "C" fn np_linalg_cholesky(mat1: *mut InputMatrix, out: *mut In
|
||||||
|
|
||||||
if mat1.ndims != 2 {
|
if mat1.ndims != 2 {
|
||||||
let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims);
|
let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims);
|
||||||
raise_exn!("ValueError", "np_linalg_cholesky", err_msg);
|
report_error("ValueError", "np_linalg_cholesky", file!(), line!(), column!(), &err_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
let dim1 = (*mat1).get_dims();
|
let dim1 = (*mat1).get_dims();
|
||||||
if dim1[0] != dim1[1] {
|
if dim1[0] != dim1[1] {
|
||||||
let err_msg =
|
let err_msg =
|
||||||
format!("last 2 dimensions of the array must be square: {0} != {1}", dim1[0], dim1[1]);
|
format!("last 2 dimensions of the array must be square: {0} != {1}", dim1[0], dim1[1]);
|
||||||
raise_exn!("LinAlgError", "np_linalg_cholesky", err_msg);
|
report_error("LinAlgError", "np_linalg_cholesky", file!(), line!(), column!(), &err_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
let outdim = out.get_dims();
|
let outdim = out.get_dims();
|
||||||
|
@ -151,7 +142,14 @@ pub unsafe extern "C" fn np_linalg_cholesky(mat1: *mut InputMatrix, out: *mut In
|
||||||
out_slice.copy_from_slice(res.unpack().transpose().as_slice());
|
out_slice.copy_from_slice(res.unpack().transpose().as_slice());
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
raise_exn!("LinAlgError", "np_linalg_cholesky", "Matrix is not positive definite");
|
report_error(
|
||||||
|
"LinAlgError",
|
||||||
|
"np_linalg_cholesky",
|
||||||
|
file!(),
|
||||||
|
line!(),
|
||||||
|
column!(),
|
||||||
|
"Matrix is not positive definite",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -171,7 +169,7 @@ pub unsafe extern "C" fn np_linalg_qr(
|
||||||
|
|
||||||
if mat1.ndims != 2 {
|
if mat1.ndims != 2 {
|
||||||
let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims);
|
let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims);
|
||||||
raise_exn!("ValueError", "np_linalg_cholesky", err_msg);
|
report_error("ValueError", "np_linalg_cholesky", file!(), line!(), column!(), &err_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
let dim1 = (*mat1).get_dims();
|
let dim1 = (*mat1).get_dims();
|
||||||
|
@ -210,7 +208,7 @@ pub unsafe extern "C" fn np_linalg_svd(
|
||||||
|
|
||||||
if mat1.ndims != 2 {
|
if mat1.ndims != 2 {
|
||||||
let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims);
|
let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims);
|
||||||
raise_exn!("ValueError", "np_linalg_svd", err_msg);
|
report_error("ValueError", "np_linalg_svd", file!(), line!(), column!(), &err_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
let dim1 = (*mat1).get_dims();
|
let dim1 = (*mat1).get_dims();
|
||||||
|
@ -241,14 +239,14 @@ pub unsafe extern "C" fn np_linalg_inv(mat1: *mut InputMatrix, out: *mut InputMa
|
||||||
|
|
||||||
if mat1.ndims != 2 {
|
if mat1.ndims != 2 {
|
||||||
let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims);
|
let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims);
|
||||||
raise_exn!("ValueError", "np_linalg_inv", err_msg);
|
report_error("ValueError", "np_linalg_inv", file!(), line!(), column!(), &err_msg);
|
||||||
}
|
}
|
||||||
let dim1 = (*mat1).get_dims();
|
let dim1 = (*mat1).get_dims();
|
||||||
|
|
||||||
if dim1[0] != dim1[1] {
|
if dim1[0] != dim1[1] {
|
||||||
let err_msg =
|
let err_msg =
|
||||||
format!("last 2 dimensions of the array must be square: {0} != {1}", dim1[0], dim1[1]);
|
format!("last 2 dimensions of the array must be square: {0} != {1}", dim1[0], dim1[1]);
|
||||||
raise_exn!("LinAlgError", "np_linalg_inv", err_msg);
|
report_error("LinAlgError", "np_linalg_inv", file!(), line!(), column!(), &err_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
let outdim = out.get_dims();
|
let outdim = out.get_dims();
|
||||||
|
@ -257,7 +255,14 @@ pub unsafe extern "C" fn np_linalg_inv(mat1: *mut InputMatrix, out: *mut InputMa
|
||||||
|
|
||||||
let matrix = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
let matrix = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
||||||
if !matrix.is_invertible() {
|
if !matrix.is_invertible() {
|
||||||
raise_exn!("LinAlgError", "np_linalg_inv", "no inverse for Singular Matrix");
|
report_error(
|
||||||
|
"LinAlgError",
|
||||||
|
"np_linalg_inv",
|
||||||
|
file!(),
|
||||||
|
line!(),
|
||||||
|
column!(),
|
||||||
|
"no inverse for Singular Matrix",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
let inv = matrix.try_inverse().unwrap();
|
let inv = matrix.try_inverse().unwrap();
|
||||||
out_slice.copy_from_slice(inv.transpose().as_slice());
|
out_slice.copy_from_slice(inv.transpose().as_slice());
|
||||||
|
@ -273,7 +278,7 @@ pub unsafe extern "C" fn np_linalg_pinv(mat1: *mut InputMatrix, out: *mut InputM
|
||||||
|
|
||||||
if mat1.ndims != 2 {
|
if mat1.ndims != 2 {
|
||||||
let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims);
|
let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims);
|
||||||
raise_exn!("ValueError", "np_linalg_pinv", err_msg);
|
report_error("ValueError", "np_linalg_pinv", file!(), line!(), column!(), &err_msg);
|
||||||
}
|
}
|
||||||
let dim1 = (*mat1).get_dims();
|
let dim1 = (*mat1).get_dims();
|
||||||
let outdim = out.get_dims();
|
let outdim = out.get_dims();
|
||||||
|
@ -288,8 +293,8 @@ pub unsafe extern "C" fn np_linalg_pinv(mat1: *mut InputMatrix, out: *mut InputM
|
||||||
Ok(m) => {
|
Ok(m) => {
|
||||||
out_slice.copy_from_slice(m.transpose().as_slice());
|
out_slice.copy_from_slice(m.transpose().as_slice());
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(err_msg) => {
|
||||||
raise_exn!("LinAlgError", "np_linalg_pinv", e);
|
report_error("LinAlgError", "np_linalg_pinv", file!(), line!(), column!(), err_msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -309,7 +314,7 @@ pub unsafe extern "C" fn sp_linalg_lu(
|
||||||
|
|
||||||
if mat1.ndims != 2 {
|
if mat1.ndims != 2 {
|
||||||
let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims);
|
let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims);
|
||||||
raise_exn!("ValueError", "sp_linalg_lu", err_msg);
|
report_error("ValueError", "sp_linalg_lu", file!(), line!(), column!(), &err_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
let dim1 = (*mat1).get_dims();
|
let dim1 = (*mat1).get_dims();
|
||||||
|
@ -342,7 +347,7 @@ pub unsafe extern "C" fn sp_linalg_schur(
|
||||||
|
|
||||||
if mat1.ndims != 2 {
|
if mat1.ndims != 2 {
|
||||||
let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims);
|
let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims);
|
||||||
raise_exn!("ValueError", "sp_linalg_schur", err_msg);
|
report_error("ValueError", "sp_linalg_schur", file!(), line!(), column!(), &err_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
let dim1 = (*mat1).get_dims();
|
let dim1 = (*mat1).get_dims();
|
||||||
|
@ -350,7 +355,7 @@ pub unsafe extern "C" fn sp_linalg_schur(
|
||||||
if dim1[0] != dim1[1] {
|
if dim1[0] != dim1[1] {
|
||||||
let err_msg =
|
let err_msg =
|
||||||
format!("last 2 dimensions of the array must be square: {0} != {1}", dim1[0], dim1[1]);
|
format!("last 2 dimensions of the array must be square: {0} != {1}", dim1[0], dim1[1]);
|
||||||
raise_exn!("LinAlgError", "np_linalg_schur", err_msg);
|
report_error("LinAlgError", "np_linalg_schur", file!(), line!(), column!(), &err_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
let out_t_dim = (*out_t).get_dims();
|
let out_t_dim = (*out_t).get_dims();
|
||||||
|
@ -382,7 +387,7 @@ pub unsafe extern "C" fn sp_linalg_hessenberg(
|
||||||
|
|
||||||
if mat1.ndims != 2 {
|
if mat1.ndims != 2 {
|
||||||
let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims);
|
let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims);
|
||||||
raise_exn!("ValueError", "sp_linalg_hessenberg", err_msg);
|
report_error("ValueError", "sp_linalg_hessenberg", file!(), line!(), column!(), &err_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
let dim1 = (*mat1).get_dims();
|
let dim1 = (*mat1).get_dims();
|
||||||
|
@ -390,7 +395,7 @@ pub unsafe extern "C" fn sp_linalg_hessenberg(
|
||||||
if dim1[0] != dim1[1] {
|
if dim1[0] != dim1[1] {
|
||||||
let err_msg =
|
let err_msg =
|
||||||
format!("last 2 dimensions of the array must be square: {} != {}", dim1[0], dim1[1]);
|
format!("last 2 dimensions of the array must be square: {} != {}", dim1[0], dim1[1]);
|
||||||
raise_exn!("LinAlgError", "sp_linalg_hessenberg", err_msg);
|
report_error("LinAlgError", "sp_linalg_hessenberg", file!(), line!(), column!(), &err_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
let out_h_dim = (*out_h).get_dims();
|
let out_h_dim = (*out_h).get_dims();
|
|
@ -1,66 +0,0 @@
|
||||||
#![allow(non_camel_case_types)]
|
|
||||||
#![allow(unused)]
|
|
||||||
|
|
||||||
// ARTIQ Exception struct declaration
|
|
||||||
use cslice::CSlice;
|
|
||||||
|
|
||||||
// Note: CSlice within an exception may not be actual cslice, they may be strings that exist only
|
|
||||||
// in the host. If the length == usize:MAX, the pointer is actually a string key in the host.
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Exception<'a> {
|
|
||||||
pub id: u32,
|
|
||||||
pub file: CSlice<'a, u8>,
|
|
||||||
pub line: u32,
|
|
||||||
pub column: u32,
|
|
||||||
pub function: CSlice<'a, u8>,
|
|
||||||
pub message: CSlice<'a, u8>,
|
|
||||||
pub param: [i64; 3],
|
|
||||||
}
|
|
||||||
|
|
||||||
fn str_err(_: core::str::Utf8Error) -> core::fmt::Error {
|
|
||||||
core::fmt::Error
|
|
||||||
}
|
|
||||||
|
|
||||||
fn exception_str<'a>(s: &'a CSlice<'a, u8>) -> Result<&'a str, core::str::Utf8Error> {
|
|
||||||
if s.len() == usize::MAX {
|
|
||||||
Ok("<host string>")
|
|
||||||
} else {
|
|
||||||
core::str::from_utf8(s.as_ref())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn raise(exception: *const Exception) -> ! {
|
|
||||||
let e = &*exception;
|
|
||||||
let f1 = exception_str(&e.function).map_err(str_err).unwrap();
|
|
||||||
let f2 = exception_str(&e.file).map_err(str_err).unwrap();
|
|
||||||
let f3 = exception_str(&e.message).map_err(str_err).unwrap();
|
|
||||||
|
|
||||||
panic!("Exception {} from {} in {}:{}:{}, message: {}", e.id, f1, f2, e.line, e.column, f3);
|
|
||||||
}
|
|
||||||
|
|
||||||
static EXCEPTION_ID_LOOKUP: [(&str, u32); 14] = [
|
|
||||||
("RuntimeError", 0),
|
|
||||||
("RTIOUnderflow", 1),
|
|
||||||
("RTIOOverflow", 2),
|
|
||||||
("RTIODestinationUnreachable", 3),
|
|
||||||
("DMAError", 4),
|
|
||||||
("I2CError", 5),
|
|
||||||
("CacheError", 6),
|
|
||||||
("SPIError", 7),
|
|
||||||
("ZeroDivisionError", 8),
|
|
||||||
("IndexError", 9),
|
|
||||||
("UnwrapNoneError", 10),
|
|
||||||
("Value", 11),
|
|
||||||
("ValueError", 12),
|
|
||||||
("LinAlgError", 13),
|
|
||||||
];
|
|
||||||
|
|
||||||
pub fn get_exception_id(name: &str) -> u32 {
|
|
||||||
for (n, id) in EXCEPTION_ID_LOOKUP.iter() {
|
|
||||||
if *n == name {
|
|
||||||
return *id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unimplemented!("unallocated internal exception id")
|
|
||||||
}
|
|
Loading…
Reference in New Issue