"variable" type renamed to "value"

This commit is contained in:
Nicolas 2025-12-06 18:09:25 +01:00
parent 423ca30ac6
commit 2e48fe5ec2
31 changed files with 369 additions and 369 deletions

View File

@ -1,5 +1,5 @@
from ._target import Target 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 ._vectors import vector, distance, scalar_projection, angle_between, rotate_vector, vector_projection
from ._matrices import matrix, identity, zeros, ones, diagonal, eye 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 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__ = [ __all__ = [
"Target", "Target",
"NumLike", "NumLike",
"variable", "value",
"generic_sdb", "generic_sdb",
"iif", "iif",
"vector", "vector",

View File

@ -1,4 +1,4 @@
from . import variable, vector, matrix from . import value, vector, matrix
import copapy.backend as cpb import copapy.backend as cpb
from typing import Any, Sequence, overload from typing import Any, Sequence, overload
import copapy as cp import copapy as cp
@ -6,14 +6,14 @@ from ._basic_types import Net, unifloat
@overload @overload
def grad(x: Any, y: variable[Any]) -> unifloat: ... def grad(x: Any, y: value[Any]) -> unifloat: ...
@overload @overload
def grad(x: Any, y: vector[Any]) -> vector[float]: ... def grad(x: Any, y: vector[Any]) -> vector[float]: ...
@overload @overload
def grad(x: Any, y: Sequence[variable[Any]]) -> list[unifloat]: ... def grad(x: Any, y: Sequence[value[Any]]) -> list[unifloat]: ...
@overload @overload
def grad(x: Any, y: matrix[Any]) -> matrix[float]: ... 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 """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. 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: Returns:
Derivative of x with the type and dimensions of y 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} y_set = {y}
if isinstance(y, matrix): if isinstance(y, matrix):
y_set = {v for row in y for v in row} 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} net_lookup = {net.source: net for node in ordered_ops for net in node.args}
grad_dict: dict[Net, unifloat] = dict() 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 grad_dict[val] = grad_dict.get(val, 0.0) + gradient_value
for node in reversed(ordered_ops): 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) args: Sequence[Any] = list(node.args)
g = 1.0 if node is x.source else grad_dict[net_lookup[node]] g = 1.0 if node is x.source else grad_dict[net_lookup[node]]
opn = node.name.split('_')[0] opn = node.name.split('_')[0]
a: variable[Any] = args[0] a: value[Any] = args[0]
b: variable[Any] = args[1] if len(args) > 1 else a b: value[Any] = args[1] if len(args) > 1 else a
if opn in ['ge', 'gt', 'eq', 'ne', 'floordiv', 'bwand', 'bwor', 'bwxor']: if opn in ['ge', 'gt', 'eq', 'ne', 'floordiv', 'bwand', 'bwor', 'bwxor']:
pass # Derivative is 0 for all ops returning integers 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: else:
raise ValueError(f"Operation {opn} not yet supported for auto diff.") raise ValueError(f"Operation {opn} not yet supported for auto diff.")
if isinstance(y, variable): if isinstance(y, value):
return grad_dict[y] return grad_dict[y]
if isinstance(y, vector): 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): 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] return [grad_dict[yi] for yi in y]

View File

@ -4,12 +4,12 @@ from ._stencils import stencil_database, detect_process_arch
import copapy as cp import copapy as cp
from ._helper_types import TNum from ._helper_types import TNum
NumLike: TypeAlias = 'variable[int] | variable[float] | int | float' NumLike: TypeAlias = 'value[int] | value[float] | int | float'
unifloat: TypeAlias = 'variable[float] | float' unifloat: TypeAlias = 'value[float] | float'
uniint: TypeAlias = 'variable[int] | int' uniint: TypeAlias = 'value[int] | int'
TCPNum = TypeVar("TCPNum", bound='variable[Any]') TCPNum = TypeVar("TCPNum", bound='value[Any]')
TVarNumb: TypeAlias = 'variable[Any] | int | float' TVarNumb: TypeAlias = 'value[Any] | int | float'
stencil_cache: dict[tuple[str, str], stencil_database] = {} stencil_cache: dict[tuple[str, str], stencil_database] = {}
@ -67,7 +67,7 @@ class Node:
class Net: 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. connects Nodes together.
Attributes: Attributes:
@ -86,19 +86,19 @@ class Net:
return self.source.node_hash return self.source.node_hash
class variable(Generic[TNum], Net): class value(Generic[TNum], Net):
"""A "variable" represents a typed variable. It supports arithmetic and """A "value" represents a typed scalar variable. It supports arithmetic and
comparison operations. comparison operations.
Attributes: 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): def __init__(self, source: TNum | Node, dtype: str | None = None):
"""Instance a variable. """Instance a value.
Args: Args:
source: A numeric value or Node object. 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): if isinstance(source, Node):
self.source = source self.source = source
@ -115,67 +115,67 @@ class variable(Generic[TNum], Net):
self.dtype = 'int' self.dtype = 'int'
@overload @overload
def __add__(self: 'variable[TNum]', other: 'variable[TNum] | TNum') -> 'variable[TNum]': ... def __add__(self: 'value[TNum]', other: 'value[TNum] | TNum') -> 'value[TNum]': ...
@overload @overload
def __add__(self: 'variable[int]', other: uniint) -> 'variable[int]': ... def __add__(self: 'value[int]', other: uniint) -> 'value[int]': ...
@overload @overload
def __add__(self, other: unifloat) -> 'variable[float]': ... def __add__(self, other: unifloat) -> 'value[float]': ...
@overload @overload
def __add__(self: 'variable[float]', other: NumLike) -> 'variable[float]': ... def __add__(self: 'value[float]', other: NumLike) -> 'value[float]': ...
@overload @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: 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 self
return add_op('add', [self, other], True) return add_op('add', [self, other], True)
@overload @overload
def __radd__(self: 'variable[TNum]', other: TNum) -> 'variable[TNum]': ... def __radd__(self: 'value[TNum]', other: TNum) -> 'value[TNum]': ...
@overload @overload
def __radd__(self: 'variable[int]', other: int) -> 'variable[int]': ... def __radd__(self: 'value[int]', other: int) -> 'value[int]': ...
@overload @overload
def __radd__(self, other: float) -> 'variable[float]': ... def __radd__(self, other: float) -> 'value[float]': ...
def __radd__(self, other: NumLike) -> Any: def __radd__(self, other: NumLike) -> Any:
return self + other return self + other
@overload @overload
def __sub__(self: 'variable[TNum]', other: 'variable[TNum] | TNum') -> 'variable[TNum]': ... def __sub__(self: 'value[TNum]', other: 'value[TNum] | TNum') -> 'value[TNum]': ...
@overload @overload
def __sub__(self: 'variable[int]', other: uniint) -> 'variable[int]': ... def __sub__(self: 'value[int]', other: uniint) -> 'value[int]': ...
@overload @overload
def __sub__(self, other: unifloat) -> 'variable[float]': ... def __sub__(self, other: unifloat) -> 'value[float]': ...
@overload @overload
def __sub__(self: 'variable[float]', other: NumLike) -> 'variable[float]': ... def __sub__(self: 'value[float]', other: NumLike) -> 'value[float]': ...
@overload @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: def __sub__(self, other: TVarNumb) -> Any:
if isinstance(other, int | float) and other == 0: if isinstance(other, int | float) and other == 0:
return self return self
return add_op('sub', [self, other]) return add_op('sub', [self, other])
@overload @overload
def __rsub__(self: 'variable[TNum]', other: TNum) -> 'variable[TNum]': ... def __rsub__(self: 'value[TNum]', other: TNum) -> 'value[TNum]': ...
@overload @overload
def __rsub__(self: 'variable[int]', other: int) -> 'variable[int]': ... def __rsub__(self: 'value[int]', other: int) -> 'value[int]': ...
@overload @overload
def __rsub__(self, other: float) -> 'variable[float]': ... def __rsub__(self, other: float) -> 'value[float]': ...
def __rsub__(self, other: NumLike) -> Any: def __rsub__(self, other: NumLike) -> Any:
return add_op('sub', [other, self]) return add_op('sub', [other, self])
@overload @overload
def __mul__(self: 'variable[TNum]', other: 'variable[TNum] | TNum') -> 'variable[TNum]': ... def __mul__(self: 'value[TNum]', other: 'value[TNum] | TNum') -> 'value[TNum]': ...
@overload @overload
def __mul__(self: 'variable[int]', other: uniint) -> 'variable[int]': ... def __mul__(self: 'value[int]', other: uniint) -> 'value[int]': ...
@overload @overload
def __mul__(self, other: unifloat) -> 'variable[float]': ... def __mul__(self, other: unifloat) -> 'value[float]': ...
@overload @overload
def __mul__(self: 'variable[float]', other: NumLike) -> 'variable[float]': ... def __mul__(self: 'value[float]', other: NumLike) -> 'value[float]': ...
@overload @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: def __mul__(self, other: TVarNumb) -> Any:
if self.dtype == 'float' and isinstance(other, int): if self.dtype == 'float' and isinstance(other, int):
other = float(other) # Prevent runtime conversion of consts; TODO: add this for other operations 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: if other == 1:
return self return self
elif other == 0: elif other == 0:
@ -183,112 +183,112 @@ class variable(Generic[TNum], Net):
return add_op('mul', [self, other], True) return add_op('mul', [self, other], True)
@overload @overload
def __rmul__(self: 'variable[TNum]', other: TNum) -> 'variable[TNum]': ... def __rmul__(self: 'value[TNum]', other: TNum) -> 'value[TNum]': ...
@overload @overload
def __rmul__(self: 'variable[int]', other: int) -> 'variable[int]': ... def __rmul__(self: 'value[int]', other: int) -> 'value[int]': ...
@overload @overload
def __rmul__(self, other: float) -> 'variable[float]': ... def __rmul__(self, other: float) -> 'value[float]': ...
def __rmul__(self, other: NumLike) -> Any: def __rmul__(self, other: NumLike) -> Any:
return self * other return self * other
def __truediv__(self, other: NumLike) -> 'variable[float]': def __truediv__(self, other: NumLike) -> 'value[float]':
return add_op('div', [self, other]) 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]) return add_op('div', [other, self])
@overload @overload
def __floordiv__(self: 'variable[TNum]', other: 'variable[TNum] | TNum') -> 'variable[TNum]': ... def __floordiv__(self: 'value[TNum]', other: 'value[TNum] | TNum') -> 'value[TNum]': ...
@overload @overload
def __floordiv__(self: 'variable[int]', other: uniint) -> 'variable[int]': ... def __floordiv__(self: 'value[int]', other: uniint) -> 'value[int]': ...
@overload @overload
def __floordiv__(self, other: unifloat) -> 'variable[float]': ... def __floordiv__(self, other: unifloat) -> 'value[float]': ...
@overload @overload
def __floordiv__(self: 'variable[float]', other: NumLike) -> 'variable[float]': ... def __floordiv__(self: 'value[float]', other: NumLike) -> 'value[float]': ...
@overload @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: def __floordiv__(self, other: TVarNumb) -> Any:
return add_op('floordiv', [self, other]) return add_op('floordiv', [self, other])
@overload @overload
def __rfloordiv__(self: 'variable[TNum]', other: TNum) -> 'variable[TNum]': ... def __rfloordiv__(self: 'value[TNum]', other: TNum) -> 'value[TNum]': ...
@overload @overload
def __rfloordiv__(self: 'variable[int]', other: int) -> 'variable[int]': ... def __rfloordiv__(self: 'value[int]', other: int) -> 'value[int]': ...
@overload @overload
def __rfloordiv__(self, other: float) -> 'variable[float]': ... def __rfloordiv__(self, other: float) -> 'value[float]': ...
def __rfloordiv__(self, other: NumLike) -> Any: def __rfloordiv__(self, other: NumLike) -> Any:
return add_op('floordiv', [other, self]) return add_op('floordiv', [other, self])
def __neg__(self: TCPNum) -> TCPNum: def __neg__(self: TCPNum) -> TCPNum:
if self.dtype == 'int': if self.dtype == 'int':
return cast(TCPNum, add_op('sub', [variable(0), self])) return cast(TCPNum, add_op('sub', [value(0), self]))
return cast(TCPNum, add_op('sub', [variable(0.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]) 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]) 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]) 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]) 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) 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) ret = add_op('ne', [self, other], True)
return variable(ret.source, dtype='bool') return value(ret.source, dtype='bool')
@overload @overload
def __mod__(self: 'variable[TNum]', other: 'variable[TNum] | TNum') -> 'variable[TNum]': ... def __mod__(self: 'value[TNum]', other: 'value[TNum] | TNum') -> 'value[TNum]': ...
@overload @overload
def __mod__(self: 'variable[int]', other: uniint) -> 'variable[int]': ... def __mod__(self: 'value[int]', other: uniint) -> 'value[int]': ...
@overload @overload
def __mod__(self, other: unifloat) -> 'variable[float]': ... def __mod__(self, other: unifloat) -> 'value[float]': ...
@overload @overload
def __mod__(self: 'variable[float]', other: NumLike) -> 'variable[float]': ... def __mod__(self: 'value[float]', other: NumLike) -> 'value[float]': ...
@overload @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: def __mod__(self, other: TVarNumb) -> Any:
return add_op('mod', [self, other]) return add_op('mod', [self, other])
@overload @overload
def __rmod__(self: 'variable[TNum]', other: TNum) -> 'variable[TNum]': ... def __rmod__(self: 'value[TNum]', other: TNum) -> 'value[TNum]': ...
@overload @overload
def __rmod__(self: 'variable[int]', other: int) -> 'variable[int]': ... def __rmod__(self: 'value[int]', other: int) -> 'value[int]': ...
@overload @overload
def __rmod__(self, other: float) -> 'variable[float]': ... def __rmod__(self, other: float) -> 'value[float]': ...
def __rmod__(self, other: NumLike) -> Any: def __rmod__(self, other: NumLike) -> Any:
return add_op('mod', [other, self]) return add_op('mod', [other, self])
@overload @overload
def __pow__(self: 'variable[TNum]', other: 'variable[TNum] | TNum') -> 'variable[TNum]': ... def __pow__(self: 'value[TNum]', other: 'value[TNum] | TNum') -> 'value[TNum]': ...
@overload @overload
def __pow__(self: 'variable[int]', other: uniint) -> 'variable[int]': ... def __pow__(self: 'value[int]', other: uniint) -> 'value[int]': ...
@overload @overload
def __pow__(self, other: unifloat) -> 'variable[float]': ... def __pow__(self, other: unifloat) -> 'value[float]': ...
@overload @overload
def __pow__(self: 'variable[float]', other: NumLike) -> 'variable[float]': ... def __pow__(self: 'value[float]', other: NumLike) -> 'value[float]': ...
@overload @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: def __pow__(self, other: TVarNumb) -> Any:
return cp.pow(self, other) return cp.pow(self, other)
@overload @overload
def __rpow__(self: 'variable[TNum]', other: TNum) -> 'variable[TNum]': ... def __rpow__(self: 'value[TNum]', other: TNum) -> 'value[TNum]': ...
@overload @overload
def __rpow__(self: 'variable[int]', other: int) -> 'variable[int]': ... def __rpow__(self: 'value[int]', other: int) -> 'value[int]': ...
@overload @overload
def __rpow__(self, other: float) -> 'variable[float]': ... def __rpow__(self, other: float) -> 'value[float]': ...
def __rpow__(self, other: NumLike) -> Any: def __rpow__(self, other: NumLike) -> Any:
return cp.pow(other, self) return cp.pow(other, self)
@ -296,34 +296,34 @@ class variable(Generic[TNum], Net):
return super().__hash__() return super().__hash__()
# Bitwise and shift operations for cp[int] # 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]) 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]) 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]) 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]) 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) 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) 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) 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) 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) 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) return add_op('bwxor', [other, self], True)
@ -356,30 +356,30 @@ class Op(Node):
self.node_hash = self.get_node_hash(commutative) self.node_hash = self.get_node_hash(commutative)
def net_from_value(value: Any) -> variable[Any]: def net_from_value(val: Any) -> value[Any]:
vi = CPConstant(value) vi = CPConstant(val)
return variable(vi, vi.dtype) return value(vi, vi.dtype)
@overload @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 @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 @overload
def iif(expression: float | int, true_result: TNum, false_result: TNum) -> TNum: ... def iif(expression: float | int, true_result: TNum, false_result: TNum) -> TNum: ...
@overload @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 @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 @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: 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" 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 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] arg_nets = [a if isinstance(a, Net) else net_from_value(a) for a in args]
if commutative: 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] result_type = generic_sdb.stencil_definitions[typed_op].split('_')[0]
if result_type == 'float': 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: 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]: def _get_data_and_dtype(value: Any) -> tuple[str, float | int]:

View File

@ -1,18 +1,18 @@
from . import vector from . import vector
from ._vectors import VecNumLike from ._vectors import VecNumLike
from . import variable, NumLike from . import value, NumLike
from typing import TypeVar, Any, overload, Callable from typing import TypeVar, Any, overload, Callable
from ._basic_types import add_op, unifloat from ._basic_types import add_op, unifloat
import math 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) U = TypeVar("U", int, float)
@overload @overload
def exp(x: float | int) -> float: ... def exp(x: float | int) -> float: ...
@overload @overload
def exp(x: variable[Any]) -> variable[float]: ... def exp(x: value[Any]) -> value[float]: ...
@overload @overload
def exp(x: vector[Any]) -> vector[float]: ... def exp(x: vector[Any]) -> vector[float]: ...
def exp(x: Any) -> Any: def exp(x: Any) -> Any:
@ -24,7 +24,7 @@ def exp(x: Any) -> Any:
Returns: Returns:
result of e**x result of e**x
""" """
if isinstance(x, variable): if isinstance(x, value):
return add_op('exp', [x]) return add_op('exp', [x])
if isinstance(x, vector): if isinstance(x, vector):
return x.map(exp) return x.map(exp)
@ -34,7 +34,7 @@ def exp(x: Any) -> Any:
@overload @overload
def log(x: float | int) -> float: ... def log(x: float | int) -> float: ...
@overload @overload
def log(x: variable[Any]) -> variable[float]: ... def log(x: value[Any]) -> value[float]: ...
@overload @overload
def log(x: vector[Any]) -> vector[float]: ... def log(x: vector[Any]) -> vector[float]: ...
def log(x: Any) -> Any: def log(x: Any) -> Any:
@ -46,7 +46,7 @@ def log(x: Any) -> Any:
Returns: Returns:
result of ln(x) result of ln(x)
""" """
if isinstance(x, variable): if isinstance(x, value):
return add_op('log', [x]) return add_op('log', [x])
if isinstance(x, vector): if isinstance(x, vector):
return x.map(log) return x.map(log)
@ -56,9 +56,9 @@ def log(x: Any) -> Any:
@overload @overload
def pow(x: float | int, y: float | int) -> float: ... def pow(x: float | int, y: float | int) -> float: ...
@overload @overload
def pow(x: variable[Any], y: NumLike) -> variable[float]: ... def pow(x: value[Any], y: NumLike) -> value[float]: ...
@overload @overload
def pow(x: NumLike, y: variable[Any]) -> variable[float]: ... def pow(x: NumLike, y: value[Any]) -> value[float]: ...
@overload @overload
def pow(x: vector[Any], y: Any) -> vector[float]: ... def pow(x: vector[Any], y: Any) -> vector[float]: ...
def pow(x: VecNumLike, y: VecNumLike) -> Any: def pow(x: VecNumLike, y: VecNumLike) -> Any:
@ -81,7 +81,7 @@ def pow(x: VecNumLike, y: VecNumLike) -> Any:
return m return m
if y == -1: if y == -1:
return 1 / x 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]) return add_op('pow', [x, y])
else: else:
return float(x ** y) return float(x ** y)
@ -90,7 +90,7 @@ def pow(x: VecNumLike, y: VecNumLike) -> Any:
@overload @overload
def sqrt(x: float | int) -> float: ... def sqrt(x: float | int) -> float: ...
@overload @overload
def sqrt(x: variable[Any]) -> variable[float]: ... def sqrt(x: value[Any]) -> value[float]: ...
@overload @overload
def sqrt(x: vector[Any]) -> vector[float]: ... def sqrt(x: vector[Any]) -> vector[float]: ...
def sqrt(x: Any) -> Any: def sqrt(x: Any) -> Any:
@ -102,7 +102,7 @@ def sqrt(x: Any) -> Any:
Returns: Returns:
Square root of x Square root of x
""" """
if isinstance(x, variable): if isinstance(x, value):
return add_op('sqrt', [x]) return add_op('sqrt', [x])
if isinstance(x, vector): if isinstance(x, vector):
return x.map(sqrt) return x.map(sqrt)
@ -112,7 +112,7 @@ def sqrt(x: Any) -> Any:
@overload @overload
def sin(x: float | int) -> float: ... def sin(x: float | int) -> float: ...
@overload @overload
def sin(x: variable[Any]) -> variable[float]: ... def sin(x: value[Any]) -> value[float]: ...
@overload @overload
def sin(x: vector[Any]) -> vector[float]: ... def sin(x: vector[Any]) -> vector[float]: ...
def sin(x: Any) -> Any: def sin(x: Any) -> Any:
@ -124,7 +124,7 @@ def sin(x: Any) -> Any:
Returns: Returns:
Square root of x Square root of x
""" """
if isinstance(x, variable): if isinstance(x, value):
return add_op('sin', [x]) return add_op('sin', [x])
if isinstance(x, vector): if isinstance(x, vector):
return x.map(sin) return x.map(sin)
@ -134,7 +134,7 @@ def sin(x: Any) -> Any:
@overload @overload
def cos(x: float | int) -> float: ... def cos(x: float | int) -> float: ...
@overload @overload
def cos(x: variable[Any]) -> variable[float]: ... def cos(x: value[Any]) -> value[float]: ...
@overload @overload
def cos(x: vector[Any]) -> vector[float]: ... def cos(x: vector[Any]) -> vector[float]: ...
def cos(x: Any) -> Any: def cos(x: Any) -> Any:
@ -146,7 +146,7 @@ def cos(x: Any) -> Any:
Returns: Returns:
Cosine of x Cosine of x
""" """
if isinstance(x, variable): if isinstance(x, value):
return add_op('cos', [x]) return add_op('cos', [x])
if isinstance(x, vector): if isinstance(x, vector):
return x.map(cos) return x.map(cos)
@ -156,7 +156,7 @@ def cos(x: Any) -> Any:
@overload @overload
def tan(x: float | int) -> float: ... def tan(x: float | int) -> float: ...
@overload @overload
def tan(x: variable[Any]) -> variable[float]: ... def tan(x: value[Any]) -> value[float]: ...
@overload @overload
def tan(x: vector[Any]) -> vector[float]: ... def tan(x: vector[Any]) -> vector[float]: ...
def tan(x: Any) -> Any: def tan(x: Any) -> Any:
@ -168,7 +168,7 @@ def tan(x: Any) -> Any:
Returns: Returns:
Tangent of x Tangent of x
""" """
if isinstance(x, variable): if isinstance(x, value):
return add_op('tan', [x]) return add_op('tan', [x])
if isinstance(x, vector): if isinstance(x, vector):
#return x.map(tan) #return x.map(tan)
@ -179,7 +179,7 @@ def tan(x: Any) -> Any:
@overload @overload
def atan(x: float | int) -> float: ... def atan(x: float | int) -> float: ...
@overload @overload
def atan(x: variable[Any]) -> variable[float]: ... def atan(x: value[Any]) -> value[float]: ...
@overload @overload
def atan(x: vector[Any]) -> vector[float]: ... def atan(x: vector[Any]) -> vector[float]: ...
def atan(x: Any) -> Any: def atan(x: Any) -> Any:
@ -191,7 +191,7 @@ def atan(x: Any) -> Any:
Returns: Returns:
Inverse tangent of x Inverse tangent of x
""" """
if isinstance(x, variable): if isinstance(x, value):
return add_op('atan', [x]) return add_op('atan', [x])
if isinstance(x, vector): if isinstance(x, vector):
return x.map(atan) return x.map(atan)
@ -201,9 +201,9 @@ def atan(x: Any) -> Any:
@overload @overload
def atan2(x: float | int, y: float | int) -> float: ... def atan2(x: float | int, y: float | int) -> float: ...
@overload @overload
def atan2(x: variable[Any], y: NumLike) -> variable[float]: ... def atan2(x: value[Any], y: NumLike) -> value[float]: ...
@overload @overload
def atan2(x: NumLike, y: variable[Any]) -> variable[float]: ... def atan2(x: NumLike, y: value[Any]) -> value[float]: ...
@overload @overload
def atan2(x: vector[float], y: VecNumLike) -> vector[float]: ... def atan2(x: vector[float], y: VecNumLike) -> vector[float]: ...
@overload @overload
@ -220,7 +220,7 @@ def atan2(x: VecNumLike, y: VecNumLike) -> Any:
""" """
if isinstance(x, vector) or isinstance(y, vector): if isinstance(x, vector) or isinstance(y, vector):
return _map2(x, y, atan2) 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 add_op('atan2', [x, y])
return math.atan2(x, y) return math.atan2(x, y)
@ -228,7 +228,7 @@ def atan2(x: VecNumLike, y: VecNumLike) -> Any:
@overload @overload
def asin(x: float | int) -> float: ... def asin(x: float | int) -> float: ...
@overload @overload
def asin(x: variable[Any]) -> variable[float]: ... def asin(x: value[Any]) -> value[float]: ...
@overload @overload
def asin(x: vector[Any]) -> vector[float]: ... def asin(x: vector[Any]) -> vector[float]: ...
def asin(x: Any) -> Any: def asin(x: Any) -> Any:
@ -240,7 +240,7 @@ def asin(x: Any) -> Any:
Returns: Returns:
Inverse sine of x Inverse sine of x
""" """
if isinstance(x, variable): if isinstance(x, value):
return add_op('asin', [x]) return add_op('asin', [x])
if isinstance(x, vector): if isinstance(x, vector):
return x.map(asin) return x.map(asin)
@ -250,7 +250,7 @@ def asin(x: Any) -> Any:
@overload @overload
def acos(x: float | int) -> float: ... def acos(x: float | int) -> float: ...
@overload @overload
def acos(x: variable[Any]) -> variable[float]: ... def acos(x: value[Any]) -> value[float]: ...
@overload @overload
def acos(x: vector[Any]) -> vector[float]: ... def acos(x: vector[Any]) -> vector[float]: ...
def acos(x: Any) -> Any: def acos(x: Any) -> Any:
@ -262,7 +262,7 @@ def acos(x: Any) -> Any:
Returns: Returns:
Inverse cosine of x Inverse cosine of x
""" """
if isinstance(x, variable): if isinstance(x, value):
return add_op('acos', [x]) return add_op('acos', [x])
if isinstance(x, vector): if isinstance(x, vector):
return x.map(acos) return x.map(acos)
@ -272,10 +272,10 @@ def acos(x: Any) -> Any:
@overload @overload
def get_42(x: float | int) -> float: ... def get_42(x: float | int) -> float: ...
@overload @overload
def get_42(x: variable[Any]) -> variable[float]: ... def get_42(x: value[Any]) -> value[float]: ...
def get_42(x: NumLike) -> variable[float] | float: def get_42(x: NumLike) -> value[float] | float:
"""Returns the variable representing the constant 42""" """Returns the value representing the constant 42"""
if isinstance(x, variable): if isinstance(x, value):
return add_op('get_42', [x, x]) return add_op('get_42', [x, x])
return float((int(x) * 3.0 + 42.0) * 5.0 + 21.0) 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 @overload
def abs(x: U) -> U: ... def abs(x: U) -> U: ...
@overload @overload
def abs(x: variable[U]) -> variable[U]: ... def abs(x: value[U]) -> value[U]: ...
@overload @overload
def abs(x: vector[U]) -> vector[U]: ... 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 """Absolute value function
Arguments: Arguments:
@ -304,10 +304,10 @@ def abs(x: U | variable[U] | vector[U]) -> Any:
@overload @overload
def sign(x: U) -> U: ... def sign(x: U) -> U: ...
@overload @overload
def sign(x: variable[U]) -> variable[U]: ... def sign(x: value[U]) -> value[U]: ...
@overload @overload
def sign(x: vector[U]) -> vector[U]: ... 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. """Return 1 for positive numbers and -1 for negative numbers.
For an input of 0 the return value is 0. For an input of 0 the return value is 0.
@ -322,16 +322,16 @@ def sign(x: U | variable[U] | vector[U]) -> Any:
@overload @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 @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 @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 @overload
def clamp(x: U, min_value: U, max_value: U) -> U: ... def clamp(x: U, min_value: U, max_value: U) -> U: ...
@overload @overload
def clamp(x: vector[U], min_value: 'U | variable[U]', max_value: 'U | variable[U]') -> vector[U]: ... def clamp(x: vector[U], min_value: 'U | value[U]', max_value: 'U | value[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: 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. """Clamp function to limit a value between a minimum and maximum.
Arguments: Arguments:
@ -351,12 +351,12 @@ def clamp(x: U | variable[U] | vector[U], min_value: U | variable[U], max_value:
@overload @overload
def min(x: variable[U], y: U | variable[U]) -> variable[U]: ... def min(x: value[U], y: U | value[U]) -> value[U]: ...
@overload @overload
def min(x: U | variable[U], y: variable[U]) -> variable[U]: ... def min(x: U | value[U], y: value[U]) -> value[U]: ...
@overload @overload
def min(x: U, y: U) -> U: ... 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. """Minimum function to get the smaller of two values.
Arguments: Arguments:
@ -370,12 +370,12 @@ def min(x: U | variable[U], y: U | variable[U]) -> Any:
@overload @overload
def max(x: variable[U], y: U | variable[U]) -> variable[U]: ... def max(x: value[U], y: U | value[U]) -> value[U]: ...
@overload @overload
def max(x: U | variable[U], y: variable[U]) -> variable[U]: ... def max(x: U | value[U], y: value[U]) -> value[U]: ...
@overload @overload
def max(x: U, y: U) -> U: ... 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. """Maximum function to get the larger of two values.
Arguments: Arguments:
@ -389,16 +389,16 @@ def max(x: U | variable[U], y: U | variable[U]) -> Any:
@overload @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 @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 @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 @overload
def lerp(v1: U, v2: U, t: float) -> U: ... def lerp(v1: U, v2: U, t: float) -> U: ...
@overload @overload
def lerp(v1: vector[U], v2: vector[U], t: unifloat) -> vector[U]: ... 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.""" """Linearly interpolate between two values or vectors v1 and v2 by a factor t."""
if isinstance(v1, vector) or isinstance(v2, vector): 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." 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 @overload
def relu(x: U) -> U: ... def relu(x: U) -> U: ...
@overload @overload
def relu(x: variable[U]) -> variable[U]: ... def relu(x: value[U]) -> value[U]: ...
@overload @overload
def relu(x: vector[U]) -> vector[U]: ... 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.""" """Returns x for x > 0 and otherwise 0."""
ret = (x > 0) * x ret = (x > 0) * x
return ret 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.""" """Applies a function to each element of the vector and a second vector or scalar."""
if isinstance(self, vector) and isinstance(other, vector): if isinstance(self, vector) and isinstance(other, vector):
return vector(func(x, y) for x, y in zip(self.values, other.values)) return vector(func(x, y) for x, y in zip(self.values, other.values))

View File

@ -1,23 +1,23 @@
from . import variable from . import value
from ._vectors import vector from ._vectors import vector
from ._mixed import mixed_sum from ._mixed import mixed_sum
from typing import TypeVar, Iterable, Any, overload, TypeAlias, Callable, Iterator, Generic from typing import TypeVar, Iterable, Any, overload, TypeAlias, Callable, Iterator, Generic
from ._helper_types import TNum from ._helper_types import TNum
MatNumLike: TypeAlias = 'matrix[int] | matrix[float] | variable[int] | variable[float] | int | float' MatNumLike: TypeAlias = 'matrix[int] | matrix[float] | value[int] | value[float] | int | float'
MatIntLike: TypeAlias = 'matrix[int] | variable[int] | int' MatIntLike: TypeAlias = 'matrix[int] | value[int] | int'
MatFloatLike: TypeAlias = 'matrix[float] | variable[float] | float' MatFloatLike: TypeAlias = 'matrix[float] | value[float] | float'
U = TypeVar("U", int, float) U = TypeVar("U", int, float)
class matrix(Generic[TNum]): 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]): def __init__(self, values: Iterable[Iterable[TNum | value[TNum]]] | vector[TNum]):
"""Create a matrix with given values and variables. """Create a matrix with given values.
Args: Args:
values: iterable of iterable of constant values and variables values: iterable of iterable of constant values
""" """
if isinstance(values, vector): if isinstance(values, vector):
rows = [values.values] rows = [values.values]
@ -27,7 +27,7 @@ class matrix(Generic[TNum]):
if rows: if rows:
row_len = len(rows[0]) row_len = len(rows[0])
assert all(len(row) == row_len for row in rows), "All rows must have the same length" 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.rows = len(self.values)
self.cols = len(self.values[0]) if self.values else 0 self.cols = len(self.values[0]) if self.values else 0
@ -41,7 +41,7 @@ class matrix(Generic[TNum]):
@overload @overload
def __getitem__(self, key: int) -> vector[TNum]: ... def __getitem__(self, key: int) -> vector[TNum]: ...
@overload @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: def __getitem__(self, key: int | tuple[int, int]) -> Any:
"""Get a row as a vector or a specific element. """Get a row as a vector or a specific element.
Args: Args:
@ -56,7 +56,7 @@ class matrix(Generic[TNum]):
else: else:
return vector(self.values[key]) 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) return iter(self.values)
def __neg__(self) -> 'matrix[TNum]': def __neg__(self) -> 'matrix[TNum]':
@ -86,7 +86,7 @@ class matrix(Generic[TNum]):
@overload @overload
def __radd__(self: 'matrix[float]', other: MatNumLike) -> 'matrix[float]': ... def __radd__(self: 'matrix[float]', other: MatNumLike) -> 'matrix[float]': ...
@overload @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: def __radd__(self, other: Any) -> Any:
return self + other return self + other
@ -114,7 +114,7 @@ class matrix(Generic[TNum]):
@overload @overload
def __rsub__(self: 'matrix[float]', other: MatNumLike) -> 'matrix[float]': ... def __rsub__(self: 'matrix[float]', other: MatNumLike) -> 'matrix[float]': ...
@overload @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: def __rsub__(self, other: MatNumLike) -> Any:
if isinstance(other, matrix): if isinstance(other, matrix):
assert self.rows == other.rows and self.cols == other.cols, \ assert self.rows == other.rows and self.cols == other.cols, \
@ -153,7 +153,7 @@ class matrix(Generic[TNum]):
@overload @overload
def __rmul__(self: 'matrix[float]', other: MatNumLike) -> 'matrix[float]': ... def __rmul__(self: 'matrix[float]', other: MatNumLike) -> 'matrix[float]': ...
@overload @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: def __rmul__(self, other: MatNumLike) -> Any:
return self * other return self * other
@ -199,9 +199,9 @@ class matrix(Generic[TNum]):
assert isinstance(other, matrix), "Cannot multiply matrix with {type(other)}" assert isinstance(other, matrix), "Cannot multiply matrix with {type(other)}"
assert self.cols == other.rows, \ assert self.cols == other.rows, \
f"Matrix columns ({self.cols}) must match other matrix rows ({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: for row in self.values:
new_row: list[TNum | variable[TNum]] = [] new_row: list[TNum | value[TNum]] = []
for col_idx in range(other.cols): for col_idx in range(other.cols):
col = tuple(other.values[i][col_idx] for i in range(other.rows)) col = tuple(other.values[i][col_idx] for i in range(other.rows))
element = sum(a * b for a, b in zip(row, col)) 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)) return vector(self.values[i][index] for i in range(self.rows))
@overload @overload
def trace(self: 'matrix[TNum]') -> TNum | variable[TNum]: ... def trace(self: 'matrix[TNum]') -> TNum | value[TNum]: ...
@overload @overload
def trace(self: 'matrix[int]') -> int | variable[int]: ... def trace(self: 'matrix[int]') -> int | value[int]: ...
@overload @overload
def trace(self: 'matrix[float]') -> float | variable[float]: ... def trace(self: 'matrix[float]') -> float | value[float]: ...
def trace(self) -> Any: def trace(self) -> Any:
"""Calculate the trace (sum of diagonal elements).""" """Calculate the trace (sum of diagonal elements)."""
assert self.rows == self.cols, "Trace is only defined for square matrices" 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)) return mixed_sum(self.values[i][i] for i in range(self.rows))
@overload @overload
def sum(self: 'matrix[TNum]') -> TNum | variable[TNum]: ... def sum(self: 'matrix[TNum]') -> TNum | value[TNum]: ...
@overload @overload
def sum(self: 'matrix[int]') -> int | variable[int]: ... def sum(self: 'matrix[int]') -> int | value[int]: ...
@overload @overload
def sum(self: 'matrix[float]') -> float | variable[float]: ... def sum(self: 'matrix[float]') -> float | value[float]: ...
def sum(self) -> Any: def sum(self) -> Any:
"""Calculate the sum of all elements.""" """Calculate the sum of all elements."""
return mixed_sum(a for row in self.values for a in row) 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.""" """Applies a function to each element of the matrix and returns a new matrix."""
return matrix( return matrix(
tuple(func(a) for a in row) tuple(func(a) for a in row)
@ -266,10 +266,10 @@ class matrix(Generic[TNum]):
) )
def homogenize(self) -> 'matrix[TNum]': def homogenize(self) -> 'matrix[TNum]':
"""Convert all elements to variables if any element is a variable.""" """Convert all elements to copapy values if any element is a copapy value."""
if any(isinstance(val, variable) for row in self.values for val in row): if any(isinstance(val, value) for row in self.values for val in row):
return matrix( 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 for row in self.values
) )
else: else:

View File

@ -1,24 +1,24 @@
from . import variable from . import value
from typing import TypeVar, Iterable, Any, overload from typing import TypeVar, Iterable, Any, overload
T = TypeVar("T", int, float) T = TypeVar("T", int, float)
@overload @overload
def mixed_sum(scalars: Iterable[float | variable[float]]) -> float | variable[float]: ... def mixed_sum(scalars: Iterable[float | value[float]]) -> float | value[float]: ...
@overload @overload
def mixed_sum(scalars: Iterable[int | variable[int]]) -> int | variable[int]: ... def mixed_sum(scalars: Iterable[int | value[int]]) -> int | value[int]: ...
@overload @overload
def mixed_sum(scalars: Iterable[T | variable[T]]) -> T | variable[T]: ... def mixed_sum(scalars: Iterable[T | value[T]]) -> T | value[T]: ...
def mixed_sum(scalars: Iterable[int | float | variable[Any]]) -> Any: def mixed_sum(scalars: Iterable[int | float | value[Any]]) -> Any:
sl = list(scalars) sl = list(scalars)
return sum(a for a in sl if not isinstance(a, variable)) +\ return sum(a for a in sl if not isinstance(a, value)) +\
sum(a for a in sl if isinstance(a, variable)) sum(a for a in sl if isinstance(a, value))
def mixed_homogenize(scalars: Iterable[T | variable[T]]) -> Iterable[T] | Iterable[variable[T]]: def mixed_homogenize(scalars: Iterable[T | value[T]]) -> Iterable[T] | Iterable[value[T]]:
if any(isinstance(val, variable) for val in scalars): if any(isinstance(val, value) for val in scalars):
return (variable(val) if not isinstance(val, variable) else val for val in scalars) return (value(val) if not isinstance(val, value) else val for val in scalars)
else: else:
return (val for val in scalars if not isinstance(val, variable)) return (val for val in scalars if not isinstance(val, value))

View File

@ -3,7 +3,7 @@ from . import _binwrite as binw
from coparun_module import coparun, read_data_mem from coparun_module import coparun, read_data_mem
import struct import struct
from ._basic_types import stencil_db_from_package 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 from ._compiler import compile_to_dag
T = TypeVar("T", int, float) T = TypeVar("T", int, float)
@ -28,16 +28,16 @@ class Target():
optimization: Optimization level optimization: Optimization level
""" """
self.sdb = stencil_db_from_package(arch, optimization) 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: 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 variables. """Compiles the code to compute the given values.
Arguments: Arguments:
variables: Variables to compute values: Values to compute
""" """
nodes: list[Node] = [] nodes: list[Node] = []
for s in variables: for s in values:
if isinstance(s, Iterable): if isinstance(s, Iterable):
for net in s: for net in s:
if isinstance(net, Net): if isinstance(net, Net):
@ -46,7 +46,7 @@ class Target():
if isinstance(s, Net): if isinstance(s, Net):
nodes.append(Write(s)) 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) dw.write_com(binw.Command.END_COM)
assert coparun(dw.get_data()) > 0 assert coparun(dw.get_data()) > 0
@ -59,56 +59,56 @@ class Target():
assert coparun(dw.get_data()) > 0 assert coparun(dw.get_data()) > 0
@overload @overload
def read_value(self, net: variable[T]) -> T: ... def read_value(self, net: value[T]) -> T: ...
@overload @overload
def read_value(self, net: NumLike) -> float | int | bool: ... def read_value(self, net: NumLike) -> float | int | bool: ...
@overload @overload
def read_value(self, net: Iterable[T | variable[T]]) -> list[T]: ... def read_value(self, net: Iterable[T | value[T]]) -> list[T]: ...
def read_value(self, net: NumLike | variable[T] | Iterable[T | variable[T]]) -> Any: def read_value(self, net: NumLike | value[T] | Iterable[T | value[T]]) -> Any:
"""Reads the value of a variable. """Reads the numeric value of a copapy type.
Arguments: Arguments:
net: Variable to read net: Values to read
Returns: Returns:
Value of the variable Numeric value
""" """
if isinstance(net, Iterable): 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): if isinstance(net, float | int):
print("Warning: value is not a copypy value") print("Warning: value is not a copypy value")
return net return net
assert isinstance(net, Net), "Variable must be a copapy variable object" assert isinstance(net, Net), "Argument must be a copapy value"
assert net in self._variables, f"Variable {net} not found. It might not have been compiled for the target." assert net in self._values, f"Value {net} not found. It might not have been compiled for the target."
addr, lengths, var_type = self._variables[net] addr, lengths, var_type = self._values[net]
assert lengths > 0 assert lengths > 0
data = read_data_mem(addr, lengths) 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] en = {'little': '<', 'big': '>'}[self.sdb.byteorder]
if var_type == 'float': if var_type == 'float':
if lengths == 4: if lengths == 4:
value = struct.unpack(en + 'f', data)[0] val = struct.unpack(en + 'f', data)[0]
elif lengths == 8: elif lengths == 8:
value = struct.unpack(en + 'd', data)[0] val = struct.unpack(en + 'd', data)[0]
else: else:
raise ValueError(f"Unsupported float length: {lengths} bytes") raise ValueError(f"Unsupported float length: {lengths} bytes")
assert isinstance(value, float) assert isinstance(val, float)
return value return val
elif var_type == 'int': elif var_type == 'int':
assert lengths in (1, 2, 4, 8), f"Unsupported int length: {lengths} bytes" assert lengths in (1, 2, 4, 8), f"Unsupported int length: {lengths} bytes"
value = int.from_bytes(data, byteorder=self.sdb.byteorder, signed=True) val = int.from_bytes(data, byteorder=self.sdb.byteorder, signed=True)
return value return val
elif var_type == 'bool': elif var_type == 'bool':
assert lengths in (1, 2, 4, 8), f"Unsupported int length: {lengths} bytes" assert lengths in (1, 2, 4, 8), f"Unsupported int length: {lengths} bytes"
value = bool.from_bytes(data, byteorder=self.sdb.byteorder, signed=True) val = bool.from_bytes(data, byteorder=self.sdb.byteorder, signed=True)
return value return val
else: 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: 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) 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 assert coparun(dw.get_data()) > 0

View File

@ -1,28 +1,28 @@
from . import variable from . import value
from ._mixed import mixed_sum, mixed_homogenize from ._mixed import mixed_sum, mixed_homogenize
from typing import TypeVar, Iterable, Any, overload, TypeAlias, Callable, Iterator, Generic from typing import TypeVar, Iterable, Any, overload, TypeAlias, Callable, Iterator, Generic
import copapy as cp import copapy as cp
from ._helper_types import TNum from ._helper_types import TNum
#VecNumLike: TypeAlias = 'vector[int] | vector[float] | variable[int] | variable[float] | int | float | bool' #VecNumLike: TypeAlias = 'vector[int] | vector[float] | value[int] | value[float] | int | float | bool'
VecNumLike: TypeAlias = 'vector[Any] | variable[Any] | int | float | bool' VecNumLike: TypeAlias = 'vector[Any] | value[Any] | int | float | bool'
VecIntLike: TypeAlias = 'vector[int] | variable[int] | int' VecIntLike: TypeAlias = 'vector[int] | value[int] | int'
VecFloatLike: TypeAlias = 'vector[float] | variable[float] | float' VecFloatLike: TypeAlias = 'vector[float] | value[float] | float'
U = TypeVar("U", int, float) U = TypeVar("U", int, float)
epsilon = 1e-20 epsilon = 1e-20
class vector(Generic[TNum]): 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]]): def __init__(self, values: Iterable[TNum | value[TNum]]):
"""Create a vector with given values and variables. """Create a vector with given values.
Args: 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: def __repr__(self) -> str:
return f"vector({self.values})" return f"vector({self.values})"
@ -31,10 +31,10 @@ class vector(Generic[TNum]):
return len(self.values) return len(self.values)
@overload @overload
def __getitem__(self, index: int) -> variable[TNum] | TNum: ... def __getitem__(self, index: int) -> value[TNum] | TNum: ...
@overload @overload
def __getitem__(self, index: slice) -> 'vector[TNum]': ... 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): if isinstance(index, slice):
return vector(self.values[index]) return vector(self.values[index])
return self.values[index] return self.values[index]
@ -42,7 +42,7 @@ class vector(Generic[TNum]):
def __neg__(self) -> 'vector[TNum]': def __neg__(self) -> 'vector[TNum]':
return vector(-a for a in self.values) 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) return iter(self.values)
@overload @overload
@ -62,7 +62,7 @@ class vector(Generic[TNum]):
@overload @overload
def __radd__(self: 'vector[float]', other: VecNumLike) -> 'vector[float]': ... def __radd__(self: 'vector[float]', other: VecNumLike) -> 'vector[float]': ...
@overload @overload
def __radd__(self: 'vector[int]', other: variable[int] | int) -> 'vector[int]': ... def __radd__(self: 'vector[int]', other: value[int] | int) -> 'vector[int]': ...
@overload @overload
def __radd__(self, other: VecNumLike) -> 'vector[Any]': ... def __radd__(self, other: VecNumLike) -> 'vector[Any]': ...
def __radd__(self, other: Any) -> Any: def __radd__(self, other: Any) -> Any:
@ -85,7 +85,7 @@ class vector(Generic[TNum]):
@overload @overload
def __rsub__(self: 'vector[float]', other: VecNumLike) -> 'vector[float]': ... def __rsub__(self: 'vector[float]', other: VecNumLike) -> 'vector[float]': ...
@overload @overload
def __rsub__(self: 'vector[int]', other: variable[int] | int) -> 'vector[int]': ... def __rsub__(self: 'vector[int]', other: value[int] | int) -> 'vector[int]': ...
@overload @overload
def __rsub__(self, other: VecNumLike) -> 'vector[Any]': ... def __rsub__(self, other: VecNumLike) -> 'vector[Any]': ...
def __rsub__(self, other: VecNumLike) -> Any: def __rsub__(self, other: VecNumLike) -> Any:
@ -111,7 +111,7 @@ class vector(Generic[TNum]):
@overload @overload
def __rmul__(self: 'vector[float]', other: VecNumLike) -> 'vector[float]': ... def __rmul__(self: 'vector[float]', other: VecNumLike) -> 'vector[float]': ...
@overload @overload
def __rmul__(self: 'vector[int]', other: variable[int] | int) -> 'vector[int]': ... def __rmul__(self: 'vector[int]', other: value[int] | int) -> 'vector[int]': ...
@overload @overload
def __rmul__(self, other: VecNumLike) -> 'vector[Any]': ... def __rmul__(self, other: VecNumLike) -> 'vector[Any]': ...
def __rmul__(self, other: VecNumLike) -> Any: def __rmul__(self, other: VecNumLike) -> Any:
@ -134,7 +134,7 @@ class vector(Generic[TNum]):
@overload @overload
def __rpow__(self: 'vector[float]', other: VecNumLike) -> 'vector[float]': ... def __rpow__(self: 'vector[float]', other: VecNumLike) -> 'vector[float]': ...
@overload @overload
def __rpow__(self: 'vector[int]', other: variable[int] | int) -> 'vector[int]': ... def __rpow__(self: 'vector[int]', other: value[int] | int) -> 'vector[int]': ...
@overload @overload
def __rpow__(self, other: VecNumLike) -> 'vector[Any]': ... def __rpow__(self, other: VecNumLike) -> 'vector[Any]': ...
def __rpow__(self, other: VecNumLike) -> Any: def __rpow__(self, other: VecNumLike) -> Any:
@ -153,26 +153,26 @@ class vector(Generic[TNum]):
return vector(other / a for a in self.values) return vector(other / a for a in self.values)
@overload @overload
def dot(self: 'vector[int]', other: 'vector[int]') -> int | variable[int]: ... def dot(self: 'vector[int]', other: 'vector[int]') -> int | value[int]: ...
@overload @overload
def dot(self, other: 'vector[float]') -> float | variable[float]: ... def dot(self, other: 'vector[float]') -> float | value[float]: ...
@overload @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 @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: def dot(self, other: 'vector[int] | vector[float]') -> Any:
assert len(self.values) == len(other.values), "Vectors must be of same length." 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)) return mixed_sum(a * b for a, b in zip(self.values, other.values))
# @ operator # @ operator
@overload @overload
def __matmul__(self: 'vector[int]', other: 'vector[int]') -> int | variable[int]: ... def __matmul__(self: 'vector[int]', other: 'vector[int]') -> int | value[int]: ...
@overload @overload
def __matmul__(self, other: 'vector[float]') -> float | variable[float]: ... def __matmul__(self, other: 'vector[float]') -> float | value[float]: ...
@overload @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 @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: def __matmul__(self, other: 'vector[int] | vector[float]') -> Any:
return self.dot(other) return self.dot(other)
@ -229,14 +229,14 @@ class vector(Generic[TNum]):
return (len(self.values),) return (len(self.values),)
@overload @overload
def sum(self: 'vector[int]') -> int | variable[int]: ... def sum(self: 'vector[int]') -> int | value[int]: ...
@overload @overload
def sum(self: 'vector[float]') -> float | variable[float]: ... def sum(self: 'vector[float]') -> float | value[float]: ...
def sum(self) -> Any: def sum(self) -> Any:
"""Sum of all vector elements.""" """Sum of all vector elements."""
return mixed_sum(self.values) return mixed_sum(self.values)
def magnitude(self) -> 'float | variable[float]': def magnitude(self) -> 'float | value[float]':
"""Magnitude (length) of the vector.""" """Magnitude (length) of the vector."""
s = mixed_sum(a * a for a in self.values) s = mixed_sum(a * a for a in self.values)
return cp.sqrt(s) return cp.sqrt(s)
@ -247,12 +247,12 @@ class vector(Generic[TNum]):
return self / mag return self / mag
def homogenize(self) -> 'vector[TNum]': 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)) return vector(mixed_homogenize(self))
else: else:
return self 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.""" """Applies a function to each element of the vector and returns a new vector."""
return vector(func(x) for x in self.values) 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) 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.""" """Calculate the dot product of two vectors."""
return v1.dot(v2) 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.""" """Calculate the Euclidean distance between two vectors."""
diff = v1 - v2 diff = v1 - v2
return diff.magnitude() 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.""" """Calculate the scalar projection of v1 onto v2."""
dot_prod = v1.dot(v2) dot_prod = v1.dot(v2)
mag_v2 = v2.magnitude() + epsilon mag_v2 = v2.magnitude() + epsilon
@ -288,7 +288,7 @@ def vector_projection(v1: vector[float], v2: vector[float]) -> vector[float]:
return v2 * scalar_proj 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.""" """Calculate the angle in radians between two vectors."""
dot_prod = v1.dot(v2) dot_prod = v1.dot(v2)
mag_v1 = v1.magnitude() 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) 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.""" """Rotate vector v around a given axis by a specified angle using Rodrigues' rotation formula."""
k = axis.normalize() k = axis.normalize()
cos_angle = cp.cos(angle) cos_angle = cp.cos(angle)

View File

@ -1,15 +1,15 @@
from . import variable, vector from . import value, vector
from ._basic_types import iif, unifloat from ._basic_types import iif, unifloat
from._helper_types import TNum from._helper_types import TNum
from typing import Any, Iterable 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) input_list = list(input_values)
if any(isinstance(val, variable) for val in input_list): if any(isinstance(val, value) for val in input_list):
return (v if isinstance(v, variable) else variable(v) for v in input_list) return (v if isinstance(v, value) else value(v) for v in input_list)
else: 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]: 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)) 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. Applies a median filter to the input vector and returns the median as a unifloat.

View File

@ -27,8 +27,8 @@ def cp_vs_python(path: str):
#v_size = 400 #v_size = 400
iter_size = 30000 iter_size = 30000
v1 = cp.vector(cp.variable(float(v)) for v in range(v_size)) v1 = cp.vector(cp.value(float(v)) for v in range(v_size))
v2 = cp.vector(cp.variable(float(v)) for v in [5]*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)) 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 #v_size = 400
iter_size = 3000 iter_size = 3000
v1 = cp.vector(cp.variable(float(v)) for v in range(v_size)) v1 = cp.vector(cp.value(float(v)) for v in range(v_size))
v2 = cp.vector(cp.variable(float(v)) for v in [5]*v_size) v2 = cp.vector(cp.value(float(v)) for v in [5]*v_size)
test = cp.vector(np.linspace(0, 1, v_size)) test = cp.vector(np.linspace(0, 1, v_size))

