From 31564cc45e52418a7592361007bc7295867d1c4a Mon Sep 17 00:00:00 2001 From: bleudev Date: Mon, 10 Jun 2024 23:04:08 +0300 Subject: [PATCH 1/6] Init progressions classes --- ufpy/__init__.py | 3 +++ ufpy/algebra/__init__.py | 2 ++ ufpy/algebra/arithmetic.py | 6 ++++++ ufpy/algebra/func_sequence.py | 6 ++++++ 4 files changed, 17 insertions(+) create mode 100644 ufpy/algebra/__init__.py create mode 100644 ufpy/algebra/arithmetic.py create mode 100644 ufpy/algebra/func_sequence.py diff --git a/ufpy/__init__.py b/ufpy/__init__.py index e15f6f8..6dfd2b2 100644 --- a/ufpy/__init__.py +++ b/ufpy/__init__.py @@ -1,7 +1,10 @@ __version__ = '0.1.2' +from ufpy import algebra # Typing package from ufpy import typ +from ufpy.algebra.arithmetic import * +from ufpy.algebra.func_sequence import * from ufpy.cmp import * from ufpy.math_op import * from ufpy.path_tools import * diff --git a/ufpy/algebra/__init__.py b/ufpy/algebra/__init__.py new file mode 100644 index 0000000..beffc62 --- /dev/null +++ b/ufpy/algebra/__init__.py @@ -0,0 +1,2 @@ +from ufpy.algebra.arithmetic import * +from ufpy.algebra.func_sequence import * diff --git a/ufpy/algebra/arithmetic.py b/ufpy/algebra/arithmetic.py new file mode 100644 index 0000000..a62e440 --- /dev/null +++ b/ufpy/algebra/arithmetic.py @@ -0,0 +1,6 @@ +__all__ = ( + 'Arithmetic', +) + +class Arithmetic: + ... diff --git a/ufpy/algebra/func_sequence.py b/ufpy/algebra/func_sequence.py new file mode 100644 index 0000000..b52aee4 --- /dev/null +++ b/ufpy/algebra/func_sequence.py @@ -0,0 +1,6 @@ +__all__ = ( + 'FunctionSequence', +) + +class FunctionSequence: + ... From 31473734a87112f2086a36f41b669d21940aa0f7 Mon Sep 17 00:00:00 2001 From: bleudev Date: Tue, 11 Jun 2024 12:53:17 +0300 Subject: [PATCH 2/6] Many things --- ufpy/algebra/arithmetic.py | 22 +++++++- ufpy/algebra/func_sequence.py | 96 ++++++++++++++++++++++++++++++++++- 2 files changed, 114 insertions(+), 4 deletions(-) diff --git a/ufpy/algebra/arithmetic.py b/ufpy/algebra/arithmetic.py index a62e440..e487537 100644 --- a/ufpy/algebra/arithmetic.py +++ b/ufpy/algebra/arithmetic.py @@ -2,5 +2,23 @@ 'Arithmetic', ) -class Arithmetic: - ... +from typing import TypeVar + +from ufpy.algebra.func_sequence import FunctionSequence + +VT = TypeVar('VT', int, float, int | float) +DT = TypeVar('DT', int, float, int | float) + +class Arithmetic(FunctionSequence[VT, DT], name_of_elements='a'): + def k_func(self, a_m: VT, a_n: VT, m: int, n: int) -> VT: + return (a_n - a_m) / (n - m) + + @property + def d(self) -> DT: + return self.k + + def __init__(self, d: VT = None, **kwargs): + def f(n, k, am, m): + return am + k * (n - m) + + super().__init__(f, d, **kwargs) diff --git a/ufpy/algebra/func_sequence.py b/ufpy/algebra/func_sequence.py index b52aee4..4e3b4ce 100644 --- a/ufpy/algebra/func_sequence.py +++ b/ufpy/algebra/func_sequence.py @@ -2,5 +2,97 @@ 'FunctionSequence', ) -class FunctionSequence: - ... +from typing import Callable, TypeVar, Generic, Literal, overload + +VT = TypeVar('VT', int, float, int | float) +KT = TypeVar('KT', int, float, int | float) + +class FunctionSequence(Generic[VT, KT]): + def __resolve_item(self, kwarg: tuple[str, VT]) -> tuple[int, VT] | None: + name, value = kwarg + name = name.lower() + + if name.startswith(self.__name_of_elements) and (x := name.replace(self.__name_of_elements, '')).isdigit(): + if int(x) <= 0: + raise Exception("'n' must be bigger that 0!") + return int(x), value + return None + + def __resolve_sum_and_composition(self, kwarg: tuple[str, VT]) -> tuple[Literal['s', 'p'], int, VT] | None: + name, value = kwarg + name = name.lower() + + if name.startswith('s') and (x := name.replace('s', '')).isdigit(): + return 's', int(x), value + if name.startswith('p') and (y := name.replace('p', '')): + return 'p', int(y), value + return None + + def __process_float(self, x: float): + return int(x) if x.is_integer() else x + + def k_func(self, a_m: VT, a_n: VT, m: int, n: int) -> KT: + ... # return k + + def __init_subclass__(cls, name_of_elements: str, **kwargs): + super().__init_subclass__(**kwargs) + cls.__name_of_elements = name_of_elements + + def __init__(self, f: Callable[[int, KT, VT, int], VT], k: KT = None, **kwargs: VT): + self.ref_func = f + self.f = lambda n: self.ref_func(n, self.k, self.first, 1) + + el = [x for i in kwargs.items() if (x := self.__resolve_item(i))] + + if k: + self.k = self.__process_float(k) + if len(el) >= 1: + i1, v1 = el[0] + self.first = self.__process_float(self.ref_func(1, self.k, v1, i1)) + return + if len(el) >= 2: + (i1, v1), (i2, v2) = el[0], el[1] + self.k = self.__process_float(self.k_func(v1, v2, i1, i2)) + self.first = self.__process_float(self.ref_func(1, self.k, v1, i1)) + return + raise Exception("__init__ can't get k") + + @overload + def __call__(self, n: int): ... + @overload + def __call__(self, start: int, end: int): ... + def __call__(self, start_or_end: int, end: int = None) -> VT | list[VT]: + start = start_or_end + if not end: + end = start_or_end + + r = [] + + for i in range(start, end+1): + r.append(self.__process_float(self.f(i))) + + return r if len(r) > 1 else r[0] + + def __getitem__(self, n: int | slice): + if isinstance(n, slice): + start, end = n.start, n.stop + print(start, end) + return self(start, end) + return self(n) + + def s(self, n: int) -> VT: + r = self.first + + for i in range(2, n+1): + r += self(i) + + return self.__process_float(r) + + def p(self, n: int) -> VT: + r = self.first + + for i in range(2, n + 1): + r *= self(i) + + return self.__process_float(r) + From 15d9cde59c3d4236c1860d228176166c5e040f74 Mon Sep 17 00:00:00 2001 From: bleudev Date: Tue, 11 Jun 2024 18:22:49 +0300 Subject: [PATCH 3/6] =?UTF-8?q?Many=20things=20=E2=84=962?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ufpy/algebra/func_sequence.py | 28 ++++++++++++---------------- ufpy/utils.py | 8 +++++++- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/ufpy/algebra/func_sequence.py b/ufpy/algebra/func_sequence.py index 4e3b4ce..f3c2240 100644 --- a/ufpy/algebra/func_sequence.py +++ b/ufpy/algebra/func_sequence.py @@ -4,6 +4,8 @@ from typing import Callable, TypeVar, Generic, Literal, overload +from ufpy.utils import mul + VT = TypeVar('VT', int, float, int | float) KT = TypeVar('KT', int, float, int | float) @@ -58,10 +60,10 @@ def __init__(self, f: Callable[[int, KT, VT, int], VT], k: KT = None, **kwargs: raise Exception("__init__ can't get k") @overload - def __call__(self, n: int): ... + def __call__(self, n: int) -> VT: ... @overload - def __call__(self, start: int, end: int): ... - def __call__(self, start_or_end: int, end: int = None) -> VT | list[VT]: + def __call__(self, start: int, end: int) -> list[VT]: ... + def __call__(self, start_or_end: int, end: int = None): start = start_or_end if not end: end = start_or_end @@ -73,26 +75,20 @@ def __call__(self, start_or_end: int, end: int = None) -> VT | list[VT]: return r if len(r) > 1 else r[0] + @overload + def __getitem__(self, n: int) -> VT: ... + @overload + def __getitem__(self, n: slice) -> list[VT]: ... def __getitem__(self, n: int | slice): if isinstance(n, slice): - start, end = n.start, n.stop + start, end = x if (x := n.start) else 1, n.stop print(start, end) return self(start, end) return self(n) def s(self, n: int) -> VT: - r = self.first - - for i in range(2, n+1): - r += self(i) - - return self.__process_float(r) + return sum(self.__getitem__(slice(n))) def p(self, n: int) -> VT: - r = self.first - - for i in range(2, n + 1): - r *= self(i) - - return self.__process_float(r) + return mul(self.__getitem__(slice(n))) diff --git a/ufpy/utils.py b/ufpy/utils.py index 3d3a984..ad54ddd 100644 --- a/ufpy/utils.py +++ b/ufpy/utils.py @@ -1,10 +1,13 @@ __all__ = ( + 'mul', 'get_items_for_several_keys', 'set_items_for_several_keys', 'del_items_for_several_keys', ) -from typing import TypeVar +from functools import reduce +from operator import mul as op_mul +from typing import TypeVar, Iterable from ufpy.typ import SupportsGet, SupportsSetItem, SupportsDelItem, AnyCollection @@ -13,6 +16,9 @@ DV = TypeVar('DV') +def mul(iterable: Iterable[VT]) -> VT: + return reduce(op_mul, iterable, 1) + def get_items_for_several_keys(o: SupportsGet[KT, VT], keys: AnyCollection[KT], default: DV = None) -> list[VT | DV]: return [o.get(k, default) for k in keys] From cbbeedff5060494e761b9531dfc8fb4636e26659 Mon Sep 17 00:00:00 2001 From: bleudev Date: Sat, 13 Jul 2024 01:20:17 +0300 Subject: [PATCH 4/6] Fibonacci + Geometric + some updates --- ufpy/__init__.py | 51 ++++++++--- ufpy/algebra/__init__.py | 2 + ufpy/algebra/arithmetic.py | 4 +- ufpy/algebra/fibonacci.py | 69 +++++++++++++++ ufpy/algebra/func_sequence.py | 35 +++++--- ufpy/algebra/geometric.py | 24 ++++++ ufpy/ustl/__init__.py | 1 + ufpy/ustl/stack.py | 156 ++++++++++++++++++++++++++++++++++ 8 files changed, 320 insertions(+), 22 deletions(-) create mode 100644 ufpy/algebra/fibonacci.py create mode 100644 ufpy/algebra/geometric.py create mode 100644 ufpy/ustl/__init__.py create mode 100644 ufpy/ustl/stack.py diff --git a/ufpy/__init__.py b/ufpy/__init__.py index 6dfd2b2..f1da47b 100644 --- a/ufpy/__init__.py +++ b/ufpy/__init__.py @@ -1,15 +1,46 @@ -__version__ = '0.1.2' +# Deprecated +def __deprecated(deprecated_name: str, x, start_version: str, end_version: str): + """This is a decorator which can be used to mark functions + as deprecated. It will result in a warning being emitted + when the function is used.""" + from functools import wraps + from warnings import warn, simplefilter -from ufpy import algebra -# Typing package -from ufpy import typ -from ufpy.algebra.arithmetic import * -from ufpy.algebra.func_sequence import * + @wraps(x) + def new_func(*args, **kwargs): + simplefilter('always', DeprecationWarning) # turn off filter + warn(f"{deprecated_name} is deprecated in {start_version} and will be deleted in {end_version}. " + f"Use {x.__name__} instead.", + category=DeprecationWarning, + stacklevel=2) + simplefilter('default', DeprecationWarning) # reset filter + return x(*args, **kwargs) + return new_func + + +__version__ = '0.2' from ufpy.cmp import * from ufpy.math_op import * -from ufpy.path_tools import * -from ufpy.typ.protocols import * -from ufpy.typ.type_alias import * from ufpy.udict import * -from ufpy.ustack import * from ufpy.utils import * + +# Typing package +__typ_version__ = '0.1' +from ufpy.typ import * + +# Ustl package +__ustl_version = '0.1' +from ufpy.ustl import * +UStack = __deprecated("UStack", Stack, '0.2', '0.5') + +# Path package +__path_version__ = '0.1' +from ufpy.path import * + +# GitHub package +__github_version__ = '0.1' +from ufpy.github import * + +# Algebra package +__algebra_version = '0.1' +from ufpy.algebra import * diff --git a/ufpy/algebra/__init__.py b/ufpy/algebra/__init__.py index beffc62..7896d3b 100644 --- a/ufpy/algebra/__init__.py +++ b/ufpy/algebra/__init__.py @@ -1,2 +1,4 @@ from ufpy.algebra.arithmetic import * +from ufpy.algebra.fibonacci import * from ufpy.algebra.func_sequence import * +from ufpy.algebra.geometric import * diff --git a/ufpy/algebra/arithmetic.py b/ufpy/algebra/arithmetic.py index e487537..09609bc 100644 --- a/ufpy/algebra/arithmetic.py +++ b/ufpy/algebra/arithmetic.py @@ -10,14 +10,14 @@ DT = TypeVar('DT', int, float, int | float) class Arithmetic(FunctionSequence[VT, DT], name_of_elements='a'): - def k_func(self, a_m: VT, a_n: VT, m: int, n: int) -> VT: + def k_func(self, a_m: VT, a_n: VT, m: int, n: int) -> DT: return (a_n - a_m) / (n - m) @property def d(self) -> DT: return self.k - def __init__(self, d: VT = None, **kwargs): + def __init__(self, *, d: DT = None, **kwargs): def f(n, k, am, m): return am + k * (n - m) diff --git a/ufpy/algebra/fibonacci.py b/ufpy/algebra/fibonacci.py new file mode 100644 index 0000000..ab6f1b5 --- /dev/null +++ b/ufpy/algebra/fibonacci.py @@ -0,0 +1,69 @@ +__all__ = ( + 'Fibonacci', +) + +from typing import overload, Any + +from ufpy.utils import mul + + +class Fibonacci: + # 1, 1, 2, 3, 5, 8, ... + + @overload + def __call__(self, n: int) -> int: ... + @overload + def __call__(self, start: int, end: int) -> list[int]: ... + def __call__(self, start_or_end: int, end: int = None): + # Format input parameters + if not end: + end = start_or_end + start = start_or_end + + # Generate fibonacci sequence from 1st to `end`th item + r = [] + + for i in range(end): + if i <= 1: + r.append(1) + else: + r.append(r[i - 1] + r[i - 2]) + + # Return result + if start == end: + return r[-1] + else: + return r[start - 1:] + + def __getitem__(self, n: int | slice): + if isinstance(n, slice): + start, end = x if (x := n.start) else 1, n.stop + return self(start, end) + return self(n) + + def __check_for_list(self, l_or_v: list | Any): + if isinstance(l_or_v, list): + return l_or_v + return [l_or_v] + + @overload + def s(self, n: int) -> int: ... + @overload + def s(self, start: int, end: int) -> int: ... + def s(self, start_or_n: int, end: int = None) -> int: + if end: + start = start_or_n + else: + start, end = 1, start_or_n + return sum(self.__check_for_list(self(start, end))) + + @overload + def p(self, n: int) -> int: ... + @overload + def p(self, start: int, end: int) -> int: ... + def p(self, start_or_n: int, end: int = None) -> int: + if end: + start = start_or_n + else: + start, end = 1, start_or_n + return mul(self.__check_for_list(self(start, end))) diff --git a/ufpy/algebra/func_sequence.py b/ufpy/algebra/func_sequence.py index f3c2240..2b73a02 100644 --- a/ufpy/algebra/func_sequence.py +++ b/ufpy/algebra/func_sequence.py @@ -2,7 +2,7 @@ 'FunctionSequence', ) -from typing import Callable, TypeVar, Generic, Literal, overload +from typing import Callable, TypeVar, Generic, Literal, overload, Any from ufpy.utils import mul @@ -75,20 +75,35 @@ def __call__(self, start_or_end: int, end: int = None): return r if len(r) > 1 else r[0] - @overload - def __getitem__(self, n: int) -> VT: ... - @overload - def __getitem__(self, n: slice) -> list[VT]: ... def __getitem__(self, n: int | slice): if isinstance(n, slice): start, end = x if (x := n.start) else 1, n.stop - print(start, end) return self(start, end) return self(n) - def s(self, n: int) -> VT: - return sum(self.__getitem__(slice(n))) + def __check_for_list(self, l_or_v: list | Any): + if isinstance(l_or_v, list): + return l_or_v + return [l_or_v] - def p(self, n: int) -> VT: - return mul(self.__getitem__(slice(n))) + @overload + def s(self, n: int) -> VT: ... + @overload + def s(self, start: int, end: int) -> VT: ... + def s(self, start_or_n: int, end: int = None) -> VT: + if end: + start = start_or_n + else: + start, end = 1, start_or_n + return sum(self.__check_for_list(self(start, end))) + @overload + def p(self, n: int) -> VT: ... + @overload + def p(self, start: int, end: int) -> VT: ... + def p(self, start_or_n: int, end: int = None) -> VT: + if end: + start = start_or_n + else: + start, end = 1, start_or_n + return mul(self.__check_for_list(self(start, end))) diff --git a/ufpy/algebra/geometric.py b/ufpy/algebra/geometric.py new file mode 100644 index 0000000..c96f79a --- /dev/null +++ b/ufpy/algebra/geometric.py @@ -0,0 +1,24 @@ +__all__ = ( + 'Geometric', +) + +from typing import TypeVar + +from ufpy.algebra.func_sequence import FunctionSequence + +VT = TypeVar('VT', int, float, int | float) +QT = TypeVar('QT', int, float, int | float) + +class Geometric(FunctionSequence[VT, QT], name_of_elements='b'): + def k_func(self, a_m: VT, a_n: VT, m: int, n: int) -> QT: + return (a_n / a_m) ** (1 / (n - m)) + + @property + def q(self) -> QT: + return self.k + + def __init__(self, *, q: QT = None, **kwargs): + def f(n, k, am, m): + return am * (k**(n-m)) + + super().__init__(f, q, **kwargs) diff --git a/ufpy/ustl/__init__.py b/ufpy/ustl/__init__.py new file mode 100644 index 0000000..cf00bd9 --- /dev/null +++ b/ufpy/ustl/__init__.py @@ -0,0 +1 @@ +from ufpy.ustl.stack import * diff --git a/ufpy/ustl/stack.py b/ufpy/ustl/stack.py new file mode 100644 index 0000000..ec41188 --- /dev/null +++ b/ufpy/ustl/stack.py @@ -0,0 +1,156 @@ +from __future__ import annotations + +from typing import Generic, TypeVar, Iterable, Callable + +from ufpy.cmp import cmp_generator +from ufpy.math_op import r_generator, i_generator +from ufpy.typ import AnyCollection, NumberLiteral, SupportsMul, SupportsTrueDiv, Empty + +__all__ = ( + "Stack", +) + +T = TypeVar("T") +T2 = TypeVar("T2") + +def convert_to_stack(other: Stack[T] | AnyCollection[T] | T) -> Stack[T]: + if isinstance(other, Stack): + return other + if isinstance(other, (list, tuple)): + return Stack(iterable=other) + return Stack(other) + +def convert_to_list_for_mul_and_div(other: Stack[T] | AnyCollection[T] | T, __len: int = None) -> list[T]: + if isinstance(other, Stack): + return other.elements + if isinstance(other, (list, tuple)): + return list(other) + return [other for _ in range(__len)] + +@cmp_generator +@i_generator +@r_generator +class Stack(Generic[T]): + """ + Class for simplifying working with stacks in Python. + """ + def __init__(self, *elements: T, iterable: Iterable[T] = None): + if iterable: + elements = iterable + self.__elements = list(elements) if elements else [] + + # elements + @property + def elements(self) -> list[T]: + return self.__elements + + @elements.setter + def elements(self, value: Iterable[T]): + self.__elements = list(value) + + @elements.deleter + def elements(self): + self.__elements.clear() + + # top + @property + def top(self) -> T | None: + """ + Top element of stack. + + :return: Top element + """ + return self.__elements[-1] if self else None + + @top.setter + def top(self, value: T): + self.__elements[-1] = value + + @top.deleter + def top(self): + del self.__elements[-1] + + # public methods + def pop(self) -> T: + """ + Remove and return top element. + + :return: Removed element + """ + return self.__elements.pop() + + def push(self, *items: T) -> Stack[T]: + """Append items to stack""" + self.__elements.extend(items) + return Stack(iterable=self.__elements) + + def remove(self, *items: T) -> Stack[T]: + for i in items: + self.__elements.remove(i) + return Stack(iterable=self.__elements) + + def clear(self) -> Empty[Stack]: + del self.elements + return self + + # copying + def copy(self) -> Stack[T]: + return Stack(iterable=self.__elements.copy()) + + def __copy__(self): + return self.copy() + + # call + def __call__(self, func: Callable[[int, T], T2]) -> Stack[T2]: + elements = self.__elements.copy() + for i, v in enumerate(elements): + elements[i] = func(i, v) + return Stack(iterable=elements) + + # math operations + def __add__(self, other: Stack[T2] | AnyCollection[T2] | T2) -> Stack[T | T2]: + other = convert_to_stack(other) + result = self.copy() + return result.push(*other.elements) + + def __sub__(self, other: Stack[T] | AnyCollection[T] | T) -> Stack[T]: + other = convert_to_stack(other) + result = self.copy() + return result.remove(*other.elements) + + def __mul__( + self: Stack[SupportsMul], other: Stack[NumberLiteral] | AnyCollection[NumberLiteral] | NumberLiteral + ) -> Stack[SupportsMul]: + other = convert_to_list_for_mul_and_div(other, len(self)) + + def mul(i: int, v: SupportsMul) -> SupportsMul: + return v * other[i] + + return self(mul) + + def __truediv__( + self: Stack[SupportsTrueDiv], other: Stack[NumberLiteral] | AnyCollection[NumberLiteral] | NumberLiteral + ) -> Stack[SupportsTrueDiv]: + other = convert_to_list_for_mul_and_div(other, len(self)) + + def div(i: int, v: SupportsTrueDiv) -> SupportsTrueDiv: + return v / other[i] + + return self(div) + + # Booleans + def __len__(self) -> int: + return len(self.__elements) + + def is_empty(self) -> bool: + return len(self) == 0 + + def __bool__(self) -> bool: + return not self.is_empty() + + def __eq__(self, other: Stack[T2]) -> bool: + return self.elements == other.elements + + # Transform to other types + def __repr__(self) -> str: + return f's{self.__elements}' From 9042e99f2afee37f18b51ebc37e71b5024d84149 Mon Sep 17 00:00:00 2001 From: bleudev Date: Sun, 14 Jul 2024 01:31:01 +0300 Subject: [PATCH 5/6] Examples: part 1 --- examples/algebra/fibonacci_sequence.md | 0 examples/algebra/progressions.md | 10 ++++++++++ 2 files changed, 10 insertions(+) create mode 100644 examples/algebra/fibonacci_sequence.md create mode 100644 examples/algebra/progressions.md diff --git a/examples/algebra/fibonacci_sequence.md b/examples/algebra/fibonacci_sequence.md new file mode 100644 index 0000000..e69de29 diff --git a/examples/algebra/progressions.md b/examples/algebra/progressions.md new file mode 100644 index 0000000..055dfc0 --- /dev/null +++ b/examples/algebra/progressions.md @@ -0,0 +1,10 @@ +# Progressions (FunctionSequence, Arithmetic, Geometric) + +## Introduction + +Progressions classes in `ufpy.algebra` package was made for simplification of working with math sequences/progressions. +For example, with arithmetic and geometric progressions. + +## `FunctionSequence` class + + From b57ff2a9f0898fa6d80ce8931060a7a2f56a7d37 Mon Sep 17 00:00:00 2001 From: bleudev Date: Thu, 5 Sep 2024 21:59:01 +0300 Subject: [PATCH 6/6] Compare function sequences --- ufpy/algebra/func_sequence.py | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/ufpy/algebra/func_sequence.py b/ufpy/algebra/func_sequence.py index 2b73a02..2a279de 100644 --- a/ufpy/algebra/func_sequence.py +++ b/ufpy/algebra/func_sequence.py @@ -1,3 +1,5 @@ +from __future__ import annotations + __all__ = ( 'FunctionSequence', ) @@ -5,10 +7,15 @@ from typing import Callable, TypeVar, Generic, Literal, overload, Any from ufpy.utils import mul +from ufpy.cmp import cmp_generator VT = TypeVar('VT', int, float, int | float) KT = TypeVar('KT', int, float, int | float) +VT2 = TypeVar('VT2', int, float, int | float) +KT2 = TypeVar('KT2', int, float, int | float) + +@cmp_generator class FunctionSequence(Generic[VT, KT]): def __resolve_item(self, kwarg: tuple[str, VT]) -> tuple[int, VT] | None: name, value = kwarg @@ -63,14 +70,14 @@ def __init__(self, f: Callable[[int, KT, VT, int], VT], k: KT = None, **kwargs: def __call__(self, n: int) -> VT: ... @overload def __call__(self, start: int, end: int) -> list[VT]: ... - def __call__(self, start_or_end: int, end: int = None): - start = start_or_end + def __call__(self, start: int, end: int | None = None): + start1 = start if not end: - end = start_or_end + end = start r = [] - for i in range(start, end+1): + for i in range(start1, end+1): r.append(self.__process_float(self.f(i))) return r if len(r) > 1 else r[0] @@ -80,6 +87,9 @@ def __getitem__(self, n: int | slice): start, end = x if (x := n.start) else 1, n.stop return self(start, end) return self(n) + + def __cmp__(self, other: FunctionSequence[VT2, KT2]): + return self.k - other.k def __check_for_list(self, l_or_v: list | Any): if isinstance(l_or_v, list): @@ -90,20 +100,16 @@ def __check_for_list(self, l_or_v: list | Any): def s(self, n: int) -> VT: ... @overload def s(self, start: int, end: int) -> VT: ... - def s(self, start_or_n: int, end: int = None) -> VT: - if end: - start = start_or_n - else: - start, end = 1, start_or_n + def s(self, start: int, end: int | None = None) -> VT: + if end is None: + start, end = 1, start return sum(self.__check_for_list(self(start, end))) @overload def p(self, n: int) -> VT: ... @overload def p(self, start: int, end: int) -> VT: ... - def p(self, start_or_n: int, end: int = None) -> VT: - if end: - start = start_or_n - else: - start, end = 1, start_or_n + def p(self, start: int, end: int | None = None) -> VT: + if end is None: + start, end = 1, start return mul(self.__check_for_list(self(start, end)))