mirror of
https://github.com/exaloop/codon.git
synced 2025-06-03 15:03:52 +08:00
293 lines
7.4 KiB
Python
293 lines
7.4 KiB
Python
|
# Copyright (C) 2022-2025 Exaloop Inc. <https://exaloop.io>
|
||
|
|
||
|
import operator
|
||
|
import util
|
||
|
|
||
|
from .ndarray import ndarray
|
||
|
from .routines import asarray
|
||
|
|
||
|
@tuple
|
||
|
class _OpWrap:
|
||
|
op: F
|
||
|
F: type
|
||
|
|
||
|
def __call__(self, a, b):
|
||
|
A = type(a)
|
||
|
B = type(b)
|
||
|
c1, c2 = util.op_types(A, B)
|
||
|
C1 = type(c1)
|
||
|
C2 = type(c2)
|
||
|
return self.op(util.cast(a, C1), util.cast(b, C2))
|
||
|
|
||
|
def _fix_scalar(x, A: type):
|
||
|
X = type(x)
|
||
|
|
||
|
a_is_int: Static[int] = (A is int or A is byte or isinstance(A, Int)
|
||
|
or isinstance(A, UInt))
|
||
|
x_is_int: Static[int] = X is int
|
||
|
|
||
|
a_is_float: Static[int] = (A is float or A is float32 or A is float16
|
||
|
or A is bfloat16 or A is float128)
|
||
|
x_is_float: Static[int] = X is float
|
||
|
|
||
|
a_is_complex: Static[int] = (A is complex or A is complex64)
|
||
|
x_is_complex: Static[int] = X is complex
|
||
|
|
||
|
should_cast: Static[int] = ((x_is_int and
|
||
|
(a_is_int or a_is_float or a_is_complex)) or
|
||
|
(x_is_float and (a_is_float or a_is_complex))
|
||
|
or (x_is_complex and a_is_complex))
|
||
|
|
||
|
if (A is float16 or A is float32) and X is complex:
|
||
|
return util.cast(x, complex64)
|
||
|
elif should_cast:
|
||
|
return util.cast(x, A)
|
||
|
else:
|
||
|
return x
|
||
|
|
||
|
@inline
|
||
|
def _binop_impl(arr: ndarray, other, op):
|
||
|
op = _OpWrap(op)
|
||
|
|
||
|
if isinstance(other, ndarray):
|
||
|
return arr._op_elemwise(other, op)
|
||
|
|
||
|
if (isinstance(other, bool) or isinstance(other, int) or
|
||
|
isinstance(other, float) or isinstance(other, complex)):
|
||
|
return arr._op_scalar(_fix_scalar(other, arr.dtype), op)
|
||
|
|
||
|
return arr._op_elemwise(asarray(other), op)
|
||
|
|
||
|
@inline
|
||
|
def _ibinop_impl(arr: ndarray, other, op):
|
||
|
op = _OpWrap(op)
|
||
|
|
||
|
if isinstance(other, ndarray):
|
||
|
return arr._iop_elemwise(other, op)
|
||
|
|
||
|
if (isinstance(other, bool) or isinstance(other, int) or
|
||
|
isinstance(other, float) or isinstance(other, complex)):
|
||
|
return arr._iop_scalar(_fix_scalar(other, arr.dtype), op)
|
||
|
|
||
|
return arr._iop_elemwise(asarray(other), op)
|
||
|
|
||
|
@inline
|
||
|
def _rbinop_impl(arr: ndarray, other, op):
|
||
|
op = _OpWrap(op)
|
||
|
|
||
|
if isinstance(other, ndarray):
|
||
|
return arr._rop_elemwise(other, op)
|
||
|
|
||
|
if (isinstance(other, bool) or isinstance(other, int) or
|
||
|
isinstance(other, float) or isinstance(other, complex)):
|
||
|
return arr._rop_scalar(_fix_scalar(other, arr.dtype), op)
|
||
|
|
||
|
return arr._rop_elemwise(asarray(other), op)
|
||
|
|
||
|
def _floor_divide(x, y):
|
||
|
X = type(x)
|
||
|
Y = type(y)
|
||
|
if isinstance(X, Int) and isinstance(Y, Int):
|
||
|
return util.pydiv(x, y)
|
||
|
else:
|
||
|
return x // y
|
||
|
|
||
|
def _remainder(x, y):
|
||
|
X = type(x)
|
||
|
Y = type(y)
|
||
|
if isinstance(X, Int) and isinstance(Y, Int):
|
||
|
return util.pymod(x, y)
|
||
|
elif ((X is float and Y is float) or
|
||
|
(X is float32 and Y is float32) or
|
||
|
(X is float16 and Y is float16)):
|
||
|
return util.pyfmod(x, y)
|
||
|
else:
|
||
|
return x % y
|
||
|
|
||
|
@extend
|
||
|
class ndarray:
|
||
|
|
||
|
@inline
|
||
|
def __add__(self, other):
|
||
|
return _binop_impl(self, other, operator.add)
|
||
|
|
||
|
@inline
|
||
|
def __radd__(self, other):
|
||
|
return _rbinop_impl(self, other, operator.add)
|
||
|
|
||
|
@inline
|
||
|
def __iadd__(self, other):
|
||
|
return _ibinop_impl(self, other, operator.add)
|
||
|
|
||
|
@inline
|
||
|
def __sub__(self, other):
|
||
|
return _binop_impl(self, other, operator.sub)
|
||
|
|
||
|
@inline
|
||
|
def __rsub__(self, other):
|
||
|
return _rbinop_impl(self, other, operator.sub)
|
||
|
|
||
|
@inline
|
||
|
def __isub__(self, other):
|
||
|
return _ibinop_impl(self, other, operator.sub)
|
||
|
|
||
|
@inline
|
||
|
def __mul__(self, other):
|
||
|
return _binop_impl(self, other, operator.mul)
|
||
|
|
||
|
@inline
|
||
|
def __rmul__(self, other):
|
||
|
return _rbinop_impl(self, other, operator.mul)
|
||
|
|
||
|
@inline
|
||
|
def __imul__(self, other):
|
||
|
return _ibinop_impl(self, other, operator.mul)
|
||
|
|
||
|
@inline
|
||
|
def __mod__(self, other):
|
||
|
return _binop_impl(self, other, _remainder)
|
||
|
|
||
|
@inline
|
||
|
def __rmod__(self, other):
|
||
|
return _rbinop_impl(self, other, _remainder)
|
||
|
|
||
|
@inline
|
||
|
def __imod__(self, other):
|
||
|
return _ibinop_impl(self, other, _remainder)
|
||
|
|
||
|
@inline
|
||
|
def __pow__(self, other):
|
||
|
return _binop_impl(self, other, operator.pow)
|
||
|
|
||
|
@inline
|
||
|
def __rpow__(self, other):
|
||
|
return _rbinop_impl(self, other, operator.pow)
|
||
|
|
||
|
@inline
|
||
|
def __ipow__(self, other):
|
||
|
return _ibinop_impl(self, other, operator.pow)
|
||
|
|
||
|
@inline
|
||
|
def __truediv__(self, other):
|
||
|
return _binop_impl(self, other, operator.truediv)
|
||
|
|
||
|
@inline
|
||
|
def __rtruediv__(self, other):
|
||
|
return _rbinop_impl(self, other, operator.truediv)
|
||
|
|
||
|
@inline
|
||
|
def __itruediv__(self, other):
|
||
|
return _ibinop_impl(self, other, operator.truediv)
|
||
|
|
||
|
@inline
|
||
|
def __floordiv__(self, other):
|
||
|
return _binop_impl(self, other, _floor_divide)
|
||
|
|
||
|
@inline
|
||
|
def __rfloordiv__(self, other):
|
||
|
return _rbinop_impl(self, other, _floor_divide)
|
||
|
|
||
|
@inline
|
||
|
def __ifloordiv__(self, other):
|
||
|
return _ibinop_impl(self, other, _floor_divide)
|
||
|
|
||
|
@inline
|
||
|
def __lshift__(self, other):
|
||
|
return _binop_impl(self, other, operator.lshift)
|
||
|
|
||
|
@inline
|
||
|
def __rlshift__(self, other):
|
||
|
return _rbinop_impl(self, other, operator.lshift)
|
||
|
|
||
|
@inline
|
||
|
def __ilshift__(self, other):
|
||
|
return _ibinop_impl(self, other, operator.lshift)
|
||
|
|
||
|
@inline
|
||
|
def __rshift__(self, other):
|
||
|
return _binop_impl(self, other, operator.rshift)
|
||
|
|
||
|
@inline
|
||
|
def __rrshift__(self, other):
|
||
|
return _rbinop_impl(self, other, operator.rshift)
|
||
|
|
||
|
@inline
|
||
|
def __irshift__(self, other):
|
||
|
return _ibinop_impl(self, other, operator.rshift)
|
||
|
|
||
|
@inline
|
||
|
def __and__(self, other):
|
||
|
return _binop_impl(self, other, operator.and_)
|
||
|
|
||
|
@inline
|
||
|
def __rand__(self, other):
|
||
|
return _rbinop_impl(self, other, operator.and_)
|
||
|
|
||
|
@inline
|
||
|
def __iand__(self, other):
|
||
|
return _ibinop_impl(self, other, operator.and_)
|
||
|
|
||
|
@inline
|
||
|
def __or__(self, other):
|
||
|
return _binop_impl(self, other, operator.or_)
|
||
|
|
||
|
@inline
|
||
|
def __ror__(self, other):
|
||
|
return _rbinop_impl(self, other, operator.or_)
|
||
|
|
||
|
@inline
|
||
|
def __ior__(self, other):
|
||
|
return _ibinop_impl(self, other, operator.or_)
|
||
|
|
||
|
@inline
|
||
|
def __xor__(self, other):
|
||
|
return _binop_impl(self, other, operator.xor)
|
||
|
|
||
|
@inline
|
||
|
def __rxor__(self, other):
|
||
|
return _rbinop_impl(self, other, operator.xor)
|
||
|
|
||
|
@inline
|
||
|
def __ixor__(self, other):
|
||
|
return _ibinop_impl(self, other, operator.xor)
|
||
|
|
||
|
@inline
|
||
|
def __pos__(self):
|
||
|
return self._op_unary(operator.pos)
|
||
|
|
||
|
@inline
|
||
|
def __neg__(self):
|
||
|
return self._op_unary(operator.neg)
|
||
|
|
||
|
@inline
|
||
|
def __invert__(self):
|
||
|
return self._op_unary(operator.invert)
|
||
|
|
||
|
@inline
|
||
|
def __abs__(self):
|
||
|
return self._op_unary(operator.abs)
|
||
|
|
||
|
@inline
|
||
|
def __eq__(self, other):
|
||
|
return _binop_impl(self, other, operator.eq)
|
||
|
|
||
|
@inline
|
||
|
def __ne__(self, other):
|
||
|
return _binop_impl(self, other, operator.ne)
|
||
|
|
||
|
@inline
|
||
|
def __lt__(self, other):
|
||
|
return _binop_impl(self, other, operator.lt)
|
||
|
|
||
|
@inline
|
||
|
def __le__(self, other):
|
||
|
return _binop_impl(self, other, operator.le)
|
||
|
|
||
|
@inline
|
||
|
def __gt__(self, other):
|
||
|
return _binop_impl(self, other, operator.gt)
|
||
|
|
||
|
@inline
|
||
|
def __ge__(self, other):
|
||
|
return _binop_impl(self, other, operator.ge)
|