View File

@ -1,4 +1,4 @@
from copapy import variable from copapy import value
from copapy.backend import Write from copapy.backend import Write
import copapy.backend as cpb import copapy.backend as cpb
@ -21,8 +21,8 @@ def test_ast_generation():
#r2 = i1 + 9 #r2 = i1 + 9
#out = [Write(r1), Write(r2)] #out = [Write(r1), Write(r2)]
c1 = variable(4) c1 = value(4)
c2 = variable(2) c2 = value(2)
#i1 = c1 * 2 #i1 = c1 * 2
#r1 = i1 + 7 + (c2 + 7 * 9) #r1 = i1 + 7 + (c2 + 7 * 9)
#r2 = i1 + 9 #r2 = i1 + 9

View File

@ -1,4 +1,4 @@
from copapy import variable, grad from copapy import value, grad
import copapy as cp import copapy as cp
import pytest import pytest
@ -6,8 +6,8 @@ import pytest
def test_autograd(): def test_autograd():
# Validate against micrograd results from Andrej Karpathy # Validate against micrograd results from Andrej Karpathy
# https://github.com/karpathy/micrograd/blob/master/test/test_engine.py # https://github.com/karpathy/micrograd/blob/master/test/test_engine.py
a = variable(-4.0) a = value(-4.0)
b = variable(2.0) b = value(2.0)
c = a + b c = a + b
d = a * b + b**3 d = a * b + b**3
c += c + 1 c += c + 1

