Compare commits
2 Commits
4a6845dac6
...
1c72698d02
Author | SHA1 | Date | |
---|---|---|---|
1c72698d02 | |||
54f883f0a5 |
@ -3,7 +3,9 @@ use inkwell::values::{BasicValue, BasicValueEnum, PointerValue};
|
|||||||
use inkwell::{FloatPredicate, IntPredicate, OptimizationLevel};
|
use inkwell::{FloatPredicate, IntPredicate, OptimizationLevel};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use crate::codegen::classes::{NDArrayValue, ProxyValue, UntypedArrayLikeAccessor};
|
use crate::codegen::classes::{
|
||||||
|
NDArrayValue, ProxyValue, UntypedArrayLikeAccessor, UntypedArrayLikeMutator,
|
||||||
|
};
|
||||||
use crate::codegen::numpy::ndarray_elementwise_unaryop_impl;
|
use crate::codegen::numpy::ndarray_elementwise_unaryop_impl;
|
||||||
use crate::codegen::stmt::gen_for_callback_incrementing;
|
use crate::codegen::stmt::gen_for_callback_incrementing;
|
||||||
use crate::codegen::{extern_fns, irrt, llvm_intrinsics, numpy, CodeGenContext, CodeGenerator};
|
use crate::codegen::{extern_fns, irrt, llvm_intrinsics, numpy, CodeGenContext, CodeGenerator};
|
||||||
@ -1865,34 +1867,6 @@ fn build_output_struct<'ctx>(
|
|||||||
out_ptr
|
out_ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invokes the `np_dot` linalg function
|
|
||||||
pub fn call_np_dot<'ctx, G: CodeGenerator + ?Sized>(
|
|
||||||
generator: &mut G,
|
|
||||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
|
||||||
x1: (Type, BasicValueEnum<'ctx>),
|
|
||||||
x2: (Type, BasicValueEnum<'ctx>),
|
|
||||||
) -> Result<BasicValueEnum<'ctx>, String> {
|
|
||||||
const FN_NAME: &str = "np_dot";
|
|
||||||
let (x1_ty, x1) = x1;
|
|
||||||
let (x2_ty, x2) = x2;
|
|
||||||
|
|
||||||
if let (BasicValueEnum::PointerValue(_), BasicValueEnum::PointerValue(_)) = (x1, x2) {
|
|
||||||
let (n1_elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, x1_ty);
|
|
||||||
let n1_elem_ty = ctx.get_llvm_type(generator, n1_elem_ty);
|
|
||||||
let (n2_elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, x2_ty);
|
|
||||||
let n2_elem_ty = ctx.get_llvm_type(generator, n2_elem_ty);
|
|
||||||
|
|
||||||
let (BasicTypeEnum::FloatType(_), BasicTypeEnum::FloatType(_)) = (n1_elem_ty, n2_elem_ty)
|
|
||||||
else {
|
|
||||||
unsupported_type(ctx, FN_NAME, &[x1_ty, x2_ty]);
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(extern_fns::call_np_dot(ctx, x1, x2, None).into())
|
|
||||||
} else {
|
|
||||||
unsupported_type(ctx, FN_NAME, &[x1_ty, x2_ty])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Invokes the `np_linalg_matmul` linalg function
|
/// Invokes the `np_linalg_matmul` linalg function
|
||||||
pub fn call_np_linalg_matmul<'ctx, G: CodeGenerator + ?Sized>(
|
pub fn call_np_linalg_matmul<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
@ -2224,6 +2198,104 @@ pub fn call_sp_linalg_lu<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Invokes the `np_linalg_matrix_power` linalg function
|
||||||
|
pub fn call_np_linalg_matrix_power<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
x1: (Type, BasicValueEnum<'ctx>),
|
||||||
|
x2: (Type, BasicValueEnum<'ctx>),
|
||||||
|
) -> Result<BasicValueEnum<'ctx>, String> {
|
||||||
|
const FN_NAME: &str = "np_linalg_matrix_power";
|
||||||
|
let (x1_ty, x1) = x1;
|
||||||
|
let (x2_ty, x2) = x2;
|
||||||
|
let x2 = call_float(generator, ctx, (x2_ty, x2)).unwrap();
|
||||||
|
|
||||||
|
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||||
|
if let (BasicValueEnum::PointerValue(n1), BasicValueEnum::FloatValue(n2)) = (x1, x2) {
|
||||||
|
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, x1_ty);
|
||||||
|
let n1_elem_ty = ctx.get_llvm_type(generator, elem_ty);
|
||||||
|
|
||||||
|
let BasicTypeEnum::FloatType(_) = n1_elem_ty else {
|
||||||
|
unsupported_type(ctx, FN_NAME, &[x1_ty, x2_ty]);
|
||||||
|
};
|
||||||
|
|
||||||
|
let n1 = NDArrayValue::from_ptr_val(n1, llvm_usize, None);
|
||||||
|
// Changing second parameter to a `NDArray` for uniformity in function call
|
||||||
|
let n2_array = numpy::create_ndarray_const_shape(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
elem_ty,
|
||||||
|
&[llvm_usize.const_int(1, false)],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
unsafe {
|
||||||
|
n2_array.data().set_unchecked(
|
||||||
|
ctx,
|
||||||
|
generator,
|
||||||
|
&llvm_usize.const_zero(),
|
||||||
|
n2.as_basic_value_enum(),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
let n2_array = n2_array.as_base_value().as_basic_value_enum();
|
||||||
|
|
||||||
|
let outdim0 = unsafe {
|
||||||
|
n1.dim_sizes()
|
||||||
|
.get_unchecked(ctx, generator, &llvm_usize.const_zero(), None)
|
||||||
|
.into_int_value()
|
||||||
|
};
|
||||||
|
let outdim1 = unsafe {
|
||||||
|
n1.dim_sizes()
|
||||||
|
.get_unchecked(ctx, generator, &llvm_usize.const_int(1, false), None)
|
||||||
|
.into_int_value()
|
||||||
|
};
|
||||||
|
|
||||||
|
let out = numpy::create_ndarray_const_shape(generator, ctx, elem_ty, &[outdim0, outdim1])
|
||||||
|
.unwrap()
|
||||||
|
.as_base_value()
|
||||||
|
.as_basic_value_enum();
|
||||||
|
|
||||||
|
extern_fns::call_np_linalg_matrix_power(ctx, x1, n2_array, out, None);
|
||||||
|
Ok(out)
|
||||||
|
} else {
|
||||||
|
unsupported_type(ctx, FN_NAME, &[x1_ty, x2_ty])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invokes the `np_linalg_det` linalg function
|
||||||
|
pub fn call_np_linalg_det<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
x1: (Type, BasicValueEnum<'ctx>),
|
||||||
|
) -> Result<BasicValueEnum<'ctx>, String> {
|
||||||
|
const FN_NAME: &str = "np_linalg_matrix_power";
|
||||||
|
let (x1_ty, x1) = x1;
|
||||||
|
|
||||||
|
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||||
|
if let BasicValueEnum::PointerValue(_) = x1 {
|
||||||
|
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, x1_ty);
|
||||||
|
let n1_elem_ty = ctx.get_llvm_type(generator, elem_ty);
|
||||||
|
|
||||||
|
let BasicTypeEnum::FloatType(_) = n1_elem_ty else {
|
||||||
|
unsupported_type(ctx, FN_NAME, &[x1_ty]);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Changing second parameter to a `NDArray` for uniformity in function call
|
||||||
|
let out = numpy::create_ndarray_const_shape(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
elem_ty,
|
||||||
|
&[llvm_usize.const_int(1, false)],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
extern_fns::call_np_linalg_det(ctx, x1, out.as_base_value().as_basic_value_enum(), None);
|
||||||
|
let res =
|
||||||
|
unsafe { out.data().get_unchecked(ctx, generator, &llvm_usize.const_zero(), None) };
|
||||||
|
Ok(res)
|
||||||
|
} else {
|
||||||
|
unsupported_type(ctx, FN_NAME, &[x1_ty])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Invokes the `sp_linalg_schur` linalg function
|
/// Invokes the `sp_linalg_schur` linalg function
|
||||||
pub fn call_sp_linalg_schur<'ctx, G: CodeGenerator + ?Sized>(
|
pub fn call_sp_linalg_schur<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
|
@ -185,36 +185,8 @@ generate_linalg_extern_fn!(call_np_linalg_qr, "np_linalg_qr", 3);
|
|||||||
generate_linalg_extern_fn!(call_np_linalg_svd, "np_linalg_svd", 4);
|
generate_linalg_extern_fn!(call_np_linalg_svd, "np_linalg_svd", 4);
|
||||||
generate_linalg_extern_fn!(call_np_linalg_inv, "np_linalg_inv", 2);
|
generate_linalg_extern_fn!(call_np_linalg_inv, "np_linalg_inv", 2);
|
||||||
generate_linalg_extern_fn!(call_np_linalg_pinv, "np_linalg_pinv", 2);
|
generate_linalg_extern_fn!(call_np_linalg_pinv, "np_linalg_pinv", 2);
|
||||||
|
generate_linalg_extern_fn!(call_np_linalg_matrix_power, "np_linalg_matrix_power", 3);
|
||||||
|
generate_linalg_extern_fn!(call_np_linalg_det, "np_linalg_det", 2);
|
||||||
generate_linalg_extern_fn!(call_sp_linalg_lu, "sp_linalg_lu", 3);
|
generate_linalg_extern_fn!(call_sp_linalg_lu, "sp_linalg_lu", 3);
|
||||||
generate_linalg_extern_fn!(call_sp_linalg_schur, "sp_linalg_schur", 3);
|
generate_linalg_extern_fn!(call_sp_linalg_schur, "sp_linalg_schur", 3);
|
||||||
generate_linalg_extern_fn!(call_sp_linalg_hessenberg, "sp_linalg_hessenberg", 3);
|
generate_linalg_extern_fn!(call_sp_linalg_hessenberg, "sp_linalg_hessenberg", 3);
|
||||||
|
|
||||||
/// Invokes the linalg `np_dot` function.
|
|
||||||
pub fn call_np_dot<'ctx>(
|
|
||||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
|
||||||
mat1: BasicValueEnum<'ctx>,
|
|
||||||
mat2: BasicValueEnum<'ctx>,
|
|
||||||
name: Option<&str>,
|
|
||||||
) -> FloatValue<'ctx> {
|
|
||||||
const FN_NAME: &str = "np_dot";
|
|
||||||
|
|
||||||
let extern_fn = ctx.module.get_function(FN_NAME).unwrap_or_else(|| {
|
|
||||||
let fn_type =
|
|
||||||
ctx.ctx.f64_type().fn_type(&[mat1.get_type().into(), mat2.get_type().into()], false);
|
|
||||||
let func = ctx.module.add_function(FN_NAME, fn_type, None);
|
|
||||||
for attr in ["mustprogress", "nofree", "nounwind", "willreturn", "writeonly"] {
|
|
||||||
func.add_attribute(
|
|
||||||
AttributeLoc::Function,
|
|
||||||
ctx.ctx.create_enum_attribute(Attribute::get_named_enum_kind_id(attr), 0),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
func
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.builder
|
|
||||||
.build_call(extern_fn, &[mat1.into(), mat2.into()], name.unwrap_or_default())
|
|
||||||
.map(CallSiteValue::try_as_basic_value)
|
|
||||||
.map(|v| v.map_left(BasicValueEnum::into_float_value))
|
|
||||||
.map(Either::unwrap_left)
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
@ -26,12 +26,15 @@ use crate::{
|
|||||||
typedef::{FunSignature, Type, TypeEnum},
|
typedef::{FunSignature, Type, TypeEnum},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use inkwell::types::{AnyTypeEnum, BasicTypeEnum, PointerType};
|
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
types::BasicType,
|
types::BasicType,
|
||||||
values::{BasicValueEnum, IntValue, PointerValue},
|
values::{BasicValueEnum, IntValue, PointerValue},
|
||||||
AddressSpace, IntPredicate, OptimizationLevel,
|
AddressSpace, IntPredicate, OptimizationLevel,
|
||||||
};
|
};
|
||||||
|
use inkwell::{
|
||||||
|
types::{AnyTypeEnum, BasicTypeEnum, PointerType},
|
||||||
|
values::BasicValue,
|
||||||
|
};
|
||||||
use nac3parser::ast::{Operator, StrRef};
|
use nac3parser::ast::{Operator, StrRef};
|
||||||
|
|
||||||
/// Creates an uninitialized `NDArray` instance.
|
/// Creates an uninitialized `NDArray` instance.
|
||||||
@ -2390,7 +2393,7 @@ pub fn ndarray_reshape<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
generator,
|
generator,
|
||||||
ctx.builder.build_int_compare(IntPredicate::EQ, out_sz, n_sz, "").unwrap(),
|
ctx.builder.build_int_compare(IntPredicate::EQ, out_sz, n_sz, "").unwrap(),
|
||||||
"0:ValueError",
|
"0:ValueError",
|
||||||
"cannot reshape array of size {} into provided shape of size {}",
|
"cannot reshape array of size {0} into provided shape of size {1}",
|
||||||
[Some(n_sz), Some(out_sz), None],
|
[Some(n_sz), Some(out_sz), None],
|
||||||
ctx.current_loc,
|
ctx.current_loc,
|
||||||
);
|
);
|
||||||
@ -2417,3 +2420,102 @@ pub fn ndarray_reshape<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generates LLVM IR for `ndarray.dot`.
|
||||||
|
/// Calculate inner product of two vectors or literals
|
||||||
|
/// For matrix multiplication use `np_matmul`
|
||||||
|
///
|
||||||
|
/// The input `NDArray` are flattened and treated as 1D
|
||||||
|
/// The operation is equivalent to `np.dot(arr1.ravel(), arr2.ravel())`
|
||||||
|
pub fn ndarray_dot<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
x1: (Type, BasicValueEnum<'ctx>),
|
||||||
|
x2: (Type, BasicValueEnum<'ctx>),
|
||||||
|
) -> Result<BasicValueEnum<'ctx>, String> {
|
||||||
|
const FN_NAME: &str = "ndarray_dot";
|
||||||
|
let (x1_ty, x1) = x1;
|
||||||
|
let (_, x2) = x2;
|
||||||
|
|
||||||
|
let llvm_usize = generator.get_size_type(ctx.ctx);
|
||||||
|
|
||||||
|
match (x1, x2) {
|
||||||
|
(BasicValueEnum::PointerValue(n1), BasicValueEnum::PointerValue(n2)) => {
|
||||||
|
let n1 = NDArrayValue::from_ptr_val(n1, llvm_usize, None);
|
||||||
|
let n2 = NDArrayValue::from_ptr_val(n2, llvm_usize, None);
|
||||||
|
|
||||||
|
let n1_sz = call_ndarray_calc_size(generator, ctx, &n1.dim_sizes(), (None, None));
|
||||||
|
let n2_sz = call_ndarray_calc_size(generator, ctx, &n1.dim_sizes(), (None, None));
|
||||||
|
|
||||||
|
ctx.make_assert(
|
||||||
|
generator,
|
||||||
|
ctx.builder.build_int_compare(IntPredicate::EQ, n1_sz, n2_sz, "").unwrap(),
|
||||||
|
"0:ValueError",
|
||||||
|
"shapes ({0}), ({1}) not aligned",
|
||||||
|
[Some(n1_sz), Some(n2_sz), None],
|
||||||
|
ctx.current_loc,
|
||||||
|
);
|
||||||
|
|
||||||
|
let identity =
|
||||||
|
unsafe { n1.data().get_unchecked(ctx, generator, &llvm_usize.const_zero(), None) };
|
||||||
|
let acc = ctx.builder.build_alloca(identity.get_type(), "").unwrap();
|
||||||
|
ctx.builder.build_store(acc, identity.get_type().const_zero()).unwrap();
|
||||||
|
|
||||||
|
gen_for_callback_incrementing(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
None,
|
||||||
|
llvm_usize.const_zero(),
|
||||||
|
(n1_sz, false),
|
||||||
|
|generator, ctx, _, idx| {
|
||||||
|
let elem1 = unsafe { n1.data().get_unchecked(ctx, generator, &idx, None) };
|
||||||
|
let elem2 = unsafe { n2.data().get_unchecked(ctx, generator, &idx, None) };
|
||||||
|
|
||||||
|
let product = match elem1 {
|
||||||
|
BasicValueEnum::IntValue(e1) => ctx
|
||||||
|
.builder
|
||||||
|
.build_int_mul(e1, elem2.into_int_value(), "")
|
||||||
|
.unwrap()
|
||||||
|
.as_basic_value_enum(),
|
||||||
|
BasicValueEnum::FloatValue(e1) => ctx
|
||||||
|
.builder
|
||||||
|
.build_float_mul(e1, elem2.into_float_value(), "")
|
||||||
|
.unwrap()
|
||||||
|
.as_basic_value_enum(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let acc_val = ctx.builder.build_load(acc, "").unwrap();
|
||||||
|
let acc_val = match acc_val {
|
||||||
|
BasicValueEnum::IntValue(e1) => ctx
|
||||||
|
.builder
|
||||||
|
.build_int_add(e1, product.into_int_value(), "")
|
||||||
|
.unwrap()
|
||||||
|
.as_basic_value_enum(),
|
||||||
|
BasicValueEnum::FloatValue(e1) => ctx
|
||||||
|
.builder
|
||||||
|
.build_float_add(e1, product.into_float_value(), "")
|
||||||
|
.unwrap()
|
||||||
|
.as_basic_value_enum(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
ctx.builder.build_store(acc, acc_val).unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
llvm_usize.const_int(1, false),
|
||||||
|
)?;
|
||||||
|
let acc_val = ctx.builder.build_load(acc, "").unwrap();
|
||||||
|
Ok(acc_val)
|
||||||
|
}
|
||||||
|
(BasicValueEnum::IntValue(e1), BasicValueEnum::IntValue(e2)) => {
|
||||||
|
Ok(ctx.builder.build_int_mul(e1, e2, "").unwrap().as_basic_value_enum())
|
||||||
|
}
|
||||||
|
(BasicValueEnum::FloatValue(e1), BasicValueEnum::FloatValue(e2)) => {
|
||||||
|
Ok(ctx.builder.build_float_mul(e1, e2, "").unwrap().as_basic_value_enum())
|
||||||
|
}
|
||||||
|
_ => unreachable!(
|
||||||
|
"{FN_NAME}() not supported for '{}'",
|
||||||
|
format!("'{}'", ctx.unifier.stringify(x1_ty))
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -568,6 +568,8 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
| PrimDef::FunNpLinalgSvd
|
| PrimDef::FunNpLinalgSvd
|
||||||
| PrimDef::FunNpLinalgInv
|
| PrimDef::FunNpLinalgInv
|
||||||
| PrimDef::FunNpLinalgPinv
|
| PrimDef::FunNpLinalgPinv
|
||||||
|
| PrimDef::FunNpLinalgMatrixPower
|
||||||
|
| PrimDef::FunNpLinalgDet
|
||||||
| PrimDef::FunSpLinalgLu
|
| PrimDef::FunSpLinalgLu
|
||||||
| PrimDef::FunSpLinalgSchur
|
| PrimDef::FunSpLinalgSchur
|
||||||
| PrimDef::FunSpLinalgHessenberg => self.build_linalg_methods(prim),
|
| PrimDef::FunSpLinalgHessenberg => self.build_linalg_methods(prim),
|
||||||
@ -1954,6 +1956,8 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
PrimDef::FunNpLinalgSvd,
|
PrimDef::FunNpLinalgSvd,
|
||||||
PrimDef::FunNpLinalgInv,
|
PrimDef::FunNpLinalgInv,
|
||||||
PrimDef::FunNpLinalgPinv,
|
PrimDef::FunNpLinalgPinv,
|
||||||
|
PrimDef::FunNpLinalgMatrixPower,
|
||||||
|
PrimDef::FunNpLinalgDet,
|
||||||
PrimDef::FunSpLinalgLu,
|
PrimDef::FunSpLinalgLu,
|
||||||
PrimDef::FunSpLinalgSchur,
|
PrimDef::FunSpLinalgSchur,
|
||||||
PrimDef::FunSpLinalgHessenberg,
|
PrimDef::FunSpLinalgHessenberg,
|
||||||
@ -1965,7 +1969,7 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
self.unifier,
|
self.unifier,
|
||||||
&self.num_or_ndarray_var_map,
|
&self.num_or_ndarray_var_map,
|
||||||
prim.name(),
|
prim.name(),
|
||||||
self.primitives.float,
|
self.num_ty.ty,
|
||||||
&[(self.num_or_ndarray_ty.ty, "x1"), (self.num_or_ndarray_ty.ty, "x2")],
|
&[(self.num_or_ndarray_ty.ty, "x1"), (self.num_or_ndarray_ty.ty, "x2")],
|
||||||
Box::new(move |ctx, _, fun, args, generator| {
|
Box::new(move |ctx, _, fun, args, generator| {
|
||||||
let x1_ty = fun.0.args[0].ty;
|
let x1_ty = fun.0.args[0].ty;
|
||||||
@ -1973,12 +1977,7 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
let x2_ty = fun.0.args[1].ty;
|
let x2_ty = fun.0.args[1].ty;
|
||||||
let x2_val = args[1].1.clone().to_basic_value_enum(ctx, generator, x2_ty)?;
|
let x2_val = args[1].1.clone().to_basic_value_enum(ctx, generator, x2_ty)?;
|
||||||
|
|
||||||
Ok(Some(builtin_fns::call_np_dot(
|
Ok(Some(ndarray_dot(generator, ctx, (x1_ty, x1_val), (x2_ty, x2_val))?))
|
||||||
generator,
|
|
||||||
ctx,
|
|
||||||
(x1_ty, x1_val),
|
|
||||||
(x2_ty, x2_val),
|
|
||||||
)?))
|
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|
||||||
@ -2077,10 +2076,39 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => {
|
PrimDef::FunNpLinalgMatrixPower => create_fn_by_codegen(
|
||||||
println!("{:?}", prim.name());
|
self.unifier,
|
||||||
unreachable!()
|
&VarMap::new(),
|
||||||
}
|
prim.name(),
|
||||||
|
self.ndarray_float_2d,
|
||||||
|
&[(self.ndarray_float_2d, "x1"), (self.primitives.int32, "power")],
|
||||||
|
Box::new(move |ctx, _, fun, args, generator| {
|
||||||
|
let x1_ty = fun.0.args[0].ty;
|
||||||
|
let x1_val = args[0].1.clone().to_basic_value_enum(ctx, generator, x1_ty)?;
|
||||||
|
let x2_ty = fun.0.args[1].ty;
|
||||||
|
let x2_val = args[1].1.clone().to_basic_value_enum(ctx, generator, x2_ty)?;
|
||||||
|
|
||||||
|
Ok(Some(builtin_fns::call_np_linalg_matrix_power(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
(x1_ty, x1_val),
|
||||||
|
(x2_ty, x2_val),
|
||||||
|
)?))
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
PrimDef::FunNpLinalgDet => create_fn_by_codegen(
|
||||||
|
self.unifier,
|
||||||
|
&VarMap::new(),
|
||||||
|
prim.name(),
|
||||||
|
self.primitives.float,
|
||||||
|
&[(self.ndarray_float_2d, "x1")],
|
||||||
|
Box::new(move |ctx, _, fun, args, generator| {
|
||||||
|
let x1_ty = fun.0.args[0].ty;
|
||||||
|
let x1_val = args[0].1.clone().to_basic_value_enum(ctx, generator, x1_ty)?;
|
||||||
|
Ok(Some(builtin_fns::call_np_linalg_det(generator, ctx, (x1_ty, x1_val))?))
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +110,8 @@ pub enum PrimDef {
|
|||||||
FunNpLinalgSvd,
|
FunNpLinalgSvd,
|
||||||
FunNpLinalgInv,
|
FunNpLinalgInv,
|
||||||
FunNpLinalgPinv,
|
FunNpLinalgPinv,
|
||||||
|
FunNpLinalgMatrixPower,
|
||||||
|
FunNpLinalgDet,
|
||||||
FunSpLinalgLu,
|
FunSpLinalgLu,
|
||||||
FunSpLinalgSchur,
|
FunSpLinalgSchur,
|
||||||
FunSpLinalgHessenberg,
|
FunSpLinalgHessenberg,
|
||||||
@ -295,6 +297,8 @@ impl PrimDef {
|
|||||||
PrimDef::FunNpLinalgSvd => fun("np_linalg_svd", None),
|
PrimDef::FunNpLinalgSvd => fun("np_linalg_svd", None),
|
||||||
PrimDef::FunNpLinalgInv => fun("np_linalg_inv", None),
|
PrimDef::FunNpLinalgInv => fun("np_linalg_inv", None),
|
||||||
PrimDef::FunNpLinalgPinv => fun("np_linalg_pinv", None),
|
PrimDef::FunNpLinalgPinv => fun("np_linalg_pinv", None),
|
||||||
|
PrimDef::FunNpLinalgMatrixPower => fun("np_linalg_matrix_power", None),
|
||||||
|
PrimDef::FunNpLinalgDet => fun("np_linalg_det", None),
|
||||||
PrimDef::FunSpLinalgLu => fun("sp_linalg_lu", None),
|
PrimDef::FunSpLinalgLu => fun("sp_linalg_lu", None),
|
||||||
PrimDef::FunSpLinalgSchur => fun("sp_linalg_schur", None),
|
PrimDef::FunSpLinalgSchur => fun("sp_linalg_schur", None),
|
||||||
PrimDef::FunSpLinalgHessenberg => fun("sp_linalg_hessenberg", None),
|
PrimDef::FunSpLinalgHessenberg => fun("sp_linalg_hessenberg", None),
|
||||||
|
@ -1130,6 +1130,44 @@ impl<'a> Inferencer<'a> {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if id == &"np_dot".into() {
|
||||||
|
let arg0 = self.fold_expr(args.remove(0))?;
|
||||||
|
let arg1 = self.fold_expr(args.remove(0))?;
|
||||||
|
let arg0_ty = arg0.custom.unwrap();
|
||||||
|
|
||||||
|
let ret = if arg0_ty.obj_id(self.unifier).is_some_and(|id| id == PrimDef::NDArray.id())
|
||||||
|
{
|
||||||
|
let (ndarray_dtype, _) = unpack_ndarray_var_tys(self.unifier, arg0_ty);
|
||||||
|
|
||||||
|
ndarray_dtype
|
||||||
|
} else {
|
||||||
|
arg0_ty
|
||||||
|
};
|
||||||
|
|
||||||
|
let custom = self.unifier.add_ty(TypeEnum::TFunc(FunSignature {
|
||||||
|
args: vec![
|
||||||
|
FuncArg { name: "x1".into(), ty: arg0.custom.unwrap(), default_value: None },
|
||||||
|
FuncArg { name: "x2".into(), ty: arg1.custom.unwrap(), default_value: None },
|
||||||
|
],
|
||||||
|
ret,
|
||||||
|
vars: VarMap::new(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
return Ok(Some(Located {
|
||||||
|
location,
|
||||||
|
custom: Some(ret),
|
||||||
|
node: ExprKind::Call {
|
||||||
|
func: Box::new(Located {
|
||||||
|
custom: Some(custom),
|
||||||
|
location: func.location,
|
||||||
|
node: ExprKind::Name { id: *id, ctx: *ctx },
|
||||||
|
}),
|
||||||
|
args: vec![arg0, arg1],
|
||||||
|
keywords: vec![],
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
if ["np_min", "np_max"].iter().any(|fun_id| id == &(*fun_id).into()) && args.len() == 1 {
|
if ["np_min", "np_max"].iter().any(|fun_id| id == &(*fun_id).into()) && args.len() == 1 {
|
||||||
let arg0 = self.fold_expr(args.remove(0))?;
|
let arg0 = self.fold_expr(args.remove(0))?;
|
||||||
let arg0_ty = arg0.custom.unwrap();
|
let arg0_ty = arg0.custom.unwrap();
|
||||||
|
@ -237,6 +237,8 @@ def patch(module):
|
|||||||
module.np_linalg_svd = np.linalg.svd
|
module.np_linalg_svd = np.linalg.svd
|
||||||
module.np_linalg_inv = np.linalg.inv
|
module.np_linalg_inv = np.linalg.inv
|
||||||
module.np_linalg_pinv = np.linalg.pinv
|
module.np_linalg_pinv = np.linalg.pinv
|
||||||
|
module.np_linalg_matrix_power = np.linalg.matrix_power
|
||||||
|
module.np_linalg_det = np.linalg.det
|
||||||
|
|
||||||
module.sp_linalg_lu = lambda x: sp.linalg.lu(x, True)
|
module.sp_linalg_lu = lambda x: sp.linalg.lu(x, True)
|
||||||
module.sp_linalg_schur = sp.linalg.schur
|
module.sp_linalg_schur = sp.linalg.schur
|
||||||
|
@ -34,38 +34,6 @@ impl InputMatrix {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// `mat1` and `mat2` should point to a valid 1DArray of `f64` floats in row-major order
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn np_dot(mat1: *mut InputMatrix, mat2: *mut InputMatrix) -> f64 {
|
|
||||||
let mat1 = mat1.as_mut().unwrap();
|
|
||||||
let mat2 = mat2.as_mut().unwrap();
|
|
||||||
|
|
||||||
if !(mat1.ndims == 1 && mat2.ndims == 1) {
|
|
||||||
let err_msg = format!(
|
|
||||||
"expected 1D Vector Input, but received {}D and {}D input",
|
|
||||||
mat1.ndims, mat2.ndims
|
|
||||||
);
|
|
||||||
report_error("ValueError", "np_dot", file!(), line!(), column!(), &err_msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
let dim1 = (*mat1).get_dims();
|
|
||||||
let dim2 = (*mat2).get_dims();
|
|
||||||
|
|
||||||
if dim1[0] != dim2[0] {
|
|
||||||
let err_msg = format!("shapes ({},) and ({},) not aligned", dim1[0], dim2[0]);
|
|
||||||
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_slice2 = unsafe { slice::from_raw_parts_mut(mat2.data, dim2[0]) };
|
|
||||||
|
|
||||||
let matrix1 = DMatrix::from_row_slice(dim1[0], 1, data_slice1);
|
|
||||||
let matrix2 = DMatrix::from_row_slice(dim2[0], 1, data_slice2);
|
|
||||||
|
|
||||||
matrix1.dot(&matrix2)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// `mat1` and `mat2` should point to a valid 2DArray of `f64` floats in row-major order
|
/// `mat1` and `mat2` should point to a valid 2DArray of `f64` floats in row-major order
|
||||||
@ -299,6 +267,76 @@ pub unsafe extern "C" fn np_linalg_pinv(mat1: *mut InputMatrix, out: *mut InputM
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// `mat1` should point to a valid 2DArray of `f64` floats in row-major order
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn np_linalg_matrix_power(
|
||||||
|
mat1: *mut InputMatrix,
|
||||||
|
mat2: *mut InputMatrix,
|
||||||
|
out: *mut InputMatrix,
|
||||||
|
) {
|
||||||
|
let mat1 = mat1.as_mut().unwrap();
|
||||||
|
let mat2 = mat2.as_mut().unwrap();
|
||||||
|
let out = out.as_mut().unwrap();
|
||||||
|
|
||||||
|
if mat1.ndims != 2 {
|
||||||
|
let err_msg = format!("expected 2D Vector Input, but received {}D", mat1.ndims);
|
||||||
|
report_error("ValueError", "np_linalg_matrix_power", file!(), line!(), column!(), &err_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
let dim1 = (*mat1).get_dims();
|
||||||
|
let power = unsafe { slice::from_raw_parts_mut(mat2.data, 1) };
|
||||||
|
let power = power[0];
|
||||||
|
let outdim = out.get_dims();
|
||||||
|
let out_slice = unsafe { slice::from_raw_parts_mut(out.data, outdim[0] * outdim[1]) };
|
||||||
|
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
||||||
|
|
||||||
|
let abs_pow = power.abs();
|
||||||
|
let matrix1 = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
||||||
|
let mut result = matrix1.pow(abs_pow as u32);
|
||||||
|
|
||||||
|
if power < 0.0 {
|
||||||
|
if !result.is_invertible() {
|
||||||
|
report_error(
|
||||||
|
"LinAlgError",
|
||||||
|
"np_linalg_inv",
|
||||||
|
file!(),
|
||||||
|
line!(),
|
||||||
|
column!(),
|
||||||
|
"no inverse for Singular Matrix",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
result = result.try_inverse().unwrap();
|
||||||
|
}
|
||||||
|
out_slice.copy_from_slice(result.transpose().as_slice());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// `mat1` should point to a valid 2DArray of `f64` floats in row-major order
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn np_linalg_det(mat1: *mut InputMatrix, out: *mut InputMatrix) {
|
||||||
|
let mat1 = mat1.as_mut().unwrap();
|
||||||
|
let out = out.as_mut().unwrap();
|
||||||
|
|
||||||
|
if mat1.ndims != 2 {
|
||||||
|
let err_msg = format!("expected 2D Vector Input, but received {}D input", mat1.ndims);
|
||||||
|
report_error("ValueError", "np_linalg_det", file!(), line!(), column!(), &err_msg);
|
||||||
|
}
|
||||||
|
let dim1 = (*mat1).get_dims();
|
||||||
|
let out_slice = unsafe { slice::from_raw_parts_mut(out.data, 1) };
|
||||||
|
let data_slice1 = unsafe { slice::from_raw_parts_mut(mat1.data, dim1[0] * dim1[1]) };
|
||||||
|
|
||||||
|
let matrix = DMatrix::from_row_slice(dim1[0], dim1[1], data_slice1);
|
||||||
|
if !matrix.is_square() {
|
||||||
|
let err_msg =
|
||||||
|
format!("last 2 dimensions of the array must be square: {0} != {1}", dim1[0], dim1[1]);
|
||||||
|
report_error("LinAlgError", "np_linalg_inv", file!(), line!(), column!(), &err_msg);
|
||||||
|
}
|
||||||
|
out_slice[0] = matrix.determinant();
|
||||||
|
}
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// `mat1` should point to a valid 2DArray of `f64` floats in row-major order
|
/// `mat1` should point to a valid 2DArray of `f64` floats in row-major order
|
||||||
|
@ -1451,13 +1451,28 @@ def test_ndarray_reshape():
|
|||||||
output_ndarray_float_1(z)
|
output_ndarray_float_1(z)
|
||||||
|
|
||||||
def test_ndarray_dot():
|
def test_ndarray_dot():
|
||||||
x: ndarray[float, 1] = np_array([5.0, 1.0])
|
x1: ndarray[float, 1] = np_array([5.0, 1.0, 4.0, 2.0])
|
||||||
y: ndarray[float, 1] = np_array([5.0, 1.0])
|
y1: ndarray[float, 1] = np_array([5.0, 1.0, 6.0, 6.0])
|
||||||
z = np_dot(x, y)
|
z1 = np_dot(x1, y1)
|
||||||
|
|
||||||
output_ndarray_float_1(x)
|
x2: ndarray[int32, 1] = np_array([5, 1, 4, 2])
|
||||||
output_ndarray_float_1(y)
|
y2: ndarray[int32, 1] = np_array([5, 1, 6, 6])
|
||||||
output_float64(z)
|
z2 = np_dot(x2, y2)
|
||||||
|
|
||||||
|
x3: ndarray[bool, 1] = np_array([True, True, True, True])
|
||||||
|
y3: ndarray[bool, 1] = np_array([True, True, True, True])
|
||||||
|
z3 = np_dot(x3, y3)
|
||||||
|
|
||||||
|
z4 = np_dot(2, 3)
|
||||||
|
z5 = np_dot(2., 3.)
|
||||||
|
z6 = np_dot(True, False)
|
||||||
|
|
||||||
|
output_float64(z1)
|
||||||
|
output_int32(z2)
|
||||||
|
output_bool(z3)
|
||||||
|
output_int32(z4)
|
||||||
|
output_float64(z5)
|
||||||
|
output_bool(z6)
|
||||||
|
|
||||||
def test_ndarray_linalg_matmul():
|
def test_ndarray_linalg_matmul():
|
||||||
x: ndarray[float, 2] = np_array([[5.0, 1.0], [1.0, 4.0]])
|
x: ndarray[float, 2] = np_array([[5.0, 1.0], [1.0, 4.0]])
|
||||||
@ -1503,6 +1518,20 @@ def test_ndarray_pinv():
|
|||||||
output_ndarray_float_2(x)
|
output_ndarray_float_2(x)
|
||||||
output_ndarray_float_2(y)
|
output_ndarray_float_2(y)
|
||||||
|
|
||||||
|
def test_ndarray_matrix_power():
|
||||||
|
x: ndarray[float, 2] = np_array([[-5.0, -1.0, 2.0], [-1.0, 4.0, 7.5], [-1.0, 8.0, -8.5]])
|
||||||
|
y = np_linalg_matrix_power(x, -9)
|
||||||
|
|
||||||
|
output_ndarray_float_2(x)
|
||||||
|
output_ndarray_float_2(y)
|
||||||
|
|
||||||
|
def test_ndarray_det():
|
||||||
|
x: ndarray[float, 2] = np_array([[-5.0, -1.0, 2.0], [-1.0, 4.0, 7.5], [-1.0, 8.0, -8.5]])
|
||||||
|
y = np_linalg_det(x)
|
||||||
|
|
||||||
|
output_ndarray_float_2(x)
|
||||||
|
output_float64(y)
|
||||||
|
|
||||||
def test_ndarray_schur():
|
def test_ndarray_schur():
|
||||||
x: ndarray[float, 2] = np_array([[-5.0, -1.0, 2.0], [-1.0, 4.0, 7.5], [-1.0, 8.0, -8.5]])
|
x: ndarray[float, 2] = np_array([[-5.0, -1.0, 2.0], [-1.0, 4.0, 7.5], [-1.0, 8.0, -8.5]])
|
||||||
t, z = sp_linalg_schur(x)
|
t, z = sp_linalg_schur(x)
|
||||||
@ -1736,6 +1765,8 @@ def run() -> int32:
|
|||||||
test_ndarray_svd()
|
test_ndarray_svd()
|
||||||
test_ndarray_linalg_inv()
|
test_ndarray_linalg_inv()
|
||||||
test_ndarray_pinv()
|
test_ndarray_pinv()
|
||||||
|
test_ndarray_matrix_power()
|
||||||
|
test_ndarray_det()
|
||||||
test_ndarray_lu()
|
test_ndarray_lu()
|
||||||
test_ndarray_schur()
|
test_ndarray_schur()
|
||||||
test_ndarray_hessenberg()
|
test_ndarray_hessenberg()
|
||||||
|
Loading…
Reference in New Issue
Block a user