""" Clase base híbrida que combina SymPy con funcionalidad especializada """ import sympy from sympy import Basic, Symbol, sympify from typing import Any, Optional, Dict import re from class_base import ClassBase class SympyClassBase(ClassBase, sympy.Basic): """Para clases que necesitan álgebra completa""" def __new__(cls, *args, **kwargs): # La subclase (ej. Class_IP4) es responsable de pasar los argumentos correctos # que sympy.Basic.__new__ espera. obj = sympy.Basic.__new__(cls, *args, **kwargs) return obj def __init__(self, value, original_str=""): ClassBase.__init__(self, value, original_str) # La inicialización de sympy.Basic se maneja principalmente a través de __new__. # Atributos adicionales de sympy como self.args son establecidos por sympy.Basic # basado en los argumentos pasados a __new__. def _sympystr(self, printer): # Las subclases deben implementar esto para una representación SymPy adecuada. # Por defecto, usa el __str__ de ClassBase, que es str(self.value). # Si self.value es un objeto Sympy, str(self.value) ya dará una buena representación. # Si self.value no es un objeto Sympy pero se desea una forma SymPy específica, # esto debería ser sobreescrito. return str(self.value) def _init_specialized(self): """Override en subclases para inicialización especializada""" pass @property def value(self): """Acceso al valor interno""" return self._value @property def original_str(self): """String original de entrada""" return self._original_str # Propiedades requeridas por SymPy @property def args(self): """Argumentos para SymPy - retorna valor como argumento""" return (sympify(self._value),) @property def func(self): """Función constructora para SymPy""" return self.__class__ def _latex(self, printer): """Representación LaTeX""" return self._sympystr(printer) def __str__(self): """Representación string para display""" return str(self._value) def __repr__(self): """Representación para debugging""" return f"{self.__class__.__name__}('{self._original_str}')" def evalf(self, n=15, **options): """Evaluación numérica si es posible""" if isinstance(self._value, (int, float, complex)): return sympy.Float(self._value) return self def _eval_evalf(self, prec): """Evaluación numérica para SymPy""" if isinstance(self._value, (int, float, complex)): return sympy.Float(self._value, prec) return None def __dec__(self): """Conversión a decimal para compatibilidad""" if isinstance(self._value, (int, float, complex)): return self._value raise TypeError(f"Cannot convert {self.__class__.__name__} to decimal") # Métodos requeridos por SymPy para manipulación algebraica def as_coeff_Mul(self, rational=True): """Descomponer como coeficiente * términos""" if isinstance(self._value, (int, float)): return sympify(self._value), sympify(1) return sympify(1), self def as_coeff_Add(self, rational=True): """Descomponer como coeficiente + términos""" if isinstance(self._value, (int, float)): return sympify(self._value), sympify(0) return sympify(0), self def as_base_exp(self): """Descomponer como base^exponente""" return self, sympify(1) def as_numer_denom(self): """Descomponer como numerador/denominador""" return self, sympify(1) # Propiedades de tipo para SymPy @property def is_number(self): """Indica si es un número""" return isinstance(self._value, (int, float, complex)) @property def is_real(self): """Indica si es real""" return isinstance(self._value, (int, float)) and not isinstance(self._value, complex) @property def is_integer(self): """Indica si es entero""" return isinstance(self._value, int) @property def is_rational(self): """Indica si es racional""" return isinstance(self._value, (int, float)) @property def is_irrational(self): """Indica si es irracional""" return False @property def is_positive(self): """Indica si es positivo""" if isinstance(self._value, (int, float)): return self._value > 0 return None @property def is_negative(self): """Indica si es negativo""" if isinstance(self._value, (int, float)): return self._value < 0 return None @property def is_zero(self): """Indica si es cero""" if isinstance(self._value, (int, float)): return self._value == 0 return None @property def is_finite(self): """Indica si es finito""" return isinstance(self._value, (int, float, complex)) @property def is_infinite(self): """Indica si es infinito""" return False @property def is_commutative(self): """Indica si es conmutativo""" return True # Operaciones aritméticas simples que retornan el valor numérico para integración con SymPy def __add__(self, other): """Suma que integra con SymPy""" if isinstance(other, (int, float, complex)): # Retornar valor numérico para que SymPy maneje la operación return sympify(self._value + other) elif hasattr(other, '_value'): return sympify(self._value + other._value) else: # Dejar que SymPy maneje la operación return sympify(self._value) + sympify(other) def __radd__(self, other): """Suma reversa""" return sympify(other) + sympify(self._value) def __mul__(self, other): """Multiplicación que integra con SymPy""" if isinstance(other, (int, float, complex)): return sympify(self._value * other) elif hasattr(other, '_value'): return sympify(self._value * other._value) else: return sympify(self._value) * sympify(other) def __rmul__(self, other): """Multiplicación reversa""" return sympify(other) * sympify(self._value) def __sub__(self, other): """Resta""" if isinstance(other, (int, float, complex)): return sympify(self._value - other) elif hasattr(other, '_value'): return sympify(self._value - other._value) else: return sympify(self._value) - sympify(other) def __rsub__(self, other): """Resta reversa""" return sympify(other) - sympify(self._value) def __truediv__(self, other): """División""" if isinstance(other, (int, float, complex)): if other == 0: raise ZeroDivisionError("Division by zero") return sympify(self._value / other) elif hasattr(other, '_value'): if other._value == 0: raise ZeroDivisionError("Division by zero") return sympify(self._value / other._value) else: return sympify(self._value) / sympify(other) def __rtruediv__(self, other): """División reversa""" if self._value == 0: raise ZeroDivisionError("Division by zero") return sympify(other) / sympify(self._value) def __pow__(self, other): """Potencia""" if isinstance(other, (int, float, complex)): return sympify(self._value ** other) elif hasattr(other, '_value'): return sympify(self._value ** other._value) else: return sympify(self._value) ** sympify(other) def __rpow__(self, other): """Potencia reversa""" return sympify(other) ** sympify(self._value) @staticmethod def Helper(input_str): """Override en subclases para ayuda contextual""" return None