View File

@ -1,4 +1,4 @@
from copapy import variable from copapy import value
from copapy.backend import Write, compile_to_dag, add_read_command from copapy.backend import Write, compile_to_dag, add_read_command
import copapy as cp import copapy as cp
import subprocess import subprocess
@ -20,7 +20,7 @@ def test_compile():
test_vals = [0.0, -1.5, -2.0, -2.5, -3.0] test_vals = [0.0, -1.5, -2.0, -2.5, -3.0]
# Function with no passing-on-jump as last instruction: # 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] out = [Write(r) for r in ret_test]

View File

@ -9,9 +9,9 @@ from copapy._compiler import patch_entry, CPConstant, get_aux_func_layout
def test_timing_compiler(): 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() #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() t5 = ((t3 * t1) * 2).magnitude()
out = [Write(t5)] out = [Write(t5)]

View File

@ -49,10 +49,10 @@ def test_compile():
#ret = function(c1, c2) #ret = function(c1, c2)
#ret = [c1 // 3.3 + 5] #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() 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() t4 = ((t3 * t1) * 2).sum()
t5 = ((t3 * t1) * 2).magnitude() t5 = ((t3 * t1) * 2).magnitude()

View File

@ -43,10 +43,10 @@ def function(c1: NumLike, c2: NumLike) -> tuple[NumLike, ...]:
@pytest.mark.runner @pytest.mark.runner
def test_compile(): 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() 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() t4 = ((t3 * t1) * 2).sum()
t5 = ((t3 * t1) * 2).magnitude() t5 = ((t3 * t1) * 2).magnitude()

