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) return EvaluationResult(line, error_msg, "error", False, str(e), is_solve_query=True)
def _evaluate_assignment(self, line: str) -> EvaluationResult: 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: try:
var_name, expression_str = line.split('=', 1) var_name, expression_str = line.split('=', 1)
var_name = var_name.strip() var_name = var_name.strip()
@ -367,10 +367,30 @@ class PureAlgebraicEngine:
eval_context = self._get_complete_context() eval_context = self._get_complete_context()
result_obj = sympify(expression_str, locals=eval_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.symbol_table[var_name] = result_obj
self.variables.add(var_name) 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}" output = f"{var_name} = {result_obj}"
# Devolver el resultado de la asignación # Devolver el resultado de la asignación
@ -514,32 +534,67 @@ class PureAlgebraicEngine:
except Exception as e: except Exception as e:
return f"Error resolviendo sistema: {e}" return f"Error resolviendo sistema: {e}"
elif len(args) == 1 and hasattr(args[0], 'is_Symbol') and args[0].is_Symbol: 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] var_symbol = args[0]
solution_value = self._solve_for_variable(var_symbol) 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: if solution_value != var_symbol:
# Resolver iterativamente para obtener el valor más simplificado # Verificar si la solución contiene otras variables
final_value = self._resolve_iteratively(solution_value) free_symbols = solution_value.free_symbols
unresolved_vars = free_symbols - {var_symbol}
# Auto-aplicar la solución al sistema if unresolved_vars:
self._auto_apply_solution(var_symbol, final_value) # 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 has_numeric_values:
if final_value == var_symbol or str(final_value) in ['True', 'False']: # Todas las variables tienen valores numéricos, resolver iterativamente
return var_symbol 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: else:
# Si no hay solución en las ecuaciones, verificar en symbol_table # Si no hay solución en las ecuaciones, verificar en symbol_table
var_name = str(var_symbol) var_name = str(var_symbol)
if var_name in self.symbol_table: if var_name in self.symbol_table:
value = self.symbol_table[var_name] value = self.symbol_table[var_name]
final_value = self._resolve_iteratively(value) # Si el valor en symbol_table es diferente de la variable, devolverlo
return Eq(var_symbol, final_value) if value != var_symbol:
else: final_value = self._resolve_iteratively(value)
return var_symbol return Eq(var_symbol, final_value)
# Si no hay información, devolver la variable tal como está
return var_symbol
else: else:
# solve() con argumentos específicos (múltiples variables, ecuaciones, etc.) # solve() con argumentos específicos (múltiples variables, ecuaciones, etc.)
return solve(*args, **kwargs) return solve(*args, **kwargs)
@ -550,13 +605,7 @@ class PureAlgebraicEngine:
return var_symbol return var_symbol
try: try:
# 1. Buscar si la variable tiene asignación directa en symbol_table # 1. Buscar ecuaciones que contengan esta variable PRIMERO
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
relevant_eqs = [eq for eq in self.equations if var_symbol in eq.free_symbols] relevant_eqs = [eq for eq in self.equations if var_symbol in eq.free_symbols]
if relevant_eqs: if relevant_eqs:
# Estrategia 1: Buscar asignación directa # Estrategia 1: Buscar asignación directa
@ -585,7 +634,8 @@ class PureAlgebraicEngine:
# en términos de otras variables # en términos de otras variables
try: try:
# Obtener todas las variables del sistema excepto la que queremos resolver # 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] other_vars = [v for v in all_vars if v != var_symbol]
if other_vars: if other_vars:
@ -624,7 +674,15 @@ class PureAlgebraicEngine:
except: except:
pass 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 return var_symbol
except Exception as e: except Exception as e: