Manual
Built-in Ops
This section introduces the native Ops provided by PyPie.
Arithmetic
__+__: [T](x: T, y: T) -> T__-__: [T](x: T, y: T) -> T__*__: [T](x: T, y: T) -> T__/__: [T](x: T, y: T) -> T__%__: [T](x: T, y: T) -> T__**__: [T](x: T, y: T) -> TThese dunder functions are desugared infix Ops, e.g. __+__(x, y) is for x + y. They all expect two rank-0 tensors of the same element type.
larger: [T](x: T, y: T) -> Tsmaller: [T](x: T, y: T) -> TThe larger or smaller of the two.
exp: [T](x: T) -> Tsqrt: [T](x: T) -> TReducers
A reducer takes a tensor and arbitrarily many dimensions to reduce. The dimensions must be integer literals. PyPie recognizes both xs.sum(0, 1) and sum(xs, 0, 1)--they are identical.
In the result, the given dimensions are removed. E.g. if xs is a Tensor[int][[a, b, c]], then xs.sum(0, 2) is a Tensor[int][[b]]. The given dimensions may not exceed the rank of the tensor. Duplicated dimensions are accepted, as if only one is given.
A reducer expects the maximum rank on all its arguments. So rank polymorphism has no effect on reducers. PyPie provides five reducers.
sum: SpecialHandlingproduct: SpecialHandlingavg: SpecialHandlingmax: SpecialHandlingmin: SpecialHandlingTheir types are SpecialHandling because they are beyond the expressiveness of PyPie's types.
If we made up some syntax for a fully fledged dependent type, then their signatures would be something like [T, s1: List[int]] (xs: Tensor[T][s1], s2: List[int]) -> Σ(s3: List[int], Tensor[int][s3] ∧ ...)
where ... ensures that s3 contains the unreduced dimensions and preserves their orders in s1, and nothing else.
But such types are very tedious and do not help much with our usages.
Shapes
reshape: [T, s1: List[int], s2: List[int]](xs: Tensor[T][s2]]) -> Tensor[T][s2]PyPie validates s1 and s2--the products of their elements must be identical.
permute: SpecialHandlingpermute takes a tensor and arbitrarily many dimensions. It reorders the elements in the tensor. E.g. if xs is a Tensor[int][[a, b, c]], then permute(xs, 0, 2, 1) transposes the last two dimensions: Tensor[int][[a, c, b]].
The dimensions must be integer literals and each dimension in the tensor must occur once. E.g. permute(xs, 0, 1) would be a type error for missing dimension 2.permute expects the maximum rank on all its arguments.xs.permute(0, 2, 1) is identical to permute(xs, 0, 2, 1).
rep: [T](shape: List[int], x: T) -> Tensor[T][shape]Creating a Tensor of shape, filled with x.
iota: (i: int) -> Tensor[int][[i]]Creating a sequence of integers up to i - 1.
length: [T, n: int](xs: Tensor[T][[n]]) -> intconcat: [T, n: int, m: int](xs: Tensor[T][[n]], ys: Tensor[T][[m]]) -> Tensor[T][[n + m]]All shape ops also have maximum expected ranks for their inputs. But we can always customize their behavior by wrapping them in an ordinary op. E.g. given
xs = Tensor([[1, 2], [3, 4]])
ys = Tensor([[5, 6], [7, 8]])
print(concat(xs, y))
[[1, 2], [3, 4], [5, 6], [7, 8]]If we need to concatenate the inner elements, we may define
from pypie import Tensor, op @op def concat_1_1[T, m, n1, n2]( xs: Tensor[T][[m, n1]], ys: Tensor[T][[m, n2]] ) -> Tensor[T][m, n1 + n2]: return [concat(x, y) for (x, y) in zip(xs, ys)]
then we have the following.
print(concat_1_1(xs, ys))
[[1, 2, 5, 6], [3, 4, 7, 8]]Getters
__getitem__: [T, n: int](xs: Tensor[T][[n]], idx: int) -> T__getitem__(xs, idx) is the desugared form of xs[idx]. Its inputs have maximum expected ranks.
PyPie does not check if idx is smaller than n.
slice_get: [T, n: int](xs: Tensor[T][[n]], start: int, end: int) -> Tensor[T][[end - start + 1]]slice_get(xs, start, end) is the desugared form of xs[start:end]. Its inputs have maximum expected ranks.
PyPie does not check if end is not smaller than start or if n is not smaller than end - start + 1.
Random Numbers
Caveat: with PyPie's current implementation, random seeds are generated at compilation. So, running a cached PyPie artifact generates the same random numbers.
rand: [T](shape: List[int], low: T, high: T) -> Tensor[T][shape]Creating random numbers with a uniform distribution.
randn: [T](shape: List[int], mean: T, variance: T) -> Tensor[T][shape]Creating random numbers with a normal distribution.