View File

@ -43,10 +43,10 @@ def function(c1: NumLike, c2: NumLike) -> tuple[NumLike, ...]:
@pytest.mark.runner @pytest.mark.runner
def test_compile(): 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() 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() t4 = ((t3 * t1) * 2).sum()
t5 = ((t3 * t1) * 2).magnitude() t5 = ((t3 * t1) * 2).magnitude()

View File

@ -1,4 +1,4 @@
from copapy import variable, NumLike from copapy import value, NumLike
from copapy.backend import Write, compile_to_dag from copapy.backend import Write, compile_to_dag
import copapy import copapy
import subprocess import subprocess
@ -22,7 +22,7 @@ def function(c1: NumLike) -> list[NumLike]:
@pytest.mark.runner @pytest.mark.runner
def test_compile(): def test_compile():
c1 = variable(16) c1 = value(16)
ret = function(c1) ret = function(c1)

View File

@ -1,4 +1,4 @@
from copapy import variable from copapy import value
from copapy.backend import Write, compile_to_dag, add_read_command from copapy.backend import Write, compile_to_dag, add_read_command
import copapy as cp import copapy as cp
import subprocess import subprocess
@ -18,7 +18,7 @@ def run_command(command: list[str]) -> str:
def test_compile_sqrt(): 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] 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] out = [Write(r) for r in ret]
@ -52,7 +52,7 @@ def test_compile_sqrt():
def test_compile_log(): 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] 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] out = [Write(r) for r in ret]
@ -86,7 +86,7 @@ def test_compile_log():
def test_compile_sin(): 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] 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] out = [Write(r) for r in ret]

View File

@ -1,4 +1,4 @@
from copapy import variable, Target, NumLike from copapy import value, Target, NumLike
import pytest import pytest
@ -14,7 +14,7 @@ def function(c1: NumLike) -> list[NumLike]:
def test_compile(): def test_compile():
c1 = variable(16) c1 = value(16)
ret = function(c1) ret = function(c1)

View File

@ -1,4 +1,4 @@
from copapy import variable, Target from copapy import value, Target
import pytest import pytest
import copapy as cp import copapy as cp
import math as ma import math as ma
@ -7,8 +7,8 @@ import warnings
def test_fine(): def test_fine():
a_i = 9 a_i = 9
a_f = 2.5 a_f = 2.5
c_i = variable(a_i) c_i = value(a_i)
c_f = variable(a_f) c_f = value(a_f)
# c_b = variable(True) # c_b = variable(True)
ret_test = (c_f ** 2, ret_test = (c_f ** 2,
@ -49,7 +49,7 @@ def test_fine():
print('* finished') print('* finished')
for test, val2, ref, name in zip(ret_test, re2_test, ret_refe, ('^2', '**-1', 'sqrt_int', 'sqrt_float', 'sin', 'cos', 'tan')): 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) val = tg.read_value(test)
print('+', val, ref, type(val), test.dtype) print('+', val, ref, type(val), test.dtype)
#for t in (int, float, bool): #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, 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] -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))] ret_refe = [r for v in test_vals for r in (ma.sin(v), ma.cos(v), ma.tan(v))]
tg = Target() tg = Target()
@ -72,7 +72,7 @@ def test_trig_precision():
for i, (v, test, ref) in enumerate(zip(test_vals, ret_test, ret_refe)): for i, (v, test, ref) in enumerate(zip(test_vals, ret_test, ret_refe)):
func_name = ['sin', 'cos', 'tan'][i % 3] func_name = ['sin', 'cos', 'tan'][i % 3]
assert isinstance(test, cp.variable) assert isinstance(test, cp.value)
val = tg.read_value(test) val = tg.read_value(test)
print(f"+ Result of {func_name}: {val}; reference: {ref}") 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] 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, 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] -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)), ret_test = [r for v in test_vals for r in (cp.asin(value(v)),
cp.acos(variable(v)), cp.acos(value(v)),
cp.atan(variable(v)), cp.atan(value(v)),
cp.atan2(variable(v), variable(3)), cp.atan2(value(v), value(3)),
cp.atan2(variable(v), variable(-3)),)] cp.atan2(value(v), value(-3)),)]
ret_refe = [r for v in test_vals for r in (ma.asin(v), ret_refe = [r for v in test_vals for r in (ma.asin(v),
ma.acos(v), ma.acos(v),
ma.atan(v), ma.atan(v),
@ -102,7 +102,7 @@ def test_arcus_trig_precision():
for i, (test, ref) in enumerate(zip(ret_test, ret_refe)): for i, (test, ref) in enumerate(zip(ret_test, ret_refe)):
func_name = ['asin', 'acos', 'atan', 'atan2[1]', 'atan2[2]'][i % 5] 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) val = tg.read_value(test)
print(f"+ Result of {func_name}: {val}; reference: {ref}") 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] #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(): 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] 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),)] ret_refe = [r for v in test_vals for r in (cp.sqrt(v),)]
tg = Target() tg = Target()
@ -122,7 +122,7 @@ def test_sqrt_precision():
for i, (test, ref) in enumerate(zip(ret_test, ret_refe)): for i, (test, ref) in enumerate(zip(ret_test, ret_refe)):
func_name = 'sqrt' func_name = 'sqrt'
assert isinstance(test, cp.variable) assert isinstance(test, cp.value)
val = tg.read_value(test) val = tg.read_value(test)
print(f"+ Result of {func_name}: {val}; reference: {ref}") 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] 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, 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] -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))), ret_test = [r for v in test_vals for r in (cp.log(value(abs(v))),
cp.exp(variable(v)))] cp.exp(value(v)))]
ret_refe = [r for v in test_vals for r in (ma.log(abs(v)), ret_refe = [r for v in test_vals for r in (ma.log(abs(v)),
ma.exp(v))] ma.exp(v))]
@ -146,7 +146,7 @@ def test_log_exp_precision():
for i, (test, ref) in enumerate(zip(ret_test, ret_refe)): for i, (test, ref) in enumerate(zip(ret_test, ret_refe)):
func_name = ['log', 'exp'][i % 2] func_name = ['log', 'exp'][i % 2]
assert isinstance(test, cp.variable) assert isinstance(test, cp.value)
val = tg.read_value(test) val = tg.read_value(test)
print(f"+ Result of {func_name}: {val}; reference: {ref}") 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] 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]

