246 lines
7.7 KiB
Python
246 lines
7.7 KiB
Python
"""
|
|
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
|
|
|
|
|
|
class SympyClassBase(Basic):
|
|
"""
|
|
Clase base híbrida que combina SymPy Basic con funcionalidad de calculadora
|
|
Todas las clases especializadas deben heredar de esta
|
|
"""
|
|
|
|
def __new__(cls, *args, **kwargs):
|
|
"""Crear objeto SymPy válido"""
|
|
obj = Basic.__new__(cls)
|
|
return obj
|
|
|
|
def __init__(self, value, original_str=""):
|
|
"""Inicialización de funcionalidad especializada"""
|
|
self._value = value
|
|
self._original_str = original_str
|
|
self._init_specialized()
|
|
|
|
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 _sympystr(self, printer):
|
|
"""Representación SymPy string"""
|
|
return f"{self.__class__.__name__}({self._original_str})"
|
|
|
|
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 |