forked from M-Labs/nac3
core/ndstrides: implement np_shape() and np_strides()
These functions are not important, but they are handy for debugging. `np.strides()` is not an actual NumPy function, but `ndarray.strides` is used.
This commit is contained in:
parent
18db85fa7b
commit
40c2448651
@ -5,7 +5,7 @@ use inkwell::{
|
||||
AddressSpace,
|
||||
};
|
||||
|
||||
use super::any::AnyObject;
|
||||
use super::{any::AnyObject, tuple::TupleObject};
|
||||
use crate::{
|
||||
codegen::{
|
||||
irrt::{
|
||||
@ -426,6 +426,62 @@ impl<'ctx> NDArrayObject<'ctx> {
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// Create the shape tuple of this ndarray like `np.shape(<ndarray>)`.
|
||||
///
|
||||
/// The returned integers in the tuple are in int32.
|
||||
pub fn make_shape_tuple<G: CodeGenerator + ?Sized>(
|
||||
&self,
|
||||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
) -> TupleObject<'ctx> {
|
||||
// TODO: Return a tuple of SizeT
|
||||
|
||||
let mut objects = Vec::with_capacity(self.ndims as usize);
|
||||
|
||||
for i in 0..self.ndims {
|
||||
let dim = self
|
||||
.instance
|
||||
.get(generator, ctx, |f| f.shape)
|
||||
.get_index_const(generator, ctx, i64::try_from(i).unwrap())
|
||||
.truncate_or_bit_cast(generator, ctx, Int32);
|
||||
|
||||
objects.push(AnyObject {
|
||||
ty: ctx.primitives.int32,
|
||||
value: dim.value.as_basic_value_enum(),
|
||||
});
|
||||
}
|
||||
|
||||
TupleObject::from_objects(generator, ctx, objects)
|
||||
}
|
||||
|
||||
/// Create the strides tuple of this ndarray like `<ndarray>.strides`.
|
||||
///
|
||||
/// The returned integers in the tuple are in int32.
|
||||
pub fn make_strides_tuple<G: CodeGenerator + ?Sized>(
|
||||
&self,
|
||||
generator: &mut G,
|
||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||
) -> TupleObject<'ctx> {
|
||||
// TODO: Return a tuple of SizeT.
|
||||
|
||||
let mut objects = Vec::with_capacity(self.ndims as usize);
|
||||
|
||||
for i in 0..self.ndims {
|
||||
let dim = self
|
||||
.instance
|
||||
.get(generator, ctx, |f| f.strides)
|
||||
.get_index_const(generator, ctx, i64::try_from(i).unwrap())
|
||||
.truncate_or_bit_cast(generator, ctx, Int32);
|
||||
|
||||
objects.push(AnyObject {
|
||||
ty: ctx.primitives.int32,
|
||||
value: dim.value.as_basic_value_enum(),
|
||||
});
|
||||
}
|
||||
|
||||
TupleObject::from_objects(generator, ctx, objects)
|
||||
}
|
||||
}
|
||||
|
||||
/// A convenience enum for implementing functions that acts on scalars or ndarrays or both.
|
||||
|
@ -20,6 +20,7 @@ use crate::{
|
||||
builtin_fns,
|
||||
classes::{ProxyValue, RangeValue},
|
||||
numpy::*,
|
||||
object::{any::AnyObject, ndarray::NDArrayObject},
|
||||
stmt::exn_constructor,
|
||||
},
|
||||
symbol_resolver::SymbolValue,
|
||||
@ -512,6 +513,10 @@ impl<'a> BuiltinBuilder<'a> {
|
||||
| PrimDef::FunNpEye
|
||||
| PrimDef::FunNpIdentity => self.build_ndarray_other_factory_function(prim),
|
||||
|
||||
PrimDef::FunNpShape | PrimDef::FunNpStrides => {
|
||||
self.build_ndarray_property_getter_function(prim)
|
||||
}
|
||||
|
||||
PrimDef::FunStr => self.build_str_function(),
|
||||
|
||||
PrimDef::FunFloor | PrimDef::FunFloor64 | PrimDef::FunCeil | PrimDef::FunCeil64 => {
|
||||
@ -1386,6 +1391,54 @@ impl<'a> BuiltinBuilder<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_ndarray_property_getter_function(&mut self, prim: PrimDef) -> TopLevelDef {
|
||||
debug_assert_prim_is_allowed(prim, &[PrimDef::FunNpShape, PrimDef::FunNpStrides]);
|
||||
|
||||
let in_ndarray_ty = self.unifier.get_fresh_var_with_range(
|
||||
&[self.primitives.ndarray],
|
||||
Some("T".into()),
|
||||
None,
|
||||
);
|
||||
|
||||
match prim {
|
||||
PrimDef::FunNpShape | PrimDef::FunNpStrides => {
|
||||
// The function signatures of `np_shape` an `np_size` are the same.
|
||||
// Mixed together for convenience.
|
||||
|
||||
// The return type is a tuple of variable length depending on the ndims of the input ndarray.
|
||||
let ret_ty = self.unifier.get_dummy_var().ty; // Handled by special folding
|
||||
|
||||
create_fn_by_codegen(
|
||||
self.unifier,
|
||||
&into_var_map([in_ndarray_ty]),
|
||||
prim.name(),
|
||||
ret_ty,
|
||||
&[(in_ndarray_ty.ty, "a")],
|
||||
Box::new(move |ctx, obj, fun, args, generator| {
|
||||
assert!(obj.is_none());
|
||||
assert_eq!(args.len(), 1);
|
||||
|
||||
let ndarray_ty = fun.0.args[0].ty;
|
||||
let ndarray =
|
||||
args[0].1.clone().to_basic_value_enum(ctx, generator, ndarray_ty)?;
|
||||
|
||||
let ndarray = AnyObject { ty: ndarray_ty, value: ndarray };
|
||||
let ndarray = NDArrayObject::from_object(generator, ctx, ndarray);
|
||||
|
||||
let result_tuple = match prim {
|
||||
PrimDef::FunNpShape => ndarray.make_shape_tuple(generator, ctx),
|
||||
PrimDef::FunNpStrides => ndarray.make_strides_tuple(generator, ctx),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
Ok(Some(result_tuple.value.as_basic_value_enum()))
|
||||
}),
|
||||
)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the `str()` function.
|
||||
fn build_str_function(&mut self) -> TopLevelDef {
|
||||
let prim = PrimDef::FunStr;
|
||||
@ -1888,8 +1941,8 @@ impl<'a> BuiltinBuilder<'a> {
|
||||
self.unifier,
|
||||
&into_var_map([ndarray_ty]),
|
||||
prim.name(),
|
||||
ndarray_ty.ty,
|
||||
&[(ndarray_ty.ty, "x")],
|
||||
self.ndarray_num_ty,
|
||||
&[(self.ndarray_num_ty, "x")],
|
||||
Box::new(move |ctx, _, fun, args, generator| {
|
||||
let arg_ty = fun.0.args[0].ty;
|
||||
let arg_val =
|
||||
|
@ -54,6 +54,10 @@ pub enum PrimDef {
|
||||
FunNpEye,
|
||||
FunNpIdentity,
|
||||
|
||||
// NumPy ndarray property getters
|
||||
FunNpShape,
|
||||
FunNpStrides,
|
||||
|
||||
// Miscellaneous NumPy & SciPy functions
|
||||
FunNpRound,
|
||||
FunNpFloor,
|
||||
@ -240,6 +244,10 @@ impl PrimDef {
|
||||
PrimDef::FunNpEye => fun("np_eye", None),
|
||||
PrimDef::FunNpIdentity => fun("np_identity", None),
|
||||
|
||||
// NumPy NDArray property getters,
|
||||
PrimDef::FunNpShape => fun("np_shape", None),
|
||||
PrimDef::FunNpStrides => fun("np_strides", None),
|
||||
|
||||
// Miscellaneous NumPy & SciPy functions
|
||||
PrimDef::FunNpRound => fun("np_round", None),
|
||||
PrimDef::FunNpFloor => fun("np_floor", None),
|
||||
|
@ -5,7 +5,7 @@ expression: res_vec
|
||||
[
|
||||
"Class {\nname: \"Generic_A\",\nancestors: [\"Generic_A[V]\", \"B\"],\nfields: [\"aa\", \"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b:T], none]\"), (\"fun\", \"fn[[a:int32], V]\")],\ntype_vars: [\"V\"]\n}\n",
|
||||
"Function {\nname: \"Generic_A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"Generic_A.fun\",\nsig: \"fn[[a:int32], V]\",\nvar_id: [TypeVarId(241)]\n}\n",
|
||||
"Function {\nname: \"Generic_A.fun\",\nsig: \"fn[[a:int32], V]\",\nvar_id: [TypeVarId(245)]\n}\n",
|
||||
"Class {\nname: \"B\",\nancestors: [\"B\"],\nfields: [\"aa\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"foo\", \"fn[[b:T], none]\")],\ntype_vars: []\n}\n",
|
||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"B.foo\",\nsig: \"fn[[b:T], none]\",\nvar_id: []\n}\n",
|
||||
|
@ -7,7 +7,7 @@ expression: res_vec
|
||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[t:T], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"A.foo\",\nsig: \"fn[[c:C], none]\",\nvar_id: []\n}\n",
|
||||
"Class {\nname: \"B\",\nancestors: [\"B[typevar230]\", \"A[float]\"],\nfields: [\"a\", \"b\", \"c\", \"d\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: [\"typevar230\"]\n}\n",
|
||||
"Class {\nname: \"B\",\nancestors: [\"B[typevar234]\", \"A[float]\"],\nfields: [\"a\", \"b\", \"c\", \"d\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: [\"typevar234\"]\n}\n",
|
||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"B.fun\",\nsig: \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\",\nvar_id: []\n}\n",
|
||||
"Class {\nname: \"C\",\nancestors: [\"C\", \"B[bool]\", \"A[float]\"],\nfields: [\"a\", \"b\", \"c\", \"d\", \"e\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:int32, b:T], list[virtual[B[bool]]]]\"), (\"foo\", \"fn[[c:C], none]\")],\ntype_vars: []\n}\n",
|
||||
|
@ -5,8 +5,8 @@ expression: res_vec
|
||||
[
|
||||
"Function {\nname: \"foo\",\nsig: \"fn[[a:list[int32], b:tuple[T, float]], A[B, bool]]\",\nvar_id: []\n}\n",
|
||||
"Class {\nname: \"A\",\nancestors: [\"A[T, V]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[v:V], none]\"), (\"fun\", \"fn[[a:T], V]\")],\ntype_vars: [\"T\", \"V\"]\n}\n",
|
||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[v:V], none]\",\nvar_id: [TypeVarId(243)]\n}\n",
|
||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:T], V]\",\nvar_id: [TypeVarId(248)]\n}\n",
|
||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[v:V], none]\",\nvar_id: [TypeVarId(247)]\n}\n",
|
||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:T], V]\",\nvar_id: [TypeVarId(252)]\n}\n",
|
||||
"Function {\nname: \"gfun\",\nsig: \"fn[[a:A[list[float], int32]], none]\",\nvar_id: []\n}\n",
|
||||
"Class {\nname: \"B\",\nancestors: [\"B\"],\nfields: [],\nmethods: [(\"__init__\", \"fn[[], none]\")],\ntype_vars: []\n}\n",
|
||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||
|
@ -3,7 +3,7 @@ source: nac3core/src/toplevel/test.rs
|
||||
expression: res_vec
|
||||
---
|
||||
[
|
||||
"Class {\nname: \"A\",\nancestors: [\"A[typevar229, typevar230]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[a:A[float, bool], b:B], none]\"), (\"fun\", \"fn[[a:A[float, bool]], A[bool, int32]]\")],\ntype_vars: [\"typevar229\", \"typevar230\"]\n}\n",
|
||||
"Class {\nname: \"A\",\nancestors: [\"A[typevar233, typevar234]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[a:A[float, bool], b:B], none]\"), (\"fun\", \"fn[[a:A[float, bool]], A[bool, int32]]\")],\ntype_vars: [\"typevar233\", \"typevar234\"]\n}\n",
|
||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[a:A[float, bool], b:B], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[a:A[float, bool]], A[bool, int32]]\",\nvar_id: []\n}\n",
|
||||
"Class {\nname: \"B\",\nancestors: [\"B\", \"A[int64, bool]\"],\nfields: [\"a\", \"b\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[a:A[float, bool]], A[bool, int32]]\"), (\"foo\", \"fn[[b:B], B]\"), (\"bar\", \"fn[[a:A[list[B], int32]], tuple[A[virtual[A[B, int32]], bool], B]]\")],\ntype_vars: []\n}\n",
|
||||
|
@ -6,12 +6,12 @@ expression: res_vec
|
||||
"Class {\nname: \"A\",\nancestors: [\"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
|
||||
"Function {\nname: \"A.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"A.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"A.foo\",\nsig: \"fn[[a:T, b:V], none]\",\nvar_id: [TypeVarId(249)]\n}\n",
|
||||
"Function {\nname: \"A.foo\",\nsig: \"fn[[a:T, b:V], none]\",\nvar_id: [TypeVarId(253)]\n}\n",
|
||||
"Class {\nname: \"B\",\nancestors: [\"B\", \"C\", \"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
|
||||
"Function {\nname: \"B.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||
"Class {\nname: \"C\",\nancestors: [\"C\", \"A\"],\nfields: [\"a\"],\nmethods: [(\"__init__\", \"fn[[], none]\"), (\"fun\", \"fn[[b:B], none]\"), (\"foo\", \"fn[[a:T, b:V], none]\")],\ntype_vars: []\n}\n",
|
||||
"Function {\nname: \"C.__init__\",\nsig: \"fn[[], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"C.fun\",\nsig: \"fn[[b:B], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"foo\",\nsig: \"fn[[a:A], none]\",\nvar_id: []\n}\n",
|
||||
"Function {\nname: \"ff\",\nsig: \"fn[[a:T], V]\",\nvar_id: [TypeVarId(257)]\n}\n",
|
||||
"Function {\nname: \"ff\",\nsig: \"fn[[a:T], V]\",\nvar_id: [TypeVarId(261)]\n}\n",
|
||||
]
|
||||
|
@ -3,7 +3,7 @@ use std::{
|
||||
cmp::max,
|
||||
collections::{HashMap, HashSet},
|
||||
convert::{From, TryInto},
|
||||
iter::once,
|
||||
iter::{self, once},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
@ -1235,6 +1235,45 @@ impl<'a> Inferencer<'a> {
|
||||
}));
|
||||
}
|
||||
|
||||
if ["np_shape".into(), "np_strides".into()].contains(id) && args.len() == 1 {
|
||||
let ndarray = self.fold_expr(args.remove(0))?;
|
||||
|
||||
let ndims = arraylike_get_ndims(self.unifier, ndarray.custom.unwrap());
|
||||
|
||||
// Make a tuple of size `ndims` full of int32 (TODO: Make it usize)
|
||||
let ret_ty = TypeEnum::TTuple {
|
||||
ty: iter::repeat(self.primitives.int32).take(ndims as usize).collect_vec(),
|
||||
is_vararg_ctx: false,
|
||||
};
|
||||
let ret_ty = self.unifier.add_ty(ret_ty);
|
||||
|
||||
let func_ty = TypeEnum::TFunc(FunSignature {
|
||||
args: vec![FuncArg {
|
||||
name: "a".into(),
|
||||
default_value: None,
|
||||
ty: ndarray.custom.unwrap(),
|
||||
is_vararg: false,
|
||||
}],
|
||||
ret: ret_ty,
|
||||
vars: VarMap::new(),
|
||||
});
|
||||
let func_ty = self.unifier.add_ty(func_ty);
|
||||
|
||||
return Ok(Some(Located {
|
||||
location,
|
||||
custom: Some(ret_ty),
|
||||
node: ExprKind::Call {
|
||||
func: Box::new(Located {
|
||||
custom: Some(func_ty),
|
||||
location: func.location,
|
||||
node: ExprKind::Name { id: *id, ctx: *ctx },
|
||||
}),
|
||||
args: vec![ndarray],
|
||||
keywords: vec![],
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
if id == &"np_dot".into() {
|
||||
let arg0 = self.fold_expr(args.remove(0))?;
|
||||
let arg1 = self.fold_expr(args.remove(0))?;
|
||||
|
@ -179,6 +179,10 @@ def patch(module):
|
||||
module.np_identity = np.identity
|
||||
module.np_array = np.array
|
||||
|
||||
# NumPy NDArray property getters
|
||||
module.np_shape = np.shape
|
||||
module.np_strides = lambda ndarray: ndarray.strides
|
||||
|
||||
# NumPy Math functions
|
||||
module.np_isnan = np.isnan
|
||||
module.np_isinf = np.isinf
|
||||
|
Loading…
Reference in New Issue
Block a user