Files
secondo-py/pysecondo/algebras/base.py
2026-01-24 11:30:02 +08:00

151 lines
4.4 KiB
Python

"""
Base classes for Algebra system
SECONDO's extensibility is based on algebras - modules that define
operators for specific data types and operations.
"""
from typing import List, Callable, Optional, Any
from abc import ABC, abstractmethod
from pysecondo.core.types import Type
from pysecondo.core.nested_list import NestedList
class Operator:
"""
Base class for all operators in SECONDO
Each operator has:
- name: Operator name (e.g., "+", "filter", "consume")
- type_map: Function that checks if input types are valid
- value_map: Function that executes the operator
The type_map function:
- Takes list of input types
- Returns output type if types are valid
- Raises TypeError if types are invalid
The value_map function:
- Takes list of input values (NestedList)
- Returns result value (NestedList)
"""
def __init__(
self,
name: str,
type_map: Callable[[List[Type]], Type],
value_map: Callable[[List[NestedList]], NestedList],
description: str = ""
):
self.name = name
self.type_map = type_map
self.value_map = value_map
self.description = description
def __repr__(self) -> str:
return f"Operator({self.name})"
class Algebra(ABC):
"""
Base class for algebras
An algebra is a collection of related operators.
Subclasses must implement the init() method to register operators.
Example:
class MyAlgebra(Algebra):
def init(self):
self.register_operator(Operator(
name="myop",
type_map=self.type_map_myop,
value_map=self.value_map_myop
))
"""
def __init__(self):
self.operators: dict[str, Operator] = {}
self.init()
@abstractmethod
def init(self) -> None:
"""
Initialize the algebra and register operators
This method should call self.register_operator() for each operator
defined in this algebra.
"""
pass
def register_operator(self, op: Operator) -> None:
"""Register an operator to this algebra"""
if op.name in self.operators:
raise ValueError(f"Operator {op.name} already registered")
self.operators[op.name] = op
def get_operator(self, name: str) -> Optional[Operator]:
"""Get operator by name"""
return self.operators.get(name)
def list_operators(self) -> List[str]:
"""List all operator names in this algebra"""
return list(self.operators.keys())
class AlgebraManager:
"""
Manager for all loaded algebras
In SECONDO, algebras can be dynamically loaded at runtime.
The AlgebraManager keeps track of all loaded algebras and their operators.
"""
def __init__(self):
self.algebras: dict[str, Algebra] = {}
self.operator_index: dict[str, tuple[Algebra, Operator]] = {}
# Maps operator name -> (algebra, operator)
def register_algebra(self, name: str, algebra: Algebra) -> None:
"""
Register a new algebra
Args:
name: Algebra name (e.g., "StandardAlgebra")
algebra: Algebra instance
"""
if name in self.algebras:
raise ValueError(f"Algebra {name} already registered")
self.algebras[name] = algebra
# Index all operators from this algebra
for op_name, operator in algebra.operators.items():
if op_name in self.operator_index:
existing_alg, _ = self.operator_index[op_name]
raise ValueError(
f"Operator {op_name} already defined in {existing_alg}"
)
self.operator_index[op_name] = (algebra, operator)
def get_operator(self, name: str) -> Optional[Operator]:
"""Get operator by name"""
result = self.operator_index.get(name)
if result:
return result[1]
return None
def get_algebra_for_operator(self, name: str) -> Optional[Algebra]:
"""Get the algebra that provides an operator"""
result = self.operator_index.get(name)
if result:
return result[0]
return None
def list_operators(self) -> List[str]:
"""List all available operators"""
return list(self.operator_index.keys())
def list_algebras(self) -> List[str]:
"""List all registered algebras"""
return list(self.algebras.keys())