View File

@ -13,11 +13,11 @@ def test_matrix_init():
def test_matrix_with_variables(): def test_matrix_with_variables():
"""Test matrix initialization 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.rows == 2
assert m1.cols == 2 assert m1.cols == 2
assert isinstance(m1[0][0], cp.variable) assert isinstance(m1[0][0], cp.value)
assert isinstance(m1[1][1], cp.variable) assert isinstance(m1[1][1], cp.value)
def test_matrix_addition(): def test_matrix_addition():
@ -201,12 +201,12 @@ def test_matrix_map():
def test_matrix_homogenize(): def test_matrix_homogenize():
"""Test homogenizing matrix (converting to all variables)""" """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() m_homo = m.homogenize()
for row in m_homo: for row in m_homo:
for elem in row: for elem in row:
assert isinstance(elem, cp.variable) assert isinstance(elem, cp.value)
def test_identity_matrix(): def test_identity_matrix():
@ -254,8 +254,8 @@ def test_diagonal_matrix():
def test_matrix_with_variables_compiled(): def test_matrix_with_variables_compiled():
"""Test matrix operations with variables in compilation""" """Test matrix operations with variables in compilation"""
m = cp.matrix([[cp.variable(1), 2], [3, cp.variable(4)]]) m = cp.matrix([[cp.value(1), 2], [3, cp.value(4)]])
v = cp.vector([cp.variable(5), 6]) v = cp.vector([cp.value(5), 6])
result = m @ v result = m @ v
# result[0] = 1*5 + 2*6 = 17 # result[0] = 1*5 + 2*6 = 17

