diff --git a/src/copapy/__init__.py b/src/copapy/__init__.py index 1309d5f..6e6ea03 100644 --- a/src/copapy/__init__.py +++ b/src/copapy/__init__.py @@ -1,5 +1,5 @@ from ._target import Target -from ._basic_types import NumLike, variable, generic_sdb, iif +from ._basic_types import NumLike, value, generic_sdb, iif from ._vectors import vector, distance, scalar_projection, angle_between, rotate_vector, vector_projection from ._matrices import matrix, identity, zeros, ones, diagonal, eye from ._math import sqrt, abs, sign, sin, cos, tan, asin, acos, atan, atan2, log, exp, pow, get_42, clamp, min, max, relu @@ -8,7 +8,7 @@ from ._autograd import grad __all__ = [ "Target", "NumLike", - "variable", + "value", "generic_sdb", "iif", "vector", diff --git a/src/copapy/_autograd.py b/src/copapy/_autograd.py index ea5e9c4..b09da2d 100644 --- a/src/copapy/_autograd.py +++ b/src/copapy/_autograd.py @@ -1,4 +1,4 @@ -from . import variable, vector, matrix +from . import value, vector, matrix import copapy.backend as cpb from typing import Any, Sequence, overload import copapy as cp @@ -6,14 +6,14 @@ from ._basic_types import Net, unifloat @overload -def grad(x: Any, y: variable[Any]) -> unifloat: ... +def grad(x: Any, y: value[Any]) -> unifloat: ... @overload def grad(x: Any, y: vector[Any]) -> vector[float]: ... @overload -def grad(x: Any, y: Sequence[variable[Any]]) -> list[unifloat]: ... +def grad(x: Any, y: Sequence[value[Any]]) -> list[unifloat]: ... @overload def grad(x: Any, y: matrix[Any]) -> matrix[float]: ... -def grad(x: Any, y: variable[Any] | Sequence[variable[Any]] | vector[Any] | matrix[Any]) -> Any: +def grad(x: Any, y: value[Any] | Sequence[value[Any]] | vector[Any] | matrix[Any]) -> Any: """Returns the partial derivative dx/dy where x needs to be a scalar and y might be a scalar, a list of scalars, a vector or matrix. @@ -24,9 +24,9 @@ def grad(x: Any, y: variable[Any] | Sequence[variable[Any]] | vector[Any] | matr Returns: Derivative of x with the type and dimensions of y """ - assert isinstance(x, variable), f"Argument x for grad function must be a variable but is {type(x)}." + assert isinstance(x, value), f"Argument x for grad function must be a copapy value but is {type(x)}." - if isinstance(y, variable): + if isinstance(y, value): y_set = {y} if isinstance(y, matrix): y_set = {v for row in y for v in row} @@ -40,7 +40,7 @@ def grad(x: Any, y: variable[Any] | Sequence[variable[Any]] | vector[Any] | matr net_lookup = {net.source: net for node in ordered_ops for net in node.args} grad_dict: dict[Net, unifloat] = dict() - def add_grad(val: variable[Any], gradient_value: unifloat) -> None: + def add_grad(val: value[Any], gradient_value: unifloat) -> None: grad_dict[val] = grad_dict.get(val, 0.0) + gradient_value for node in reversed(ordered_ops): @@ -49,8 +49,8 @@ def grad(x: Any, y: variable[Any] | Sequence[variable[Any]] | vector[Any] | matr args: Sequence[Any] = list(node.args) g = 1.0 if node is x.source else grad_dict[net_lookup[node]] opn = node.name.split('_')[0] - a: variable[Any] = args[0] - b: variable[Any] = args[1] if len(args) > 1 else a + a: value[Any] = args[0] + b: value[Any] = args[1] if len(args) > 1 else a if opn in ['ge', 'gt', 'eq', 'ne', 'floordiv', 'bwand', 'bwor', 'bwxor']: pass # Derivative is 0 for all ops returning integers @@ -117,10 +117,10 @@ def grad(x: Any, y: variable[Any] | Sequence[variable[Any]] | vector[Any] | matr else: raise ValueError(f"Operation {opn} not yet supported for auto diff.") - if isinstance(y, variable): + if isinstance(y, value): return grad_dict[y] if isinstance(y, vector): - return vector(grad_dict[yi] if isinstance(yi, variable) else 0.0 for yi in y) + return vector(grad_dict[yi] if isinstance(yi, value) else 0.0 for yi in y) if isinstance(y, matrix): - return matrix((grad_dict[yi] if isinstance(yi, variable) else 0.0 for yi in row) for row in y) + return matrix((grad_dict[yi] if isinstance(yi, value) else 0.0 for yi in row) for row in y) return [grad_dict[yi] for yi in y] diff --git a/src/copapy/_basic_types.py b/src/copapy/_basic_types.py index 879488a..aa399dd 100644 --- a/src/copapy/_basic_types.py +++ b/src/copapy/_basic_types.py @@ -4,12 +4,12 @@ from ._stencils import stencil_database, detect_process_arch import copapy as cp from ._helper_types import TNum -NumLike: TypeAlias = 'variable[int] | variable[float] | int | float' -unifloat: TypeAlias = 'variable[float] | float' -uniint: TypeAlias = 'variable[int] | int' +NumLike: TypeAlias = 'value[int] | value[float] | int | float' +unifloat: TypeAlias = 'value[float] | float' +uniint: TypeAlias = 'value[int] | int' -TCPNum = TypeVar("TCPNum", bound='variable[Any]') -TVarNumb: TypeAlias = 'variable[Any] | int | float' +TCPNum = TypeVar("TCPNum", bound='value[Any]') +TVarNumb: TypeAlias = 'value[Any] | int | float' stencil_cache: dict[tuple[str, str], stencil_database] = {} @@ -67,7 +67,7 @@ class Node: class Net: - """A Net represents a variable in the computation graph - or more generally it + """A Net represents a scalar type in the computation graph - or more generally it connects Nodes together. Attributes: @@ -86,19 +86,19 @@ class Net: return self.source.node_hash -class variable(Generic[TNum], Net): - """A "variable" represents a typed variable. It supports arithmetic and +class value(Generic[TNum], Net): + """A "value" represents a typed scalar variable. It supports arithmetic and comparison operations. Attributes: - dtype (str): Data type of this variable. + dtype (str): Data type of this value. """ def __init__(self, source: TNum | Node, dtype: str | None = None): - """Instance a variable. + """Instance a value. Args: source: A numeric value or Node object. - dtype: Data type of this variable. Required if source is a Node. + dtype: Data type of this value. Required if source is a Node. """ if isinstance(source, Node): self.source = source @@ -115,67 +115,67 @@ class variable(Generic[TNum], Net): self.dtype = 'int' @overload - def __add__(self: 'variable[TNum]', other: 'variable[TNum] | TNum') -> 'variable[TNum]': ... + def __add__(self: 'value[TNum]', other: 'value[TNum] | TNum') -> 'value[TNum]': ... @overload - def __add__(self: 'variable[int]', other: uniint) -> 'variable[int]': ... + def __add__(self: 'value[int]', other: uniint) -> 'value[int]': ... @overload - def __add__(self, other: unifloat) -> 'variable[float]': ... + def __add__(self, other: unifloat) -> 'value[float]': ... @overload - def __add__(self: 'variable[float]', other: NumLike) -> 'variable[float]': ... + def __add__(self: 'value[float]', other: NumLike) -> 'value[float]': ... @overload - def __add__(self, other: TVarNumb) -> 'variable[float] | variable[int]': ... + def __add__(self, other: TVarNumb) -> 'value[float] | value[int]': ... def __add__(self, other: TVarNumb) -> Any: - if not isinstance(other, variable) and other == 0: + if not isinstance(other, value) and other == 0: return self return add_op('add', [self, other], True) @overload - def __radd__(self: 'variable[TNum]', other: TNum) -> 'variable[TNum]': ... + def __radd__(self: 'value[TNum]', other: TNum) -> 'value[TNum]': ... @overload - def __radd__(self: 'variable[int]', other: int) -> 'variable[int]': ... + def __radd__(self: 'value[int]', other: int) -> 'value[int]': ... @overload - def __radd__(self, other: float) -> 'variable[float]': ... + def __radd__(self, other: float) -> 'value[float]': ... def __radd__(self, other: NumLike) -> Any: return self + other @overload - def __sub__(self: 'variable[TNum]', other: 'variable[TNum] | TNum') -> 'variable[TNum]': ... + def __sub__(self: 'value[TNum]', other: 'value[TNum] | TNum') -> 'value[TNum]': ... @overload - def __sub__(self: 'variable[int]', other: uniint) -> 'variable[int]': ... + def __sub__(self: 'value[int]', other: uniint) -> 'value[int]': ... @overload - def __sub__(self, other: unifloat) -> 'variable[float]': ... + def __sub__(self, other: unifloat) -> 'value[float]': ... @overload - def __sub__(self: 'variable[float]', other: NumLike) -> 'variable[float]': ... + def __sub__(self: 'value[float]', other: NumLike) -> 'value[float]': ... @overload - def __sub__(self, other: TVarNumb) -> 'variable[float] | variable[int]': ... + def __sub__(self, other: TVarNumb) -> 'value[float] | value[int]': ... def __sub__(self, other: TVarNumb) -> Any: if isinstance(other, int | float) and other == 0: return self return add_op('sub', [self, other]) @overload - def __rsub__(self: 'variable[TNum]', other: TNum) -> 'variable[TNum]': ... + def __rsub__(self: 'value[TNum]', other: TNum) -> 'value[TNum]': ... @overload - def __rsub__(self: 'variable[int]', other: int) -> 'variable[int]': ... + def __rsub__(self: 'value[int]', other: int) -> 'value[int]': ... @overload - def __rsub__(self, other: float) -> 'variable[float]': ... + def __rsub__(self, other: float) -> 'value[float]': ... def __rsub__(self, other: NumLike) -> Any: return add_op('sub', [other, self]) @overload - def __mul__(self: 'variable[TNum]', other: 'variable[TNum] | TNum') -> 'variable[TNum]': ... + def __mul__(self: 'value[TNum]', other: 'value[TNum] | TNum') -> 'value[TNum]': ... @overload - def __mul__(self: 'variable[int]', other: uniint) -> 'variable[int]': ... + def __mul__(self: 'value[int]', other: uniint) -> 'value[int]': ... @overload - def __mul__(self, other: unifloat) -> 'variable[float]': ... + def __mul__(self, other: unifloat) -> 'value[float]': ... @overload - def __mul__(self: 'variable[float]', other: NumLike) -> 'variable[float]': ... + def __mul__(self: 'value[float]', other: NumLike) -> 'value[float]': ... @overload - def __mul__(self, other: TVarNumb) -> 'variable[float] | variable[int]': ... + def __mul__(self, other: TVarNumb) -> 'value[float] | value[int]': ... def __mul__(self, other: TVarNumb) -> Any: if self.dtype == 'float' and isinstance(other, int): other = float(other) # Prevent runtime conversion of consts; TODO: add this for other operations - if not isinstance(other, variable): + if not isinstance(other, value): if other == 1: return self elif other == 0: @@ -183,112 +183,112 @@ class variable(Generic[TNum], Net): return add_op('mul', [self, other], True) @overload - def __rmul__(self: 'variable[TNum]', other: TNum) -> 'variable[TNum]': ... + def __rmul__(self: 'value[TNum]', other: TNum) -> 'value[TNum]': ... @overload - def __rmul__(self: 'variable[int]', other: int) -> 'variable[int]': ... + def __rmul__(self: 'value[int]', other: int) -> 'value[int]': ... @overload - def __rmul__(self, other: float) -> 'variable[float]': ... + def __rmul__(self, other: float) -> 'value[float]': ... def __rmul__(self, other: NumLike) -> Any: return self * other - def __truediv__(self, other: NumLike) -> 'variable[float]': + def __truediv__(self, other: NumLike) -> 'value[float]': return add_op('div', [self, other]) - def __rtruediv__(self, other: NumLike) -> 'variable[float]': + def __rtruediv__(self, other: NumLike) -> 'value[float]': return add_op('div', [other, self]) @overload - def __floordiv__(self: 'variable[TNum]', other: 'variable[TNum] | TNum') -> 'variable[TNum]': ... + def __floordiv__(self: 'value[TNum]', other: 'value[TNum] | TNum') -> 'value[TNum]': ... @overload - def __floordiv__(self: 'variable[int]', other: uniint) -> 'variable[int]': ... + def __floordiv__(self: 'value[int]', other: uniint) -> 'value[int]': ... @overload - def __floordiv__(self, other: unifloat) -> 'variable[float]': ... + def __floordiv__(self, other: unifloat) -> 'value[float]': ... @overload - def __floordiv__(self: 'variable[float]', other: NumLike) -> 'variable[float]': ... + def __floordiv__(self: 'value[float]', other: NumLike) -> 'value[float]': ... @overload - def __floordiv__(self, other: TVarNumb) -> 'variable[float] | variable[int]': ... + def __floordiv__(self, other: TVarNumb) -> 'value[float] | value[int]': ... def __floordiv__(self, other: TVarNumb) -> Any: return add_op('floordiv', [self, other]) @overload - def __rfloordiv__(self: 'variable[TNum]', other: TNum) -> 'variable[TNum]': ... + def __rfloordiv__(self: 'value[TNum]', other: TNum) -> 'value[TNum]': ... @overload - def __rfloordiv__(self: 'variable[int]', other: int) -> 'variable[int]': ... + def __rfloordiv__(self: 'value[int]', other: int) -> 'value[int]': ... @overload - def __rfloordiv__(self, other: float) -> 'variable[float]': ... + def __rfloordiv__(self, other: float) -> 'value[float]': ... def __rfloordiv__(self, other: NumLike) -> Any: return add_op('floordiv', [other, self]) def __neg__(self: TCPNum) -> TCPNum: if self.dtype == 'int': - return cast(TCPNum, add_op('sub', [variable(0), self])) - return cast(TCPNum, add_op('sub', [variable(0.0), self])) + return cast(TCPNum, add_op('sub', [value(0), self])) + return cast(TCPNum, add_op('sub', [value(0.0), self])) - def __gt__(self, other: TVarNumb) -> 'variable[int]': + def __gt__(self, other: TVarNumb) -> 'value[int]': ret = add_op('gt', [self, other]) - return variable(ret.source, dtype='bool') + return value(ret.source, dtype='bool') - def __lt__(self, other: TVarNumb) -> 'variable[int]': + def __lt__(self, other: TVarNumb) -> 'value[int]': ret = add_op('gt', [other, self]) - return variable(ret.source, dtype='bool') + return value(ret.source, dtype='bool') - def __ge__(self, other: TVarNumb) -> 'variable[int]': + def __ge__(self, other: TVarNumb) -> 'value[int]': ret = add_op('ge', [self, other]) - return variable(ret.source, dtype='bool') + return value(ret.source, dtype='bool') - def __le__(self, other: TVarNumb) -> 'variable[int]': + def __le__(self, other: TVarNumb) -> 'value[int]': ret = add_op('ge', [other, self]) - return variable(ret.source, dtype='bool') + return value(ret.source, dtype='bool') - def __eq__(self, other: TVarNumb) -> 'variable[int]': # type: ignore + def __eq__(self, other: TVarNumb) -> 'value[int]': # type: ignore ret = add_op('eq', [self, other], True) - return variable(ret.source, dtype='bool') + return value(ret.source, dtype='bool') - def __ne__(self, other: TVarNumb) -> 'variable[int]': # type: ignore + def __ne__(self, other: TVarNumb) -> 'value[int]': # type: ignore ret = add_op('ne', [self, other], True) - return variable(ret.source, dtype='bool') + return value(ret.source, dtype='bool') @overload - def __mod__(self: 'variable[TNum]', other: 'variable[TNum] | TNum') -> 'variable[TNum]': ... + def __mod__(self: 'value[TNum]', other: 'value[TNum] | TNum') -> 'value[TNum]': ... @overload - def __mod__(self: 'variable[int]', other: uniint) -> 'variable[int]': ... + def __mod__(self: 'value[int]', other: uniint) -> 'value[int]': ... @overload - def __mod__(self, other: unifloat) -> 'variable[float]': ... + def __mod__(self, other: unifloat) -> 'value[float]': ... @overload - def __mod__(self: 'variable[float]', other: NumLike) -> 'variable[float]': ... + def __mod__(self: 'value[float]', other: NumLike) -> 'value[float]': ... @overload - def __mod__(self, other: TVarNumb) -> 'variable[float] | variable[int]': ... + def __mod__(self, other: TVarNumb) -> 'value[float] | value[int]': ... def __mod__(self, other: TVarNumb) -> Any: return add_op('mod', [self, other]) @overload - def __rmod__(self: 'variable[TNum]', other: TNum) -> 'variable[TNum]': ... + def __rmod__(self: 'value[TNum]', other: TNum) -> 'value[TNum]': ... @overload - def __rmod__(self: 'variable[int]', other: int) -> 'variable[int]': ... + def __rmod__(self: 'value[int]', other: int) -> 'value[int]': ... @overload - def __rmod__(self, other: float) -> 'variable[float]': ... + def __rmod__(self, other: float) -> 'value[float]': ... def __rmod__(self, other: NumLike) -> Any: return add_op('mod', [other, self]) @overload - def __pow__(self: 'variable[TNum]', other: 'variable[TNum] | TNum') -> 'variable[TNum]': ... + def __pow__(self: 'value[TNum]', other: 'value[TNum] | TNum') -> 'value[TNum]': ... @overload - def __pow__(self: 'variable[int]', other: uniint) -> 'variable[int]': ... + def __pow__(self: 'value[int]', other: uniint) -> 'value[int]': ... @overload - def __pow__(self, other: unifloat) -> 'variable[float]': ... + def __pow__(self, other: unifloat) -> 'value[float]': ... @overload - def __pow__(self: 'variable[float]', other: NumLike) -> 'variable[float]': ... + def __pow__(self: 'value[float]', other: NumLike) -> 'value[float]': ... @overload - def __pow__(self, other: TVarNumb) -> 'variable[float] | variable[int]': ... + def __pow__(self, other: TVarNumb) -> 'value[float] | value[int]': ... def __pow__(self, other: TVarNumb) -> Any: return cp.pow(self, other) @overload - def __rpow__(self: 'variable[TNum]', other: TNum) -> 'variable[TNum]': ... + def __rpow__(self: 'value[TNum]', other: TNum) -> 'value[TNum]': ... @overload - def __rpow__(self: 'variable[int]', other: int) -> 'variable[int]': ... + def __rpow__(self: 'value[int]', other: int) -> 'value[int]': ... @overload - def __rpow__(self, other: float) -> 'variable[float]': ... + def __rpow__(self, other: float) -> 'value[float]': ... def __rpow__(self, other: NumLike) -> Any: return cp.pow(other, self) @@ -296,34 +296,34 @@ class variable(Generic[TNum], Net): return super().__hash__() # Bitwise and shift operations for cp[int] - def __lshift__(self, other: uniint) -> 'variable[int]': + def __lshift__(self, other: uniint) -> 'value[int]': return add_op('lshift', [self, other]) - def __rlshift__(self, other: uniint) -> 'variable[int]': + def __rlshift__(self, other: uniint) -> 'value[int]': return add_op('lshift', [other, self]) - def __rshift__(self, other: uniint) -> 'variable[int]': + def __rshift__(self, other: uniint) -> 'value[int]': return add_op('rshift', [self, other]) - def __rrshift__(self, other: uniint) -> 'variable[int]': + def __rrshift__(self, other: uniint) -> 'value[int]': return add_op('rshift', [other, self]) - def __and__(self, other: uniint) -> 'variable[int]': + def __and__(self, other: uniint) -> 'value[int]': return add_op('bwand', [self, other], True) - def __rand__(self, other: uniint) -> 'variable[int]': + def __rand__(self, other: uniint) -> 'value[int]': return add_op('bwand', [other, self], True) - def __or__(self, other: uniint) -> 'variable[int]': + def __or__(self, other: uniint) -> 'value[int]': return add_op('bwor', [self, other], True) - def __ror__(self, other: uniint) -> 'variable[int]': + def __ror__(self, other: uniint) -> 'value[int]': return add_op('bwor', [other, self], True) - def __xor__(self, other: uniint) -> 'variable[int]': + def __xor__(self, other: uniint) -> 'value[int]': return add_op('bwxor', [self, other], True) - def __rxor__(self, other: uniint) -> 'variable[int]': + def __rxor__(self, other: uniint) -> 'value[int]': return add_op('bwxor', [other, self], True) @@ -356,30 +356,30 @@ class Op(Node): self.node_hash = self.get_node_hash(commutative) -def net_from_value(value: Any) -> variable[Any]: - vi = CPConstant(value) - return variable(vi, vi.dtype) +def net_from_value(val: Any) -> value[Any]: + vi = CPConstant(val) + return value(vi, vi.dtype) @overload -def iif(expression: variable[Any], true_result: uniint, false_result: uniint) -> variable[int]: ... # pyright: ignore[reportOverlappingOverload] +def iif(expression: value[Any], true_result: uniint, false_result: uniint) -> value[int]: ... # pyright: ignore[reportOverlappingOverload] @overload -def iif(expression: variable[Any], true_result: unifloat, false_result: unifloat) -> variable[float]: ... +def iif(expression: value[Any], true_result: unifloat, false_result: unifloat) -> value[float]: ... @overload def iif(expression: float | int, true_result: TNum, false_result: TNum) -> TNum: ... @overload -def iif(expression: float | int, true_result: TNum | variable[TNum], false_result: variable[TNum]) -> variable[TNum]: ... +def iif(expression: float | int, true_result: TNum | value[TNum], false_result: value[TNum]) -> value[TNum]: ... @overload -def iif(expression: float | int, true_result: variable[TNum], false_result: TNum | variable[TNum]) -> variable[TNum]: ... +def iif(expression: float | int, true_result: value[TNum], false_result: TNum | value[TNum]) -> value[TNum]: ... @overload -def iif(expression: float | int | variable[Any], true_result: TNum | variable[TNum], false_result: TNum | variable[TNum]) -> variable[TNum] | TNum: ... +def iif(expression: float | int | value[Any], true_result: TNum | value[TNum], false_result: TNum | value[TNum]) -> value[TNum] | TNum: ... def iif(expression: Any, true_result: Any, false_result: Any) -> Any: - allowed_type = (variable, int, float) + allowed_type = (value, int, float) assert isinstance(true_result, allowed_type) and isinstance(false_result, allowed_type), "Result type not supported" return (expression != 0) * true_result + (expression == 0) * false_result -def add_op(op: str, args: list[variable[Any] | int | float], commutative: bool = False) -> variable[Any]: +def add_op(op: str, args: list[value[Any] | int | float], commutative: bool = False) -> value[Any]: arg_nets = [a if isinstance(a, Net) else net_from_value(a) for a in args] if commutative: @@ -393,9 +393,9 @@ def add_op(op: str, args: list[variable[Any] | int | float], commutative: bool = result_type = generic_sdb.stencil_definitions[typed_op].split('_')[0] if result_type == 'float': - return variable[float](Op(typed_op, arg_nets, commutative), result_type) + return value[float](Op(typed_op, arg_nets, commutative), result_type) else: - return variable[int](Op(typed_op, arg_nets, commutative), result_type) + return value[int](Op(typed_op, arg_nets, commutative), result_type) def _get_data_and_dtype(value: Any) -> tuple[str, float | int]: diff --git a/src/copapy/_math.py b/src/copapy/_math.py index 03a22bf..3303ce1 100644 --- a/src/copapy/_math.py +++ b/src/copapy/_math.py @@ -1,18 +1,18 @@ from . import vector from ._vectors import VecNumLike -from . import variable, NumLike +from . import value, NumLike from typing import TypeVar, Any, overload, Callable from ._basic_types import add_op, unifloat import math -T = TypeVar("T", int, float, variable[int], variable[float]) +T = TypeVar("T", int, float, value[int], value[float]) U = TypeVar("U", int, float) @overload def exp(x: float | int) -> float: ... @overload -def exp(x: variable[Any]) -> variable[float]: ... +def exp(x: value[Any]) -> value[float]: ... @overload def exp(x: vector[Any]) -> vector[float]: ... def exp(x: Any) -> Any: @@ -24,7 +24,7 @@ def exp(x: Any) -> Any: Returns: result of e**x """ - if isinstance(x, variable): + if isinstance(x, value): return add_op('exp', [x]) if isinstance(x, vector): return x.map(exp) @@ -34,7 +34,7 @@ def exp(x: Any) -> Any: @overload def log(x: float | int) -> float: ... @overload -def log(x: variable[Any]) -> variable[float]: ... +def log(x: value[Any]) -> value[float]: ... @overload def log(x: vector[Any]) -> vector[float]: ... def log(x: Any) -> Any: @@ -46,7 +46,7 @@ def log(x: Any) -> Any: Returns: result of ln(x) """ - if isinstance(x, variable): + if isinstance(x, value): return add_op('log', [x]) if isinstance(x, vector): return x.map(log) @@ -56,9 +56,9 @@ def log(x: Any) -> Any: @overload def pow(x: float | int, y: float | int) -> float: ... @overload -def pow(x: variable[Any], y: NumLike) -> variable[float]: ... +def pow(x: value[Any], y: NumLike) -> value[float]: ... @overload -def pow(x: NumLike, y: variable[Any]) -> variable[float]: ... +def pow(x: NumLike, y: value[Any]) -> value[float]: ... @overload def pow(x: vector[Any], y: Any) -> vector[float]: ... def pow(x: VecNumLike, y: VecNumLike) -> Any: @@ -81,7 +81,7 @@ def pow(x: VecNumLike, y: VecNumLike) -> Any: return m if y == -1: return 1 / x - if isinstance(x, variable) or isinstance(y, variable): + if isinstance(x, value) or isinstance(y, value): return add_op('pow', [x, y]) else: return float(x ** y) @@ -90,7 +90,7 @@ def pow(x: VecNumLike, y: VecNumLike) -> Any: @overload def sqrt(x: float | int) -> float: ... @overload -def sqrt(x: variable[Any]) -> variable[float]: ... +def sqrt(x: value[Any]) -> value[float]: ... @overload def sqrt(x: vector[Any]) -> vector[float]: ... def sqrt(x: Any) -> Any: @@ -102,7 +102,7 @@ def sqrt(x: Any) -> Any: Returns: Square root of x """ - if isinstance(x, variable): + if isinstance(x, value): return add_op('sqrt', [x]) if isinstance(x, vector): return x.map(sqrt) @@ -112,7 +112,7 @@ def sqrt(x: Any) -> Any: @overload def sin(x: float | int) -> float: ... @overload -def sin(x: variable[Any]) -> variable[float]: ... +def sin(x: value[Any]) -> value[float]: ... @overload def sin(x: vector[Any]) -> vector[float]: ... def sin(x: Any) -> Any: @@ -124,7 +124,7 @@ def sin(x: Any) -> Any: Returns: Square root of x """ - if isinstance(x, variable): + if isinstance(x, value): return add_op('sin', [x]) if isinstance(x, vector): return x.map(sin) @@ -134,7 +134,7 @@ def sin(x: Any) -> Any: @overload def cos(x: float | int) -> float: ... @overload -def cos(x: variable[Any]) -> variable[float]: ... +def cos(x: value[Any]) -> value[float]: ... @overload def cos(x: vector[Any]) -> vector[float]: ... def cos(x: Any) -> Any: @@ -146,7 +146,7 @@ def cos(x: Any) -> Any: Returns: Cosine of x """ - if isinstance(x, variable): + if isinstance(x, value): return add_op('cos', [x]) if isinstance(x, vector): return x.map(cos) @@ -156,7 +156,7 @@ def cos(x: Any) -> Any: @overload def tan(x: float | int) -> float: ... @overload -def tan(x: variable[Any]) -> variable[float]: ... +def tan(x: value[Any]) -> value[float]: ... @overload def tan(x: vector[Any]) -> vector[float]: ... def tan(x: Any) -> Any: @@ -168,7 +168,7 @@ def tan(x: Any) -> Any: Returns: Tangent of x """ - if isinstance(x, variable): + if isinstance(x, value): return add_op('tan', [x]) if isinstance(x, vector): #return x.map(tan) @@ -179,7 +179,7 @@ def tan(x: Any) -> Any: @overload def atan(x: float | int) -> float: ... @overload -def atan(x: variable[Any]) -> variable[float]: ... +def atan(x: value[Any]) -> value[float]: ... @overload def atan(x: vector[Any]) -> vector[float]: ... def atan(x: Any) -> Any: @@ -191,7 +191,7 @@ def atan(x: Any) -> Any: Returns: Inverse tangent of x """ - if isinstance(x, variable): + if isinstance(x, value): return add_op('atan', [x]) if isinstance(x, vector): return x.map(atan) @@ -201,9 +201,9 @@ def atan(x: Any) -> Any: @overload def atan2(x: float | int, y: float | int) -> float: ... @overload -def atan2(x: variable[Any], y: NumLike) -> variable[float]: ... +def atan2(x: value[Any], y: NumLike) -> value[float]: ... @overload -def atan2(x: NumLike, y: variable[Any]) -> variable[float]: ... +def atan2(x: NumLike, y: value[Any]) -> value[float]: ... @overload def atan2(x: vector[float], y: VecNumLike) -> vector[float]: ... @overload @@ -220,7 +220,7 @@ def atan2(x: VecNumLike, y: VecNumLike) -> Any: """ if isinstance(x, vector) or isinstance(y, vector): return _map2(x, y, atan2) - if isinstance(x, variable) or isinstance(y, variable): + if isinstance(x, value) or isinstance(y, value): return add_op('atan2', [x, y]) return math.atan2(x, y) @@ -228,7 +228,7 @@ def atan2(x: VecNumLike, y: VecNumLike) -> Any: @overload def asin(x: float | int) -> float: ... @overload -def asin(x: variable[Any]) -> variable[float]: ... +def asin(x: value[Any]) -> value[float]: ... @overload def asin(x: vector[Any]) -> vector[float]: ... def asin(x: Any) -> Any: @@ -240,7 +240,7 @@ def asin(x: Any) -> Any: Returns: Inverse sine of x """ - if isinstance(x, variable): + if isinstance(x, value): return add_op('asin', [x]) if isinstance(x, vector): return x.map(asin) @@ -250,7 +250,7 @@ def asin(x: Any) -> Any: @overload def acos(x: float | int) -> float: ... @overload -def acos(x: variable[Any]) -> variable[float]: ... +def acos(x: value[Any]) -> value[float]: ... @overload def acos(x: vector[Any]) -> vector[float]: ... def acos(x: Any) -> Any: @@ -262,7 +262,7 @@ def acos(x: Any) -> Any: Returns: Inverse cosine of x """ - if isinstance(x, variable): + if isinstance(x, value): return add_op('acos', [x]) if isinstance(x, vector): return x.map(acos) @@ -272,10 +272,10 @@ def acos(x: Any) -> Any: @overload def get_42(x: float | int) -> float: ... @overload -def get_42(x: variable[Any]) -> variable[float]: ... -def get_42(x: NumLike) -> variable[float] | float: - """Returns the variable representing the constant 42""" - if isinstance(x, variable): +def get_42(x: value[Any]) -> value[float]: ... +def get_42(x: NumLike) -> value[float] | float: + """Returns the value representing the constant 42""" + if isinstance(x, value): return add_op('get_42', [x, x]) return float((int(x) * 3.0 + 42.0) * 5.0 + 21.0) @@ -284,10 +284,10 @@ def get_42(x: NumLike) -> variable[float] | float: @overload def abs(x: U) -> U: ... @overload -def abs(x: variable[U]) -> variable[U]: ... +def abs(x: value[U]) -> value[U]: ... @overload def abs(x: vector[U]) -> vector[U]: ... -def abs(x: U | variable[U] | vector[U]) -> Any: +def abs(x: U | value[U] | vector[U]) -> Any: """Absolute value function Arguments: @@ -304,10 +304,10 @@ def abs(x: U | variable[U] | vector[U]) -> Any: @overload def sign(x: U) -> U: ... @overload -def sign(x: variable[U]) -> variable[U]: ... +def sign(x: value[U]) -> value[U]: ... @overload def sign(x: vector[U]) -> vector[U]: ... -def sign(x: U | variable[U] | vector[U]) -> Any: +def sign(x: U | value[U] | vector[U]) -> Any: """Return 1 for positive numbers and -1 for negative numbers. For an input of 0 the return value is 0. @@ -322,16 +322,16 @@ def sign(x: U | variable[U] | vector[U]) -> Any: @overload -def clamp(x: variable[U], min_value: U | variable[U], max_value: U | variable[U]) -> variable[U]: ... +def clamp(x: value[U], min_value: U | value[U], max_value: U | value[U]) -> value[U]: ... @overload -def clamp(x: U | variable[U], min_value: variable[U], max_value: U | variable[U]) -> variable[U]: ... +def clamp(x: U | value[U], min_value: value[U], max_value: U | value[U]) -> value[U]: ... @overload -def clamp(x: U | variable[U], min_value: U | variable[U], max_value: variable[U]) -> variable[U]: ... +def clamp(x: U | value[U], min_value: U | value[U], max_value: value[U]) -> value[U]: ... @overload def clamp(x: U, min_value: U, max_value: U) -> U: ... @overload -def clamp(x: vector[U], min_value: 'U | variable[U]', max_value: 'U | variable[U]') -> vector[U]: ... -def clamp(x: U | variable[U] | vector[U], min_value: U | variable[U], max_value: U | variable[U]) -> Any: +def clamp(x: vector[U], min_value: 'U | value[U]', max_value: 'U | value[U]') -> vector[U]: ... +def clamp(x: U | value[U] | vector[U], min_value: U | value[U], max_value: U | value[U]) -> Any: """Clamp function to limit a value between a minimum and maximum. Arguments: @@ -351,12 +351,12 @@ def clamp(x: U | variable[U] | vector[U], min_value: U | variable[U], max_value: @overload -def min(x: variable[U], y: U | variable[U]) -> variable[U]: ... +def min(x: value[U], y: U | value[U]) -> value[U]: ... @overload -def min(x: U | variable[U], y: variable[U]) -> variable[U]: ... +def min(x: U | value[U], y: value[U]) -> value[U]: ... @overload def min(x: U, y: U) -> U: ... -def min(x: U | variable[U], y: U | variable[U]) -> Any: +def min(x: U | value[U], y: U | value[U]) -> Any: """Minimum function to get the smaller of two values. Arguments: @@ -370,12 +370,12 @@ def min(x: U | variable[U], y: U | variable[U]) -> Any: @overload -def max(x: variable[U], y: U | variable[U]) -> variable[U]: ... +def max(x: value[U], y: U | value[U]) -> value[U]: ... @overload -def max(x: U | variable[U], y: variable[U]) -> variable[U]: ... +def max(x: U | value[U], y: value[U]) -> value[U]: ... @overload def max(x: U, y: U) -> U: ... -def max(x: U | variable[U], y: U | variable[U]) -> Any: +def max(x: U | value[U], y: U | value[U]) -> Any: """Maximum function to get the larger of two values. Arguments: @@ -389,16 +389,16 @@ def max(x: U | variable[U], y: U | variable[U]) -> Any: @overload -def lerp(v1: variable[U], v2: U | variable[U], t: unifloat) -> variable[U]: ... +def lerp(v1: value[U], v2: U | value[U], t: unifloat) -> value[U]: ... @overload -def lerp(v1: U | variable[U], v2: variable[U], t: unifloat) -> variable[U]: ... +def lerp(v1: U | value[U], v2: value[U], t: unifloat) -> value[U]: ... @overload -def lerp(v1: U | variable[U], v2: U | variable[U], t: variable[float]) -> variable[U]: ... +def lerp(v1: U | value[U], v2: U | value[U], t: value[float]) -> value[U]: ... @overload def lerp(v1: U, v2: U, t: float) -> U: ... @overload def lerp(v1: vector[U], v2: vector[U], t: unifloat) -> vector[U]: ... -def lerp(v1: U | variable[U] | vector[U], v2: U | variable[U] | vector[U], t: unifloat) -> Any: +def lerp(v1: U | value[U] | vector[U], v2: U | value[U] | vector[U], t: unifloat) -> Any: """Linearly interpolate between two values or vectors v1 and v2 by a factor t.""" if isinstance(v1, vector) or isinstance(v2, vector): assert isinstance(v1, vector) and isinstance(v2, vector), "None or both v1 and v2 must be vectors." @@ -410,16 +410,16 @@ def lerp(v1: U | variable[U] | vector[U], v2: U | variable[U] | vector[U], t: u @overload def relu(x: U) -> U: ... @overload -def relu(x: variable[U]) -> variable[U]: ... +def relu(x: value[U]) -> value[U]: ... @overload def relu(x: vector[U]) -> vector[U]: ... -def relu(x: U | variable[U] | vector[U]) -> Any: +def relu(x: U | value[U] | vector[U]) -> Any: """Returns x for x > 0 and otherwise 0.""" ret = (x > 0) * x return ret -def _map2(self: VecNumLike, other: VecNumLike, func: Callable[[Any, Any], variable[U] | U]) -> vector[U]: +def _map2(self: VecNumLike, other: VecNumLike, func: Callable[[Any, Any], value[U] | U]) -> vector[U]: """Applies a function to each element of the vector and a second vector or scalar.""" if isinstance(self, vector) and isinstance(other, vector): return vector(func(x, y) for x, y in zip(self.values, other.values)) diff --git a/src/copapy/_matrices.py b/src/copapy/_matrices.py index 773ac38..a5505a7 100644 --- a/src/copapy/_matrices.py +++ b/src/copapy/_matrices.py @@ -1,23 +1,23 @@ -from . import variable +from . import value from ._vectors import vector from ._mixed import mixed_sum from typing import TypeVar, Iterable, Any, overload, TypeAlias, Callable, Iterator, Generic from ._helper_types import TNum -MatNumLike: TypeAlias = 'matrix[int] | matrix[float] | variable[int] | variable[float] | int | float' -MatIntLike: TypeAlias = 'matrix[int] | variable[int] | int' -MatFloatLike: TypeAlias = 'matrix[float] | variable[float] | float' +MatNumLike: TypeAlias = 'matrix[int] | matrix[float] | value[int] | value[float] | int | float' +MatIntLike: TypeAlias = 'matrix[int] | value[int] | int' +MatFloatLike: TypeAlias = 'matrix[float] | value[float] | float' U = TypeVar("U", int, float) class matrix(Generic[TNum]): - """Mathematical matrix class supporting basic operations and interactions with variables. + """Mathematical matrix class supporting basic operations and interactions with values. """ - def __init__(self, values: Iterable[Iterable[TNum | variable[TNum]]] | vector[TNum]): - """Create a matrix with given values and variables. + def __init__(self, values: Iterable[Iterable[TNum | value[TNum]]] | vector[TNum]): + """Create a matrix with given values. Args: - values: iterable of iterable of constant values and variables + values: iterable of iterable of constant values """ if isinstance(values, vector): rows = [values.values] @@ -27,7 +27,7 @@ class matrix(Generic[TNum]): if rows: row_len = len(rows[0]) assert all(len(row) == row_len for row in rows), "All rows must have the same length" - self.values: tuple[tuple[variable[TNum] | TNum, ...], ...] = tuple(rows) + self.values: tuple[tuple[value[TNum] | TNum, ...], ...] = tuple(rows) self.rows = len(self.values) self.cols = len(self.values[0]) if self.values else 0 @@ -41,7 +41,7 @@ class matrix(Generic[TNum]): @overload def __getitem__(self, key: int) -> vector[TNum]: ... @overload - def __getitem__(self, key: tuple[int, int]) -> variable[TNum] | TNum: ... + def __getitem__(self, key: tuple[int, int]) -> value[TNum] | TNum: ... def __getitem__(self, key: int | tuple[int, int]) -> Any: """Get a row as a vector or a specific element. Args: @@ -56,7 +56,7 @@ class matrix(Generic[TNum]): else: return vector(self.values[key]) - def __iter__(self) -> Iterator[tuple[variable[TNum] | TNum, ...]]: + def __iter__(self) -> Iterator[tuple[value[TNum] | TNum, ...]]: return iter(self.values) def __neg__(self) -> 'matrix[TNum]': @@ -86,7 +86,7 @@ class matrix(Generic[TNum]): @overload def __radd__(self: 'matrix[float]', other: MatNumLike) -> 'matrix[float]': ... @overload - def __radd__(self: 'matrix[int]', other: variable[int] | int) -> 'matrix[int]': ... + def __radd__(self: 'matrix[int]', other: value[int] | int) -> 'matrix[int]': ... def __radd__(self, other: Any) -> Any: return self + other @@ -114,7 +114,7 @@ class matrix(Generic[TNum]): @overload def __rsub__(self: 'matrix[float]', other: MatNumLike) -> 'matrix[float]': ... @overload - def __rsub__(self: 'matrix[int]', other: variable[int] | int) -> 'matrix[int]': ... + def __rsub__(self: 'matrix[int]', other: value[int] | int) -> 'matrix[int]': ... def __rsub__(self, other: MatNumLike) -> Any: if isinstance(other, matrix): assert self.rows == other.rows and self.cols == other.cols, \ @@ -153,7 +153,7 @@ class matrix(Generic[TNum]): @overload def __rmul__(self: 'matrix[float]', other: MatNumLike) -> 'matrix[float]': ... @overload - def __rmul__(self: 'matrix[int]', other: variable[int] | int) -> 'matrix[int]': ... + def __rmul__(self: 'matrix[int]', other: value[int] | int) -> 'matrix[int]': ... def __rmul__(self, other: MatNumLike) -> Any: return self * other @@ -199,9 +199,9 @@ class matrix(Generic[TNum]): assert isinstance(other, matrix), "Cannot multiply matrix with {type(other)}" assert self.cols == other.rows, \ f"Matrix columns ({self.cols}) must match other matrix rows ({other.rows})" - result: list[list[TNum | variable[TNum]]] = [] + result: list[list[TNum | value[TNum]]] = [] for row in self.values: - new_row: list[TNum | variable[TNum]] = [] + new_row: list[TNum | value[TNum]] = [] for col_idx in range(other.cols): col = tuple(other.values[i][col_idx] for i in range(other.rows)) element = sum(a * b for a, b in zip(row, col)) @@ -238,27 +238,27 @@ class matrix(Generic[TNum]): return vector(self.values[i][index] for i in range(self.rows)) @overload - def trace(self: 'matrix[TNum]') -> TNum | variable[TNum]: ... + def trace(self: 'matrix[TNum]') -> TNum | value[TNum]: ... @overload - def trace(self: 'matrix[int]') -> int | variable[int]: ... + def trace(self: 'matrix[int]') -> int | value[int]: ... @overload - def trace(self: 'matrix[float]') -> float | variable[float]: ... + def trace(self: 'matrix[float]') -> float | value[float]: ... def trace(self) -> Any: """Calculate the trace (sum of diagonal elements).""" assert self.rows == self.cols, "Trace is only defined for square matrices" return mixed_sum(self.values[i][i] for i in range(self.rows)) @overload - def sum(self: 'matrix[TNum]') -> TNum | variable[TNum]: ... + def sum(self: 'matrix[TNum]') -> TNum | value[TNum]: ... @overload - def sum(self: 'matrix[int]') -> int | variable[int]: ... + def sum(self: 'matrix[int]') -> int | value[int]: ... @overload - def sum(self: 'matrix[float]') -> float | variable[float]: ... + def sum(self: 'matrix[float]') -> float | value[float]: ... def sum(self) -> Any: """Calculate the sum of all elements.""" return mixed_sum(a for row in self.values for a in row) - def map(self, func: Callable[[Any], variable[U] | U]) -> 'matrix[U]': + def map(self, func: Callable[[Any], value[U] | U]) -> 'matrix[U]': """Applies a function to each element of the matrix and returns a new matrix.""" return matrix( tuple(func(a) for a in row) @@ -266,10 +266,10 @@ class matrix(Generic[TNum]): ) def homogenize(self) -> 'matrix[TNum]': - """Convert all elements to variables if any element is a variable.""" - if any(isinstance(val, variable) for row in self.values for val in row): + """Convert all elements to copapy values if any element is a copapy value.""" + if any(isinstance(val, value) for row in self.values for val in row): return matrix( - tuple(variable(val) if not isinstance(val, variable) else val for val in row) + tuple(value(val) if not isinstance(val, value) else val for val in row) for row in self.values ) else: diff --git a/src/copapy/_mixed.py b/src/copapy/_mixed.py index e4d2632..5b84e93 100644 --- a/src/copapy/_mixed.py +++ b/src/copapy/_mixed.py @@ -1,24 +1,24 @@ -from . import variable +from . import value from typing import TypeVar, Iterable, Any, overload T = TypeVar("T", int, float) @overload -def mixed_sum(scalars: Iterable[float | variable[float]]) -> float | variable[float]: ... +def mixed_sum(scalars: Iterable[float | value[float]]) -> float | value[float]: ... @overload -def mixed_sum(scalars: Iterable[int | variable[int]]) -> int | variable[int]: ... +def mixed_sum(scalars: Iterable[int | value[int]]) -> int | value[int]: ... @overload -def mixed_sum(scalars: Iterable[T | variable[T]]) -> T | variable[T]: ... -def mixed_sum(scalars: Iterable[int | float | variable[Any]]) -> Any: +def mixed_sum(scalars: Iterable[T | value[T]]) -> T | value[T]: ... +def mixed_sum(scalars: Iterable[int | float | value[Any]]) -> Any: sl = list(scalars) - return sum(a for a in sl if not isinstance(a, variable)) +\ - sum(a for a in sl if isinstance(a, variable)) + return sum(a for a in sl if not isinstance(a, value)) +\ + sum(a for a in sl if isinstance(a, value)) -def mixed_homogenize(scalars: Iterable[T | variable[T]]) -> Iterable[T] | Iterable[variable[T]]: - if any(isinstance(val, variable) for val in scalars): - return (variable(val) if not isinstance(val, variable) else val for val in scalars) +def mixed_homogenize(scalars: Iterable[T | value[T]]) -> Iterable[T] | Iterable[value[T]]: + if any(isinstance(val, value) for val in scalars): + return (value(val) if not isinstance(val, value) else val for val in scalars) else: - return (val for val in scalars if not isinstance(val, variable)) + return (val for val in scalars if not isinstance(val, value)) diff --git a/src/copapy/_target.py b/src/copapy/_target.py index d2bbed4..be0e6a1 100644 --- a/src/copapy/_target.py +++ b/src/copapy/_target.py @@ -3,7 +3,7 @@ from . import _binwrite as binw from coparun_module import coparun, read_data_mem import struct from ._basic_types import stencil_db_from_package -from ._basic_types import variable, Net, Node, Write, NumLike +from ._basic_types import value, Net, Node, Write, NumLike from ._compiler import compile_to_dag T = TypeVar("T", int, float) @@ -28,16 +28,16 @@ class Target(): optimization: Optimization level """ self.sdb = stencil_db_from_package(arch, optimization) - self._variables: dict[Net, tuple[int, int, str]] = {} + self._values: dict[Net, tuple[int, int, str]] = {} - def compile(self, *variables: int | float | variable[int] | variable[float] | Iterable[int | float | variable[int] | variable[float]]) -> None: - """Compiles the code to compute the given variables. + def compile(self, *values: int | float | value[int] | value[float] | Iterable[int | float | value[int] | value[float]]) -> None: + """Compiles the code to compute the given values. Arguments: - variables: Variables to compute + values: Values to compute """ nodes: list[Node] = [] - for s in variables: + for s in values: if isinstance(s, Iterable): for net in s: if isinstance(net, Net): @@ -46,7 +46,7 @@ class Target(): if isinstance(s, Net): nodes.append(Write(s)) - dw, self._variables = compile_to_dag(nodes, self.sdb) + dw, self._values = compile_to_dag(nodes, self.sdb) dw.write_com(binw.Command.END_COM) assert coparun(dw.get_data()) > 0 @@ -59,56 +59,56 @@ class Target(): assert coparun(dw.get_data()) > 0 @overload - def read_value(self, net: variable[T]) -> T: ... + def read_value(self, net: value[T]) -> T: ... @overload def read_value(self, net: NumLike) -> float | int | bool: ... @overload - def read_value(self, net: Iterable[T | variable[T]]) -> list[T]: ... - def read_value(self, net: NumLike | variable[T] | Iterable[T | variable[T]]) -> Any: - """Reads the value of a variable. + def read_value(self, net: Iterable[T | value[T]]) -> list[T]: ... + def read_value(self, net: NumLike | value[T] | Iterable[T | value[T]]) -> Any: + """Reads the numeric value of a copapy type. Arguments: - net: Variable to read + net: Values to read Returns: - Value of the variable + Numeric value """ if isinstance(net, Iterable): - return [self.read_value(ni) if isinstance(ni, variable) else ni for ni in net] + return [self.read_value(ni) if isinstance(ni, value) else ni for ni in net] if isinstance(net, float | int): print("Warning: value is not a copypy value") return net - assert isinstance(net, Net), "Variable must be a copapy variable object" - assert net in self._variables, f"Variable {net} not found. It might not have been compiled for the target." - addr, lengths, var_type = self._variables[net] + assert isinstance(net, Net), "Argument must be a copapy value" + assert net in self._values, f"Value {net} not found. It might not have been compiled for the target." + addr, lengths, var_type = self._values[net] assert lengths > 0 data = read_data_mem(addr, lengths) - assert data is not None and len(data) == lengths, f"Failed to read variable {net}" + assert data is not None and len(data) == lengths, f"Failed to read value {net}" en = {'little': '<', 'big': '>'}[self.sdb.byteorder] if var_type == 'float': if lengths == 4: - value = struct.unpack(en + 'f', data)[0] + val = struct.unpack(en + 'f', data)[0] elif lengths == 8: - value = struct.unpack(en + 'd', data)[0] + val = struct.unpack(en + 'd', data)[0] else: raise ValueError(f"Unsupported float length: {lengths} bytes") - assert isinstance(value, float) - return value + assert isinstance(val, float) + return val elif var_type == 'int': assert lengths in (1, 2, 4, 8), f"Unsupported int length: {lengths} bytes" - value = int.from_bytes(data, byteorder=self.sdb.byteorder, signed=True) - return value + val = int.from_bytes(data, byteorder=self.sdb.byteorder, signed=True) + return val elif var_type == 'bool': assert lengths in (1, 2, 4, 8), f"Unsupported int length: {lengths} bytes" - value = bool.from_bytes(data, byteorder=self.sdb.byteorder, signed=True) - return value + val = bool.from_bytes(data, byteorder=self.sdb.byteorder, signed=True) + return val else: - raise ValueError(f"Unsupported variable type: {var_type}") + raise ValueError(f"Unsupported value type: {var_type}") def read_value_remote(self, net: Net) -> None: - """Reads the raw data of a variable by the runner.""" + """Reads the raw data of a value by the runner.""" dw = binw.data_writer(self.sdb.byteorder) - add_read_command(dw, self._variables, net) + add_read_command(dw, self._values, net) assert coparun(dw.get_data()) > 0 diff --git a/src/copapy/_vectors.py b/src/copapy/_vectors.py index 44d5869..ced1137 100644 --- a/src/copapy/_vectors.py +++ b/src/copapy/_vectors.py @@ -1,28 +1,28 @@ -from . import variable +from . import value from ._mixed import mixed_sum, mixed_homogenize from typing import TypeVar, Iterable, Any, overload, TypeAlias, Callable, Iterator, Generic import copapy as cp from ._helper_types import TNum -#VecNumLike: TypeAlias = 'vector[int] | vector[float] | variable[int] | variable[float] | int | float | bool' -VecNumLike: TypeAlias = 'vector[Any] | variable[Any] | int | float | bool' -VecIntLike: TypeAlias = 'vector[int] | variable[int] | int' -VecFloatLike: TypeAlias = 'vector[float] | variable[float] | float' +#VecNumLike: TypeAlias = 'vector[int] | vector[float] | value[int] | value[float] | int | float | bool' +VecNumLike: TypeAlias = 'vector[Any] | value[Any] | int | float | bool' +VecIntLike: TypeAlias = 'vector[int] | value[int] | int' +VecFloatLike: TypeAlias = 'vector[float] | value[float] | float' U = TypeVar("U", int, float) epsilon = 1e-20 class vector(Generic[TNum]): - """Mathematical vector class supporting basic operations and interactions with variables. + """Mathematical vector class supporting basic operations and interactions with values. """ - def __init__(self, values: Iterable[TNum | variable[TNum]]): - """Create a vector with given values and variables. + def __init__(self, values: Iterable[TNum | value[TNum]]): + """Create a vector with given values. Args: - values: iterable of constant values and variables + values: iterable of constant values """ - self.values: tuple[variable[TNum] | TNum, ...] = tuple(values) + self.values: tuple[value[TNum] | TNum, ...] = tuple(values) def __repr__(self) -> str: return f"vector({self.values})" @@ -31,10 +31,10 @@ class vector(Generic[TNum]): return len(self.values) @overload - def __getitem__(self, index: int) -> variable[TNum] | TNum: ... + def __getitem__(self, index: int) -> value[TNum] | TNum: ... @overload def __getitem__(self, index: slice) -> 'vector[TNum]': ... - def __getitem__(self, index: int | slice) -> 'vector[TNum] | variable[TNum] | TNum': + def __getitem__(self, index: int | slice) -> 'vector[TNum] | value[TNum] | TNum': if isinstance(index, slice): return vector(self.values[index]) return self.values[index] @@ -42,7 +42,7 @@ class vector(Generic[TNum]): def __neg__(self) -> 'vector[TNum]': return vector(-a for a in self.values) - def __iter__(self) -> Iterator[variable[TNum] | TNum]: + def __iter__(self) -> Iterator[value[TNum] | TNum]: return iter(self.values) @overload @@ -62,7 +62,7 @@ class vector(Generic[TNum]): @overload def __radd__(self: 'vector[float]', other: VecNumLike) -> 'vector[float]': ... @overload - def __radd__(self: 'vector[int]', other: variable[int] | int) -> 'vector[int]': ... + def __radd__(self: 'vector[int]', other: value[int] | int) -> 'vector[int]': ... @overload def __radd__(self, other: VecNumLike) -> 'vector[Any]': ... def __radd__(self, other: Any) -> Any: @@ -85,7 +85,7 @@ class vector(Generic[TNum]): @overload def __rsub__(self: 'vector[float]', other: VecNumLike) -> 'vector[float]': ... @overload - def __rsub__(self: 'vector[int]', other: variable[int] | int) -> 'vector[int]': ... + def __rsub__(self: 'vector[int]', other: value[int] | int) -> 'vector[int]': ... @overload def __rsub__(self, other: VecNumLike) -> 'vector[Any]': ... def __rsub__(self, other: VecNumLike) -> Any: @@ -111,7 +111,7 @@ class vector(Generic[TNum]): @overload def __rmul__(self: 'vector[float]', other: VecNumLike) -> 'vector[float]': ... @overload - def __rmul__(self: 'vector[int]', other: variable[int] | int) -> 'vector[int]': ... + def __rmul__(self: 'vector[int]', other: value[int] | int) -> 'vector[int]': ... @overload def __rmul__(self, other: VecNumLike) -> 'vector[Any]': ... def __rmul__(self, other: VecNumLike) -> Any: @@ -134,7 +134,7 @@ class vector(Generic[TNum]): @overload def __rpow__(self: 'vector[float]', other: VecNumLike) -> 'vector[float]': ... @overload - def __rpow__(self: 'vector[int]', other: variable[int] | int) -> 'vector[int]': ... + def __rpow__(self: 'vector[int]', other: value[int] | int) -> 'vector[int]': ... @overload def __rpow__(self, other: VecNumLike) -> 'vector[Any]': ... def __rpow__(self, other: VecNumLike) -> Any: @@ -153,26 +153,26 @@ class vector(Generic[TNum]): return vector(other / a for a in self.values) @overload - def dot(self: 'vector[int]', other: 'vector[int]') -> int | variable[int]: ... + def dot(self: 'vector[int]', other: 'vector[int]') -> int | value[int]: ... @overload - def dot(self, other: 'vector[float]') -> float | variable[float]: ... + def dot(self, other: 'vector[float]') -> float | value[float]: ... @overload - def dot(self: 'vector[float]', other: 'vector[int] | vector[float]') -> float | variable[float]: ... + def dot(self: 'vector[float]', other: 'vector[int] | vector[float]') -> float | value[float]: ... @overload - def dot(self, other: 'vector[int] | vector[float]') -> float | int | variable[float] | variable[int]: ... + def dot(self, other: 'vector[int] | vector[float]') -> float | int | value[float] | value[int]: ... def dot(self, other: 'vector[int] | vector[float]') -> Any: assert len(self.values) == len(other.values), "Vectors must be of same length." return mixed_sum(a * b for a, b in zip(self.values, other.values)) # @ operator @overload - def __matmul__(self: 'vector[int]', other: 'vector[int]') -> int | variable[int]: ... + def __matmul__(self: 'vector[int]', other: 'vector[int]') -> int | value[int]: ... @overload - def __matmul__(self, other: 'vector[float]') -> float | variable[float]: ... + def __matmul__(self, other: 'vector[float]') -> float | value[float]: ... @overload - def __matmul__(self: 'vector[float]', other: 'vector[int] | vector[float]') -> float | variable[float]: ... + def __matmul__(self: 'vector[float]', other: 'vector[int] | vector[float]') -> float | value[float]: ... @overload - def __matmul__(self, other: 'vector[int] | vector[float]') -> float | int | variable[float] | variable[int]: ... + def __matmul__(self, other: 'vector[int] | vector[float]') -> float | int | value[float] | value[int]: ... def __matmul__(self, other: 'vector[int] | vector[float]') -> Any: return self.dot(other) @@ -229,14 +229,14 @@ class vector(Generic[TNum]): return (len(self.values),) @overload - def sum(self: 'vector[int]') -> int | variable[int]: ... + def sum(self: 'vector[int]') -> int | value[int]: ... @overload - def sum(self: 'vector[float]') -> float | variable[float]: ... + def sum(self: 'vector[float]') -> float | value[float]: ... def sum(self) -> Any: """Sum of all vector elements.""" return mixed_sum(self.values) - def magnitude(self) -> 'float | variable[float]': + def magnitude(self) -> 'float | value[float]': """Magnitude (length) of the vector.""" s = mixed_sum(a * a for a in self.values) return cp.sqrt(s) @@ -247,12 +247,12 @@ class vector(Generic[TNum]): return self / mag def homogenize(self) -> 'vector[TNum]': - if any(isinstance(val, variable) for val in self.values): + if any(isinstance(val, value) for val in self.values): return vector(mixed_homogenize(self)) else: return self - def map(self, func: Callable[[Any], variable[U] | U]) -> 'vector[U]': + def map(self, func: Callable[[Any], value[U] | U]) -> 'vector[U]': """Applies a function to each element of the vector and returns a new vector.""" return vector(func(x) for x in self.values) @@ -262,18 +262,18 @@ def cross_product(v1: vector[float], v2: vector[float]) -> vector[float]: return v1.cross(v2) -def dot_product(v1: vector[float], v2: vector[float]) -> 'float | variable[float]': +def dot_product(v1: vector[float], v2: vector[float]) -> 'float | value[float]': """Calculate the dot product of two vectors.""" return v1.dot(v2) -def distance(v1: vector[float], v2: vector[float]) -> 'float | variable[float]': +def distance(v1: vector[float], v2: vector[float]) -> 'float | value[float]': """Calculate the Euclidean distance between two vectors.""" diff = v1 - v2 return diff.magnitude() -def scalar_projection(v1: vector[float], v2: vector[float]) -> 'float | variable[float]': +def scalar_projection(v1: vector[float], v2: vector[float]) -> 'float | value[float]': """Calculate the scalar projection of v1 onto v2.""" dot_prod = v1.dot(v2) mag_v2 = v2.magnitude() + epsilon @@ -288,7 +288,7 @@ def vector_projection(v1: vector[float], v2: vector[float]) -> vector[float]: return v2 * scalar_proj -def angle_between(v1: vector[float], v2: vector[float]) -> 'float | variable[float]': +def angle_between(v1: vector[float], v2: vector[float]) -> 'float | value[float]': """Calculate the angle in radians between two vectors.""" dot_prod = v1.dot(v2) mag_v1 = v1.magnitude() @@ -297,7 +297,7 @@ def angle_between(v1: vector[float], v2: vector[float]) -> 'float | variable[flo return cp.acos(cos_angle) -def rotate_vector(v: vector[float], axis: vector[float], angle: 'float | variable[float]') -> vector[float]: +def rotate_vector(v: vector[float], axis: vector[float], angle: 'float | value[float]') -> vector[float]: """Rotate vector v around a given axis by a specified angle using Rodrigues' rotation formula.""" k = axis.normalize() cos_angle = cp.cos(angle) diff --git a/src/copapy/filters.py b/src/copapy/filters.py index abd6d44..4cbdc40 100644 --- a/src/copapy/filters.py +++ b/src/copapy/filters.py @@ -1,15 +1,15 @@ -from . import variable, vector +from . import value, vector from ._basic_types import iif, unifloat from._helper_types import TNum from typing import Any, Iterable -def homogenize_vector(input_values: Iterable[TNum | variable[TNum]]) -> Iterable[TNum] | Iterable[variable[TNum]]: +def homogenize_vector(input_values: Iterable[TNum | value[TNum]]) -> Iterable[TNum] | Iterable[value[TNum]]: input_list = list(input_values) - if any(isinstance(val, variable) for val in input_list): - return (v if isinstance(v, variable) else variable(v) for v in input_list) + if any(isinstance(val, value) for val in input_list): + return (v if isinstance(v, value) else value(v) for v in input_list) else: - return (v for v in input_list if not isinstance(v, variable)) + return (v for v in input_list if not isinstance(v, value)) def _inv_argsort(input_vector: vector[TNum]) -> vector[int]: @@ -31,7 +31,7 @@ def argsort(input_vector: vector[TNum]) -> vector[int]: return _inv_argsort(_inv_argsort(input_vector)) -def median(input_vector: vector[TNum]) -> TNum | variable[TNum]: +def median(input_vector: vector[TNum]) -> TNum | value[TNum]: """ Applies a median filter to the input vector and returns the median as a unifloat. diff --git a/tests/benchmark.py b/tests/benchmark.py index b2d7f7b..647afd5 100644 --- a/tests/benchmark.py +++ b/tests/benchmark.py @@ -27,8 +27,8 @@ def cp_vs_python(path: str): #v_size = 400 iter_size = 30000 - v1 = cp.vector(cp.variable(float(v)) for v in range(v_size)) - v2 = cp.vector(cp.variable(float(v)) for v in [5]*v_size) + v1 = cp.vector(cp.value(float(v)) for v in range(v_size)) + v2 = cp.vector(cp.value(float(v)) for v in [5]*v_size) v3 = sum((v1 + i) @ v2 for i in range(sum_size)) @@ -95,8 +95,8 @@ def cp_vs_python_sparse(path: str = 'benchmark_results_001_sparse.json'): #v_size = 400 iter_size = 3000 - v1 = cp.vector(cp.variable(float(v)) for v in range(v_size)) - v2 = cp.vector(cp.variable(float(v)) for v in [5]*v_size) + v1 = cp.vector(cp.value(float(v)) for v in range(v_size)) + v2 = cp.vector(cp.value(float(v)) for v in [5]*v_size) test = cp.vector(np.linspace(0, 1, v_size)) diff --git a/tests/test_ast_gen.py b/tests/test_ast_gen.py index 89ee086..ee36f05 100644 --- a/tests/test_ast_gen.py +++ b/tests/test_ast_gen.py @@ -1,4 +1,4 @@ -from copapy import variable +from copapy import value from copapy.backend import Write import copapy.backend as cpb @@ -21,8 +21,8 @@ def test_ast_generation(): #r2 = i1 + 9 #out = [Write(r1), Write(r2)] - c1 = variable(4) - c2 = variable(2) + c1 = value(4) + c2 = value(2) #i1 = c1 * 2 #r1 = i1 + 7 + (c2 + 7 * 9) #r2 = i1 + 9 diff --git a/tests/test_autograd.py b/tests/test_autograd.py index f8ecaf1..841840f 100644 --- a/tests/test_autograd.py +++ b/tests/test_autograd.py @@ -1,4 +1,4 @@ -from copapy import variable, grad +from copapy import value, grad import copapy as cp import pytest @@ -6,8 +6,8 @@ import pytest def test_autograd(): # Validate against micrograd results from Andrej Karpathy # https://github.com/karpathy/micrograd/blob/master/test/test_engine.py - a = variable(-4.0) - b = variable(2.0) + a = value(-4.0) + b = value(2.0) c = a + b d = a * b + b**3 c += c + 1 diff --git a/tests/test_branching_stencils.py b/tests/test_branching_stencils.py index 8751d1f..8e8c244 100644 --- a/tests/test_branching_stencils.py +++ b/tests/test_branching_stencils.py @@ -1,4 +1,4 @@ -from copapy import variable +from copapy import value from copapy.backend import Write, compile_to_dag, add_read_command import copapy as cp import subprocess @@ -20,7 +20,7 @@ def test_compile(): test_vals = [0.0, -1.5, -2.0, -2.5, -3.0] # Function with no passing-on-jump as last instruction: - ret_test = [r for v in test_vals for r in (cp.tan(variable(v)),)] + ret_test = [r for v in test_vals for r in (cp.tan(value(v)),)] out = [Write(r) for r in ret_test] diff --git a/tests/test_comp_timing.py b/tests/test_comp_timing.py index 301851e..b848fb9 100644 --- a/tests/test_comp_timing.py +++ b/tests/test_comp_timing.py @@ -9,9 +9,9 @@ from copapy._compiler import patch_entry, CPConstant, get_aux_func_layout def test_timing_compiler(): - t1 = cp.vector([10, 11]*128) + cp.vector(cp.variable(v) for v in range(256)) + t1 = cp.vector([10, 11]*128) + cp.vector(cp.value(v) for v in range(256)) #t2 = t1.sum() - t3 = cp.vector(cp.variable(1 / (v + 1)) for v in range(256)) + t3 = cp.vector(cp.value(1 / (v + 1)) for v in range(256)) t5 = ((t3 * t1) * 2).magnitude() out = [Write(t5)] diff --git a/tests/test_compile.py b/tests/test_compile.py index ed12b56..9635ff1 100644 --- a/tests/test_compile.py +++ b/tests/test_compile.py @@ -49,10 +49,10 @@ def test_compile(): #ret = function(c1, c2) #ret = [c1 // 3.3 + 5] - t1 = cp.vector([10, 11, 12]) + cp.vector(cp.variable(v) for v in range(3)) + t1 = cp.vector([10, 11, 12]) + cp.vector(cp.value(v) for v in range(3)) t2 = t1.sum() - t3 = cp.vector(cp.variable(1 / (v + 1)) for v in range(3)) + t3 = cp.vector(cp.value(1 / (v + 1)) for v in range(3)) t4 = ((t3 * t1) * 2).sum() t5 = ((t3 * t1) * 2).magnitude() diff --git a/tests/test_compile_aarch64.py b/tests/test_compile_aarch64.py index 552ab77..efc3990 100644 --- a/tests/test_compile_aarch64.py +++ b/tests/test_compile_aarch64.py @@ -43,10 +43,10 @@ def function(c1: NumLike, c2: NumLike) -> tuple[NumLike, ...]: @pytest.mark.runner def test_compile(): - t1 = cp.vector([10, 11, 12]) + cp.vector(cp.variable(v) for v in range(3)) + t1 = cp.vector([10, 11, 12]) + cp.vector(cp.value(v) for v in range(3)) t2 = t1.sum() - t3 = cp.vector(cp.variable(1 / (v + 1)) for v in range(3)) + t3 = cp.vector(cp.value(1 / (v + 1)) for v in range(3)) t4 = ((t3 * t1) * 2).sum() t5 = ((t3 * t1) * 2).magnitude() diff --git a/tests/test_compile_armv7.py b/tests/test_compile_armv7.py index 5b1c6bb..6d52845 100644 --- a/tests/test_compile_armv7.py +++ b/tests/test_compile_armv7.py @@ -43,10 +43,10 @@ def function(c1: NumLike, c2: NumLike) -> tuple[NumLike, ...]: @pytest.mark.runner def test_compile(): - t1 = cp.vector([10, 11, 12]) + cp.vector(cp.variable(v) for v in range(3)) + t1 = cp.vector([10, 11, 12]) + cp.vector(cp.value(v) for v in range(3)) t2 = t1.sum() - t3 = cp.vector(cp.variable(1 / (v + 1)) for v in range(3)) + t3 = cp.vector(cp.value(1 / (v + 1)) for v in range(3)) t4 = ((t3 * t1) * 2).sum() t5 = ((t3 * t1) * 2).magnitude() diff --git a/tests/test_compile_div.py b/tests/test_compile_div.py index 9f1dcc2..87ee766 100644 --- a/tests/test_compile_div.py +++ b/tests/test_compile_div.py @@ -1,4 +1,4 @@ -from copapy import variable, NumLike +from copapy import value, NumLike from copapy.backend import Write, compile_to_dag import copapy import subprocess @@ -22,7 +22,7 @@ def function(c1: NumLike) -> list[NumLike]: @pytest.mark.runner def test_compile(): - c1 = variable(16) + c1 = value(16) ret = function(c1) diff --git a/tests/test_compile_math.py b/tests/test_compile_math.py index 6712535..90385c3 100644 --- a/tests/test_compile_math.py +++ b/tests/test_compile_math.py @@ -1,4 +1,4 @@ -from copapy import variable +from copapy import value from copapy.backend import Write, compile_to_dag, add_read_command import copapy as cp import subprocess @@ -18,7 +18,7 @@ def run_command(command: list[str]) -> str: def test_compile_sqrt(): test_vals = [0.0, 0.0001, 0.1, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.28318530718, 100.0, 1000.0, 100000.0] - ret = [r for v in test_vals for r in (cp.sqrt(variable(v)),)] + ret = [r for v in test_vals for r in (cp.sqrt(value(v)),)] out = [Write(r) for r in ret] @@ -52,7 +52,7 @@ def test_compile_sqrt(): def test_compile_log(): test_vals = [0.0, 0.0001, 0.1, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.28318530718, 100.0, 1000.0, 100000.0] - ret = [r for v in test_vals for r in (cp.log(variable(v)),)] + ret = [r for v in test_vals for r in (cp.log(value(v)),)] out = [Write(r) for r in ret] @@ -86,7 +86,7 @@ def test_compile_log(): def test_compile_sin(): test_vals = [0.0, 0.0001, 0.1, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.28318530718, 100.0, 1000.0, 100000.0] - ret = [r for v in test_vals for r in (cp.sin(variable(v)),)] + ret = [r for v in test_vals for r in (cp.sin(value(v)),)] out = [Write(r) for r in ret] diff --git a/tests/test_coparun_module.py b/tests/test_coparun_module.py index 5985bd1..90b0946 100644 --- a/tests/test_coparun_module.py +++ b/tests/test_coparun_module.py @@ -1,4 +1,4 @@ -from copapy import variable, Target, NumLike +from copapy import value, Target, NumLike import pytest @@ -14,7 +14,7 @@ def function(c1: NumLike) -> list[NumLike]: def test_compile(): - c1 = variable(16) + c1 = value(16) ret = function(c1) diff --git a/tests/test_math.py b/tests/test_math.py index b39396f..534d309 100644 --- a/tests/test_math.py +++ b/tests/test_math.py @@ -1,4 +1,4 @@ -from copapy import variable, Target +from copapy import value, Target import pytest import copapy as cp import math as ma @@ -7,8 +7,8 @@ import warnings def test_fine(): a_i = 9 a_f = 2.5 - c_i = variable(a_i) - c_f = variable(a_f) + c_i = value(a_i) + c_f = value(a_f) # c_b = variable(True) ret_test = (c_f ** 2, @@ -49,7 +49,7 @@ def test_fine(): print('* finished') for test, val2, ref, name in zip(ret_test, re2_test, ret_refe, ('^2', '**-1', 'sqrt_int', 'sqrt_float', 'sin', 'cos', 'tan')): - assert isinstance(test, cp.variable) + assert isinstance(test, cp.value) val = tg.read_value(test) print('+', val, ref, type(val), test.dtype) #for t in (int, float, bool): @@ -63,7 +63,7 @@ def test_trig_precision(): test_vals = [0.0, 0.0001, 0.1, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.28318530718, 100.0, 1000.0, 100000.0, -0.0001, -0.1, -0.5, -1.0, -1.5, -2.0, -2.5, -3.0, -3.5, -4.0, -4.5, -5.0, -5.5, -6.0, -6.28318530718, -100.0, -1000.0, -100000.0] - ret_test = [r for v in test_vals for r in (cp.sin(variable(v)), cp.cos(variable(v)), cp.tan(variable(v)))] + ret_test = [r for v in test_vals for r in (cp.sin(value(v)), cp.cos(value(v)), cp.tan(value(v)))] ret_refe = [r for v in test_vals for r in (ma.sin(v), ma.cos(v), ma.tan(v))] tg = Target() @@ -72,7 +72,7 @@ def test_trig_precision(): for i, (v, test, ref) in enumerate(zip(test_vals, ret_test, ret_refe)): func_name = ['sin', 'cos', 'tan'][i % 3] - assert isinstance(test, cp.variable) + assert isinstance(test, cp.value) val = tg.read_value(test) print(f"+ Result of {func_name}: {val}; reference: {ref}") assert val == pytest.approx(ref, abs=1e-3), f"Result of {func_name} for input {test_vals[i // 3]} does not match: {val} and reference: {ref} (value: {v})" # pyright: ignore[reportUnknownMemberType] @@ -85,11 +85,11 @@ def test_arcus_trig_precision(): test_vals = [0.0, 0.01, 0.1, 0.5, 0.7, 0.9, 0.95, -0.01, -0.1, -0.5, -0.7, -0.9, 0.95] - ret_test = [r for v in test_vals for r in (cp.asin(variable(v)), - cp.acos(variable(v)), - cp.atan(variable(v)), - cp.atan2(variable(v), variable(3)), - cp.atan2(variable(v), variable(-3)),)] + ret_test = [r for v in test_vals for r in (cp.asin(value(v)), + cp.acos(value(v)), + cp.atan(value(v)), + cp.atan2(value(v), value(3)), + cp.atan2(value(v), value(-3)),)] ret_refe = [r for v in test_vals for r in (ma.asin(v), ma.acos(v), ma.atan(v), @@ -102,7 +102,7 @@ def test_arcus_trig_precision(): for i, (test, ref) in enumerate(zip(ret_test, ret_refe)): func_name = ['asin', 'acos', 'atan', 'atan2[1]', 'atan2[2]'][i % 5] - assert isinstance(test, cp.variable) + assert isinstance(test, cp.value) val = tg.read_value(test) print(f"+ Result of {func_name}: {val}; reference: {ref}") #assert val == pytest.approx(ref, abs=1e-5), f"Result of {func_name} for input {test_vals[i // 5]} does not match: {val} and reference: {ref}" # pyright: ignore[reportUnknownMemberType] @@ -113,7 +113,7 @@ def test_arcus_trig_precision(): def test_sqrt_precision(): test_vals = [0.0, 0.0001, 0.1, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.28318530718, 100.0, 1000.0, 100000.0] - ret_test = [r for v in test_vals for r in (cp.sqrt(variable(v)),)] + ret_test = [r for v in test_vals for r in (cp.sqrt(value(v)),)] ret_refe = [r for v in test_vals for r in (cp.sqrt(v),)] tg = Target() @@ -122,7 +122,7 @@ def test_sqrt_precision(): for i, (test, ref) in enumerate(zip(ret_test, ret_refe)): func_name = 'sqrt' - assert isinstance(test, cp.variable) + assert isinstance(test, cp.value) val = tg.read_value(test) print(f"+ Result of {func_name}: {val}; reference: {ref}") assert val == pytest.approx(ref, rel=1e-5), f"Result of {func_name} for input {test_vals[i]} does not match: {val} and reference: {ref}" # pyright: ignore[reportUnknownMemberType] @@ -135,8 +135,8 @@ def test_log_exp_precision(): test_vals = [0.1, 0.5, 0.9, 0.999, 1.0, 2.5, -0.1, -0.5, -0.9, -0.999, -1.0, 2.5] - ret_test = [r for v in test_vals for r in (cp.log(variable(abs(v))), - cp.exp(variable(v)))] + ret_test = [r for v in test_vals for r in (cp.log(value(abs(v))), + cp.exp(value(v)))] ret_refe = [r for v in test_vals for r in (ma.log(abs(v)), ma.exp(v))] @@ -146,7 +146,7 @@ def test_log_exp_precision(): for i, (test, ref) in enumerate(zip(ret_test, ret_refe)): func_name = ['log', 'exp'][i % 2] - assert isinstance(test, cp.variable) + assert isinstance(test, cp.value) val = tg.read_value(test) print(f"+ Result of {func_name}: {val}; reference: {ref}") assert val == pytest.approx(ref, abs=1e-5), f"Result of {func_name} for input {test_vals[i // 2]} does not match: {val} and reference: {ref}" # pyright: ignore[reportUnknownMemberType] diff --git a/tests/test_matrix.py b/tests/test_matrix.py index 324b481..81ec534 100644 --- a/tests/test_matrix.py +++ b/tests/test_matrix.py @@ -13,11 +13,11 @@ def test_matrix_init(): def test_matrix_with_variables(): """Test matrix initialization with variables""" - m1 = cp.matrix([[cp.variable(1), 2], [3, cp.variable(4)]]) + m1 = cp.matrix([[cp.value(1), 2], [3, cp.value(4)]]) assert m1.rows == 2 assert m1.cols == 2 - assert isinstance(m1[0][0], cp.variable) - assert isinstance(m1[1][1], cp.variable) + assert isinstance(m1[0][0], cp.value) + assert isinstance(m1[1][1], cp.value) def test_matrix_addition(): @@ -201,12 +201,12 @@ def test_matrix_map(): def test_matrix_homogenize(): """Test homogenizing matrix (converting to all variables)""" - m = cp.matrix([[1, cp.variable(2)], [3, 4]]) + m = cp.matrix([[1, cp.value(2)], [3, 4]]) m_homo = m.homogenize() for row in m_homo: for elem in row: - assert isinstance(elem, cp.variable) + assert isinstance(elem, cp.value) def test_identity_matrix(): @@ -254,8 +254,8 @@ def test_diagonal_matrix(): def test_matrix_with_variables_compiled(): """Test matrix operations with variables in compilation""" - m = cp.matrix([[cp.variable(1), 2], [3, cp.variable(4)]]) - v = cp.vector([cp.variable(5), 6]) + m = cp.matrix([[cp.value(1), 2], [3, cp.value(4)]]) + v = cp.vector([cp.value(5), 6]) result = m @ v # result[0] = 1*5 + 2*6 = 17 diff --git a/tests/test_ops.py b/tests/test_ops.py index e2bd62c..33b18d6 100644 --- a/tests/test_ops.py +++ b/tests/test_ops.py @@ -1,4 +1,4 @@ -from copapy import variable, Target, NumLike, iif +from copapy import value, Target, NumLike, iif import pytest import copapy @@ -42,11 +42,11 @@ def iiftests(c1: NumLike) -> list[NumLike]: def test_compile(): - c_i = variable(9) - c_f = variable(1.111) - c_b = variable(True) + c_i = value(9) + c_f = value(1.111) + c_b = value(True) - ret_test = function1(c_i) + function1(c_f) + function2(c_i) + function2(c_f) + function3(c_i) + function4(c_i) + function5(c_b) + [variable(9) % 2] + iiftests(c_i) + iiftests(c_f) + ret_test = function1(c_i) + function1(c_f) + function2(c_i) + function2(c_f) + function3(c_i) + function4(c_i) + function5(c_b) + [value(9) % 2] + iiftests(c_i) + iiftests(c_f) ret_ref = function1(9) + function1(1.111) + function2(9) + function2(1.111) + function3(9) + function4(9) + function5(True) + [9 % 2] + iiftests(9) + iiftests(1.111) tg = Target() @@ -57,7 +57,7 @@ def test_compile(): print('* finished') for test, ref in zip(ret_test, ret_ref): - assert isinstance(test, copapy.variable) + assert isinstance(test, copapy.value) val = tg.read_value(test) print('+', val, ref, test.dtype) for t in (int, float, bool): diff --git a/tests/test_ops_aarch64.py b/tests/test_ops_aarch64.py index 017def3..2b0ffdd 100644 --- a/tests/test_ops_aarch64.py +++ b/tests/test_ops_aarch64.py @@ -1,4 +1,4 @@ -from copapy import NumLike, iif, variable +from copapy import NumLike, iif, value from copapy.backend import Write, compile_to_dag, add_read_command import subprocess from copapy import _binwrite @@ -84,11 +84,11 @@ def iiftests(c1: NumLike) -> list[NumLike]: @pytest.mark.runner def test_compile(): - c_i = variable(9) - c_f = variable(1.111) - c_b = variable(True) + c_i = value(9) + c_f = value(1.111) + c_b = value(True) - ret_test = function1(c_i) + function1(c_f) + function2(c_i) + function2(c_f) + function3(c_i) + function4(c_i) + function5(c_b) + [variable(9) % 2] + iiftests(c_i) + iiftests(c_f) + [cp.asin(c_i/10)] + ret_test = function1(c_i) + function1(c_f) + function2(c_i) + function2(c_f) + function3(c_i) + function4(c_i) + function5(c_b) + [value(9) % 2] + iiftests(c_i) + iiftests(c_f) + [cp.asin(c_i/10)] ret_ref = function1(9) + function1(1.111) + function2(9) + function2(1.111) + function3(9) + function4(9) + function5(True) + [9 % 2] + iiftests(9) + iiftests(1.111) + [cp.asin(9/10)] out = [Write(r) for r in ret_test] @@ -145,7 +145,7 @@ def test_compile(): result_data = parse_results(result) for test, ref in zip(ret_test, ret_ref): - assert isinstance(test, variable) + assert isinstance(test, value) address = variables[test][0] data = result_data[address] if test.dtype == 'int': diff --git a/tests/test_ops_armv7.py b/tests/test_ops_armv7.py index 4941f9b..0c5d552 100644 --- a/tests/test_ops_armv7.py +++ b/tests/test_ops_armv7.py @@ -1,4 +1,4 @@ -from copapy import NumLike, iif, variable +from copapy import NumLike, iif, value from copapy.backend import Write, compile_to_dag, add_read_command import subprocess from copapy import _binwrite @@ -86,11 +86,11 @@ def iiftests(c1: NumLike) -> list[NumLike]: @pytest.mark.runner def test_compile(): - c_i = variable(9) - c_f = variable(1.111) - c_b = variable(True) + c_i = value(9) + c_f = value(1.111) + c_b = value(True) - ret_test = function1(c_i) + function1(c_f) + function2(c_i) + function2(c_f) + function3(c_i) + function4(c_i) + function5(c_b) + [variable(9) % 2] + iiftests(c_i) + iiftests(c_f) + [cp.asin(c_i/10)] + ret_test = function1(c_i) + function1(c_f) + function2(c_i) + function2(c_f) + function3(c_i) + function4(c_i) + function5(c_b) + [value(9) % 2] + iiftests(c_i) + iiftests(c_f) + [cp.asin(c_i/10)] ret_ref = function1(9) + function1(1.111) + function2(9) + function2(1.111) + function3(9) + function4(9) + function5(True) + [9 % 2] + iiftests(9) + iiftests(1.111) + [cp.asin(9/10)] #ret_test = (c_i * 100 // 5, c_f * 10 // 5) @@ -147,7 +147,7 @@ def test_compile(): result_data = parse_results(result) for test, ref in zip(ret_test, ret_ref): - assert isinstance(test, variable) + assert isinstance(test, value) address = variables[test][0] data = result_data[address] if test.dtype == 'int': diff --git a/tests/test_ops_x86.py b/tests/test_ops_x86.py index 069f341..6ea427d 100644 --- a/tests/test_ops_x86.py +++ b/tests/test_ops_x86.py @@ -1,4 +1,4 @@ -from copapy import NumLike, iif, variable +from copapy import NumLike, iif, value from copapy.backend import Write, compile_to_dag, add_read_command import subprocess from copapy import _binwrite @@ -77,7 +77,7 @@ def test_compile(): #t4 = ((t3 * t1) * 2).sum() #t5 = ((t3 * t1) * 2).magnitude() - c_i = variable(9) + c_i = value(9) #c_f = variable(1.111) #c_b = variable(True) @@ -87,7 +87,7 @@ def test_compile(): #ret_test = [cp.sin(c_i), cp.asin(variable(0.0))] #ret_ref = [cp.sin(9), cp.asin(0.0)] - ret_test: list[variable[float]] = [] + ret_test: list[value[float]] = [] ret_ref: list[float] = [] #sval = variable(8.0) #tval = 8.0 @@ -155,7 +155,7 @@ def test_compile(): result_data = parse_results(result) for test, ref in zip(ret_test, ret_ref): - assert isinstance(test, variable) + assert isinstance(test, value) address = variables[test][0] data = result_data[address] if test.dtype == 'int': diff --git a/tests/test_prog_flow.py b/tests/test_prog_flow.py index bd796c8..5c4563f 100644 --- a/tests/test_prog_flow.py +++ b/tests/test_prog_flow.py @@ -1,11 +1,11 @@ -from copapy import variable, Target, iif +from copapy import value, Target, iif import pytest import copapy def test_compile(): - c_i = variable(9) - c_f = variable(2.5) + c_i = value(9) + c_f = value(2.5) # c_b = variable(True) ret_test = (iif(c_f > 5, c_f, -1), iif(c_i > 5, c_f, 8.8), iif(c_i > 2, c_i, 1)) @@ -19,7 +19,7 @@ def test_compile(): print('* finished') for test, ref in zip(ret_test, ret_ref): - assert isinstance(test, copapy.variable) + assert isinstance(test, copapy.value) val = tg.read_value(test) print('+', val, ref, type(val), test.dtype) #for t in (int, float, bool): diff --git a/tests/test_readme_example.py b/tests/test_readme_example.py index 201d4fa..354c563 100644 --- a/tests/test_readme_example.py +++ b/tests/test_readme_example.py @@ -3,8 +3,8 @@ import pytest def test_readme_example(): # Define variables - a = cp.variable(0.25) - b = cp.variable(0.87) + a = cp.value(0.25) + b = cp.value(0.87) # Define computations c = a + b * 2.0 diff --git a/tests/test_rev_kinematics.py b/tests/test_rev_kinematics.py index abf04ab..9072490 100644 --- a/tests/test_rev_kinematics.py +++ b/tests/test_rev_kinematics.py @@ -10,7 +10,7 @@ target = cp.vector([0.7, 0.7]) alpha = 0.1 -def forward_kinematics(theta1: cp.variable[float] | float, theta2: cp.variable[float] | float) -> tuple[cp.vector[float], cp.vector[float]]: +def forward_kinematics(theta1: cp.value[float] | float, theta2: cp.value[float] | float) -> tuple[cp.vector[float], cp.vector[float]]: """Return positions of joint and end-effector.""" joint = cp.vector([l1 * cp.cos(theta1), l1 * cp.sin(theta1)]) end_effector = joint + cp.vector([l2 * cp.cos(theta1 + theta2), @@ -20,7 +20,7 @@ def forward_kinematics(theta1: cp.variable[float] | float, theta2: cp.variable[f def test_two_arms(): target_vec = cp.vector(target) - theta = cp.vector([cp.variable(0.0), cp.variable(0.0)]) + theta = cp.vector([cp.value(0.0), cp.value(0.0)]) joint = cp.vector([0.0, 0.0]) effector = cp.vector([0.0, 0.0]) diff --git a/tests/test_vector.py b/tests/test_vector.py index c893f6b..b7ce95c 100644 --- a/tests/test_vector.py +++ b/tests/test_vector.py @@ -5,38 +5,38 @@ from copapy import filters def test_vectors_init(): tt1 = cp.vector(range(3)) + cp.vector([1.1, 2.2, 3.3]) - tt2 = cp.vector([1.1, 2, cp.variable(5)]) + cp.vector(range(3)) + tt2 = cp.vector([1.1, 2, cp.value(5)]) + cp.vector(range(3)) tt3 = (cp.vector(range(3)) + 5.6) - tt4 = cp.vector([1.1, 2, 3]) + cp.vector(cp.variable(v) for v in range(3)) + tt4 = cp.vector([1.1, 2, 3]) + cp.vector(cp.value(v) for v in range(3)) tt5 = cp.vector([1, 2, 3]).dot(tt4) print(tt1, tt2, tt3, tt4, tt5) def test_compiled_vectors(): - t1 = cp.vector([10, 11, 12]) + cp.vector(cp.variable(v) for v in range(3)) + t1 = cp.vector([10, 11, 12]) + cp.vector(cp.value(v) for v in range(3)) t2 = t1.sum() - t3 = cp.vector(cp.variable(1 / (v + 1)) for v in range(3)) + t3 = cp.vector(cp.value(1 / (v + 1)) for v in range(3)) t4 = ((t3 * t1) * 2).sum() t5 = ((t3 * t1) * 2).magnitude() - t6 = cp.angle_between(cp.vector([cp.variable(5.0), 0.0, 0.0]), cp.vector([5.0, 5.0, 0.0])) + t6 = cp.angle_between(cp.vector([cp.value(5.0), 0.0, 0.0]), cp.vector([5.0, 5.0, 0.0])) tg = cp.Target() tg.compile(t2, t4, t5, t6) tg.run() - assert isinstance(t2, cp.variable) + assert isinstance(t2, cp.value) assert tg.read_value(t2) == 10 + 11 + 12 + 0 + 1 + 2 - assert isinstance(t4, cp.variable) + assert isinstance(t4, cp.value) assert tg.read_value(t4) == pytest.approx(((10/1*2) + (12/2*2) + (14/3*2)), 0.001) # pyright: ignore[reportUnknownMemberType] - assert isinstance(t5, cp.variable) + assert isinstance(t5, cp.value) assert tg.read_value(t5) == pytest.approx(((10/1*2)**2 + (12/2*2)**2 + (14/3*2)**2) ** 0.5, 0.001) # pyright: ignore[reportUnknownMemberType] - assert isinstance(t6, cp.variable) + assert isinstance(t6, cp.value) assert tg.read_value(t6) == pytest.approx(math.pi / 4, 0.001), tg.read_value(t6) # pyright: ignore[reportUnknownMemberType] @@ -97,7 +97,7 @@ def test_non_compiled_vector_operations(): def test_sort_vector(): vlist = [50, 21, 20, 10, 22, 1, 80, 70, 90] - t1 = cp.vector(cp.variable(v) for v in vlist) + t1 = cp.vector(cp.value(v) for v in vlist) #t1 = cp.vector(v for v in vlist) t2 = filters.median(t1) diff --git a/tools/make_example.py b/tools/make_example.py index 672f0e1..2f16334 100644 --- a/tools/make_example.py +++ b/tools/make_example.py @@ -1,4 +1,4 @@ -from copapy import variable +from copapy import value from copapy.backend import Write, compile_to_dag, stencil_db_from_package from copapy._binwrite import Command import copapy as cp @@ -6,7 +6,7 @@ import copapy as cp def compile_to_x86_64() -> None: """Test compilation of a simple program for x86_64.""" - c1 = variable(9.0) + c1 = value(9.0) #ret = [c1 / 4, c1 / -4, c1 // 4, c1 // -4, (c1 * -1) // 4] ret = [c1 // 3.3 + 5] @@ -29,14 +29,14 @@ def compile_to_x86_64() -> None: def compile_to_x86() -> None: """Test compilation of a simple program for x86 32 bit.""" - c1 = variable(9.0) + c1 = value(9.0) #ret = [c1 / 4, c1 / -4, c1 // 4, c1 // -4, (c1 * -1) // 4] ret = [c1 // 3.3 + 5] #ret = [cp.sqrt(c1)] #c2 = cp._math.get_42() #ret = [c2] - ret = [cp.sin(variable(2.5))] + ret = [cp.sin(value(2.5))] out = [Write(r) for r in ret] @@ -53,7 +53,7 @@ def compile_to_x86() -> None: def compile_to_aarch64() -> None: """Test compilation of a simple program for arm64.""" - c1 = variable(9.0) + c1 = value(9.0) #ret = [c1 / 4, c1 / -4, c1 // 4, c1 // -4, (c1 * -1) // 4] #ret = [cp.sin(c1), cp.sqrt(c1) + 5]