helping functions separated for vectors and matrices

This commit is contained in:
Nicolas Kruse 2025-12-01 00:13:08 +01:00
parent bb4472eccb
commit 29f5a26278
2 changed files with 31 additions and 7 deletions

24
src/copapy/_mixed.py Normal file
View File

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

View File

@ -1,4 +1,5 @@
from . import variable from . import variable
from ._mixed import mixed_sum, mixed_homogenize
from typing import Generic, TypeVar, Iterable, Any, overload, TypeAlias, Callable, Iterator from typing import Generic, TypeVar, Iterable, Any, overload, TypeAlias, Callable, Iterator
import copapy as cp import copapy as cp
@ -31,7 +32,7 @@ class vector(Generic[T]):
def __getitem__(self, index: int) -> variable[T] | T: def __getitem__(self, index: int) -> variable[T] | T:
return self.values[index] return self.values[index]
def __neg__(self) -> 'vector[float] | vector[int]': def __neg__(self) -> 'vector[T]':
return vector(-a for a in self.values) return vector(-a for a in self.values)
def __iter__(self) -> Iterator[variable[T] | T]: def __iter__(self) -> Iterator[variable[T] | T]:
@ -125,7 +126,7 @@ class vector(Generic[T]):
def dot(self, other: 'vector[int] | vector[float]') -> float | int | variable[float] | variable[int]: ... def dot(self, other: 'vector[int] | vector[float]') -> float | int | variable[float] | variable[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 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
@ -156,13 +157,12 @@ class vector(Generic[T]):
def sum(self: 'vector[float]') -> float | variable[float]: ... def sum(self: 'vector[float]') -> float | variable[float]: ...
def sum(self) -> Any: def sum(self) -> Any:
"""Sum of all vector elements.""" """Sum of all vector elements."""
return sum(a for a in self.values if isinstance(a, variable)) +\ return mixed_sum(self.values)
sum(a for a in self.values if not isinstance(a, variable))
def magnitude(self) -> 'float | variable[float]': def magnitude(self) -> 'float | variable[float]':
"""Magnitude (length) of the vector.""" """Magnitude (length) of the vector."""
s = sum(a * a for a in self.values) s = mixed_sum(a * a for a in self.values)
return cp.sqrt(s) if isinstance(s, variable) else cp.sqrt(s) return cp.sqrt(s)
def normalize(self) -> 'vector[float]': def normalize(self) -> 'vector[float]':
"""Returns a normalized (unit length) version of the vector.""" """Returns a normalized (unit length) version of the vector."""
@ -171,7 +171,7 @@ class vector(Generic[T]):
def homogenize(self) -> 'vector[T]': def homogenize(self) -> 'vector[T]':
if any(isinstance(val, variable) for val in self.values): if any(isinstance(val, variable) for val in self.values):
return vector(variable(val) if not isinstance(val, variable) else val for val in self.values) return vector(mixed_homogenize(self))
else: else:
return self return self