View File

@ -1,4 +1,4 @@
from copapy import variable, Target, NumLike, iif from copapy import value, Target, NumLike, iif
import pytest import pytest
import copapy import copapy
@ -42,11 +42,11 @@ def iiftests(c1: NumLike) -> list[NumLike]:
def test_compile(): def test_compile():
c_i = variable(9) c_i = value(9)
c_f = variable(1.111) c_f = value(1.111)
c_b = variable(True) 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) 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() tg = Target()
@ -57,7 +57,7 @@ def test_compile():
print('* finished') print('* finished')
for test, ref in zip(ret_test, ret_ref): for test, ref in zip(ret_test, ret_ref):
assert isinstance(test, copapy.variable) assert isinstance(test, copapy.value)
val = tg.read_value(test) val = tg.read_value(test)
print('+', val, ref, test.dtype) print('+', val, ref, test.dtype)
for t in (int, float, bool): for t in (int, float, bool):

View File

@ -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 from copapy.backend import Write, compile_to_dag, add_read_command
import subprocess import subprocess
from copapy import _binwrite from copapy import _binwrite
@ -84,11 +84,11 @@ def iiftests(c1: NumLike) -> list[NumLike]:
@pytest.mark.runner @pytest.mark.runner
def test_compile(): def test_compile():
c_i = variable(9) c_i = value(9)
c_f = variable(1.111) c_f = value(1.111)
c_b = variable(True) 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_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] out = [Write(r) for r in ret_test]
@ -145,7 +145,7 @@ def test_compile():
result_data = parse_results(result) result_data = parse_results(result)
for test, ref in zip(ret_test, ret_ref): for test, ref in zip(ret_test, ret_ref):
assert isinstance(test, variable) assert isinstance(test, value)
address = variables[test][0] address = variables[test][0]
data = result_data[address] data = result_data[address]
if test.dtype == 'int': if test.dtype == 'int':

View File

@ -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 from copapy.backend import Write, compile_to_dag, add_read_command
import subprocess import subprocess
from copapy import _binwrite from copapy import _binwrite
@ -86,11 +86,11 @@ def iiftests(c1: NumLike) -> list[NumLike]:
@pytest.mark.runner @pytest.mark.runner
def test_compile(): def test_compile():
c_i = variable(9) c_i = value(9)
c_f = variable(1.111) c_f = value(1.111)
c_b = variable(True) 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_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) #ret_test = (c_i * 100 // 5, c_f * 10 // 5)
@ -147,7 +147,7 @@ def test_compile():
result_data = parse_results(result) result_data = parse_results(result)
for test, ref in zip(ret_test, ret_ref): for test, ref in zip(ret_test, ret_ref):
assert isinstance(test, variable) assert isinstance(test, value)
address = variables[test][0] address = variables[test][0]
data = result_data[address] data = result_data[address]
if test.dtype == 'int': if test.dtype == 'int':

View File

@ -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 from copapy.backend import Write, compile_to_dag, add_read_command
import subprocess import subprocess
from copapy import _binwrite from copapy import _binwrite
@ -77,7 +77,7 @@ def test_compile():
#t4 = ((t3 * t1) * 2).sum() #t4 = ((t3 * t1) * 2).sum()
#t5 = ((t3 * t1) * 2).magnitude() #t5 = ((t3 * t1) * 2).magnitude()
c_i = variable(9) c_i = value(9)
#c_f = variable(1.111) #c_f = variable(1.111)
#c_b = variable(True) #c_b = variable(True)
@ -87,7 +87,7 @@ def test_compile():
#ret_test = [cp.sin(c_i), cp.asin(variable(0.0))] #ret_test = [cp.sin(c_i), cp.asin(variable(0.0))]
#ret_ref = [cp.sin(9), cp.asin(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] = [] ret_ref: list[float] = []
#sval = variable(8.0) #sval = variable(8.0)
#tval = 8.0 #tval = 8.0
@ -155,7 +155,7 @@ def test_compile():
result_data = parse_results(result) result_data = parse_results(result)
for test, ref in zip(ret_test, ret_ref): for test, ref in zip(ret_test, ret_ref):
assert isinstance(test, variable) assert isinstance(test, value)
address = variables[test][0] address = variables[test][0]
data = result_data[address] data = result_data[address]
if test.dtype == 'int': if test.dtype == 'int':

View File

@ -1,11 +1,11 @@
from copapy import variable, Target, iif from copapy import value, Target, iif
import pytest import pytest
import copapy import copapy
def test_compile(): def test_compile():
c_i = variable(9) c_i = value(9)
c_f = variable(2.5) c_f = value(2.5)
# c_b = variable(True) # 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)) 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') print('* finished')
for test, ref in zip(ret_test, ret_ref): for test, ref in zip(ret_test, ret_ref):
assert isinstance(test, copapy.variable) assert isinstance(test, copapy.value)
val = tg.read_value(test) val = tg.read_value(test)
print('+', val, ref, type(val), test.dtype) print('+', val, ref, type(val), test.dtype)
#for t in (int, float, bool): #for t in (int, float, bool):

View File

@ -3,8 +3,8 @@ import pytest
def test_readme_example(): def test_readme_example():
# Define variables # Define variables
a = cp.variable(0.25) a = cp.value(0.25)
b = cp.variable(0.87) b = cp.value(0.87)
# Define computations # Define computations
c = a + b * 2.0 c = a + b * 2.0

View File

@ -10,7 +10,7 @@ target = cp.vector([0.7, 0.7])
alpha = 0.1 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.""" """Return positions of joint and end-effector."""
joint = cp.vector([l1 * cp.cos(theta1), l1 * cp.sin(theta1)]) joint = cp.vector([l1 * cp.cos(theta1), l1 * cp.sin(theta1)])
end_effector = joint + cp.vector([l2 * cp.cos(theta1 + theta2), 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(): def test_two_arms():
target_vec = cp.vector(target) 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]) joint = cp.vector([0.0, 0.0])
effector = cp.vector([0.0, 0.0]) effector = cp.vector([0.0, 0.0])

View File

@ -5,38 +5,38 @@ from copapy import filters
def test_vectors_init(): def test_vectors_init():
tt1 = cp.vector(range(3)) + cp.vector([1.1, 2.2, 3.3]) 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) 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) tt5 = cp.vector([1, 2, 3]).dot(tt4)
print(tt1, tt2, tt3, tt4, tt5) print(tt1, tt2, tt3, tt4, tt5)
def test_compiled_vectors(): 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() 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() t4 = ((t3 * t1) * 2).sum()
t5 = ((t3 * t1) * 2).magnitude() 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 = cp.Target()
tg.compile(t2, t4, t5, t6) tg.compile(t2, t4, t5, t6)
tg.run() tg.run()
assert isinstance(t2, cp.variable) assert isinstance(t2, cp.value)
assert tg.read_value(t2) == 10 + 11 + 12 + 0 + 1 + 2 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 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 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] 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(): def test_sort_vector():
vlist = [50, 21, 20, 10, 22, 1, 80, 70, 90] 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) #t1 = cp.vector(v for v in vlist)
t2 = filters.median(t1) t2 = filters.median(t1)

View File

@ -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.backend import Write, compile_to_dag, stencil_db_from_package
from copapy._binwrite import Command from copapy._binwrite import Command
import copapy as cp import copapy as cp
@ -6,7 +6,7 @@ import copapy as cp
def compile_to_x86_64() -> None: def compile_to_x86_64() -> None:
"""Test compilation of a simple program for x86_64.""" """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 / 4, c1 / -4, c1 // 4, c1 // -4, (c1 * -1) // 4]
ret = [c1 // 3.3 + 5] ret = [c1 // 3.3 + 5]
@ -29,14 +29,14 @@ def compile_to_x86_64() -> None:
def compile_to_x86() -> None: def compile_to_x86() -> None:
"""Test compilation of a simple program for x86 32 bit.""" """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 / 4, c1 / -4, c1 // 4, c1 // -4, (c1 * -1) // 4]
ret = [c1 // 3.3 + 5] ret = [c1 // 3.3 + 5]
#ret = [cp.sqrt(c1)] #ret = [cp.sqrt(c1)]
#c2 = cp._math.get_42() #c2 = cp._math.get_42()
#ret = [c2] #ret = [c2]
ret = [cp.sin(variable(2.5))] ret = [cp.sin(value(2.5))]
out = [Write(r) for r in ret] out = [Write(r) for r in ret]
@ -53,7 +53,7 @@ def compile_to_x86() -> None:
def compile_to_aarch64() -> None: def compile_to_aarch64() -> None:
"""Test compilation of a simple program for arm64.""" """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 = [c1 / 4, c1 / -4, c1 // 4, c1 // -4, (c1 * -1) // 4]
#ret = [cp.sin(c1), cp.sqrt(c1) + 5] #ret = [cp.sin(c1), cp.sqrt(c1) + 5]