Actualización del motor algebraico para permitir asignaciones duales, integrando ecuaciones en el contexto de SymPy. Se mejora la gestión de variables y se optimiza la lógica de resolución, asegurando que las soluciones se apliquen correctamente al sistema. Se actualiza el historial de cálculos con nuevas expresiones.

This commit is contained in:
Miguel 2025-06-11 00:01:47 +02:00
parent 242d5095af
commit b7e35d1ae3
2 changed files with 92 additions and 31 deletions

View File

@ -1,9 +1,12 @@
61.6/2.54
x=t**2+5/m
t=?
m=3
x=4
t=?
k=2.54
1080/1440
1920/(3/4)

View File

@ -350,7 +350,7 @@ class PureAlgebraicEngine:
return EvaluationResult(line, error_msg, "error", False, str(e), is_solve_query=True)
def _evaluate_assignment(self, line: str) -> EvaluationResult:
"""Evalúa una asignación"""
"""Evalúa una asignación CON FUNCIONALIDAD DUAL: asignación al contexto + ecuación a sympy"""
try:
var_name, expression_str = line.split('=', 1)
var_name = var_name.strip()
@ -367,10 +367,30 @@ class PureAlgebraicEngine:
eval_context = self._get_complete_context()
result_obj = sympify(expression_str, locals=eval_context)
# Actualizar tabla de símbolos
# 1. ASIGNACIÓN AL CONTEXTO (para evaluación directa)
self.symbol_table[var_name] = result_obj
self.variables.add(var_name)
# 2. AGREGAR COMO ECUACIÓN A SYMPY (para resolución algebraica)
try:
# Crear el símbolo de la variable y la ecuación simbólica
var_symbol = sp.Symbol(var_name)
right_expr = sympify(expression_str, locals=eval_context)
equation_obj = Eq(var_symbol, right_expr)
# Agregar a la lista de ecuaciones para resolución
self.equations.append(equation_obj)
# Registrar símbolos de la ecuación
for free_symbol in equation_obj.free_symbols:
self.variables.add(str(free_symbol))
self.logger.debug(f"Asignación dual agregada: {var_name} = {result_obj} (como ecuación: {equation_obj})")
except Exception as eq_error:
# Si falla como ecuación, continuar solo con la asignación
self.logger.warning(f"No se pudo agregar '{line}' como ecuación: {eq_error}")
output = f"{var_name} = {result_obj}"
# Devolver el resultado de la asignación
@ -514,32 +534,67 @@ class PureAlgebraicEngine:
except Exception as e:
return f"Error resolviendo sistema: {e}"
elif len(args) == 1 and hasattr(args[0], 'is_Symbol') and args[0].is_Symbol:
# solve(variable) - resolver para una variable específica y auto-aplicar
# solve(variable) - resolver para una variable específica
var_symbol = args[0]
solution_value = self._solve_for_variable(var_symbol)
# Si encontramos una solución, auto-aplicar al sistema
# Si encontramos una solución diferente de la variable
if solution_value != var_symbol:
# Resolver iterativamente para obtener el valor más simplificado
final_value = self._resolve_iteratively(solution_value)
# Verificar si la solución contiene otras variables
free_symbols = solution_value.free_symbols
unresolved_vars = free_symbols - {var_symbol}
# Auto-aplicar la solución al sistema
self._auto_apply_solution(var_symbol, final_value)
if unresolved_vars:
# Hay variables sin resolver, verificar si tienen valores numéricos
has_numeric_values = True
for var_sym in unresolved_vars:
var_name = str(var_sym)
if var_name in self.symbol_table:
value = self.symbol_table[var_name]
# Si el valor es simbólico (no numérico), no podemos resolver completamente
if not (hasattr(value, 'is_number') and value.is_number):
has_numeric_values = False
break
else:
# Variable no tiene valor asignado
has_numeric_values = False
break
# Verificar que el resultado no sea problemático
if final_value == var_symbol or str(final_value) in ['True', 'False']:
return var_symbol
if has_numeric_values:
# Todas las variables tienen valores numéricos, resolver iterativamente
final_value = self._resolve_iteratively(solution_value)
return Eq(var_symbol, final_value)
# Auto-aplicar la solución numérica al sistema
if final_value != var_symbol and not str(final_value) in ['True', 'False']:
self._auto_apply_solution(var_symbol, final_value)
return Eq(var_symbol, final_value)
else:
# Hay variables con valores simbólicos, mostrar la relación algebraica
# Ejemplo: t = x - 5 (donde x = t + 5, es simbólico)
result_eq = Eq(var_symbol, solution_value)
return result_eq
else:
# No hay variables sin resolver, intentar resolver completamente
final_value = self._resolve_iteratively(solution_value)
# Auto-aplicar la solución al sistema solo si es un valor específico
if final_value != var_symbol and not str(final_value) in ['True', 'False']:
self._auto_apply_solution(var_symbol, final_value)
return Eq(var_symbol, final_value)
else:
# Si no hay solución en las ecuaciones, verificar en symbol_table
var_name = str(var_symbol)
if var_name in self.symbol_table:
value = self.symbol_table[var_name]
final_value = self._resolve_iteratively(value)
return Eq(var_symbol, final_value)
else:
return var_symbol
# Si el valor en symbol_table es diferente de la variable, devolverlo
if value != var_symbol:
final_value = self._resolve_iteratively(value)
return Eq(var_symbol, final_value)
# Si no hay información, devolver la variable tal como está
return var_symbol
else:
# solve() con argumentos específicos (múltiples variables, ecuaciones, etc.)
return solve(*args, **kwargs)
@ -550,13 +605,7 @@ class PureAlgebraicEngine:
return var_symbol
try:
# 1. Buscar si la variable tiene asignación directa en symbol_table
var_name = str(var_symbol)
if var_name in self.symbol_table:
# Devolver el valor de la asignación directa
return self.symbol_table[var_name]
# 2. Buscar ecuaciones que contengan esta variable
# 1. Buscar ecuaciones que contengan esta variable PRIMERO
relevant_eqs = [eq for eq in self.equations if var_symbol in eq.free_symbols]
if relevant_eqs:
# Estrategia 1: Buscar asignación directa
@ -585,7 +634,8 @@ class PureAlgebraicEngine:
# en términos de otras variables
try:
# Obtener todas las variables del sistema excepto la que queremos resolver
all_vars = list(self.variables)
# Convertir todas las variables a símbolos para sympy
all_vars = [sp.Symbol(v) if isinstance(v, str) else v for v in self.variables]
other_vars = [v for v in all_vars if v != var_symbol]
if other_vars:
@ -624,7 +674,15 @@ class PureAlgebraicEngine:
except:
pass
# 5. Si nada funciona, devolver la variable tal como está
# 5. Si no hay ecuaciones relevantes, buscar en symbol_table como último recurso
var_name = str(var_symbol)
if var_name in self.symbol_table:
value = self.symbol_table[var_name]
# Solo devolver si el valor no es la misma variable (evitar bucles)
if value != var_symbol:
return value
# 6. Si nada funciona, devolver la variable tal como está
return var_symbol
except Exception as e: