mejorado de solve para equaciones con varias variables
This commit is contained in:
parent
c0e638ec79
commit
53dd4eb801
|
@ -1,9 +1,11 @@
|
||||||
|
|
||||||
# x = 5
|
|
||||||
y = x + 3
|
y = x + 3
|
||||||
z = y + x
|
z = y + x
|
||||||
|
solve(x)
|
||||||
|
solve(z)
|
||||||
|
|
||||||
x=?
|
x=?
|
||||||
solve()
|
|
||||||
# Instanciación via sympify
|
# Instanciación via sympify
|
||||||
ip = IP4(120.11.255.2,30)
|
ip = IP4(120.11.255.2,30)
|
||||||
ip.Nodes()
|
ip.Nodes()
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"window_geometry": "1020x700+356+1216",
|
"window_geometry": "1020x700+356+1216",
|
||||||
"sash_pos_x": 327,
|
"sash_pos_x": 343,
|
||||||
"symbolic_mode": true,
|
"symbolic_mode": true,
|
||||||
"show_numeric_approximation": true,
|
"show_numeric_approximation": true,
|
||||||
"keep_symbolic_fractions": true,
|
"keep_symbolic_fractions": true,
|
||||||
|
|
|
@ -138,6 +138,15 @@ class PureAlgebraicEngine:
|
||||||
|
|
||||||
def _apply_tokenization(self, line: str) -> str:
|
def _apply_tokenization(self, line: str) -> str:
|
||||||
"""Aplica tokenización dinámica a la línea de entrada"""
|
"""Aplica tokenización dinámica a la línea de entrada"""
|
||||||
|
|
||||||
|
# 1. TOKENIZACIÓN ESPECIAL: _x=? → solve(_x)
|
||||||
|
variable_solve_pattern = r'([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*\?'
|
||||||
|
if re.match(variable_solve_pattern, line.strip()):
|
||||||
|
var_name = re.match(variable_solve_pattern, line.strip()).group(1)
|
||||||
|
tokenized_line = f"solve({var_name})"
|
||||||
|
self.logger.debug(f"Tokenización solve: '{line}' → '{tokenized_line}'")
|
||||||
|
line = tokenized_line
|
||||||
|
|
||||||
if not self.tokenization_patterns:
|
if not self.tokenization_patterns:
|
||||||
return line
|
return line
|
||||||
|
|
||||||
|
@ -204,8 +213,8 @@ class PureAlgebraicEngine:
|
||||||
return EvaluationResult(line, error_msg, "error", False, str(e))
|
return EvaluationResult(line, error_msg, "error", False, str(e))
|
||||||
|
|
||||||
def _is_solve_shortcut(self, line: str) -> bool:
|
def _is_solve_shortcut(self, line: str) -> bool:
|
||||||
"""Detecta atajos de resolución como x=? o solve(x)"""
|
"""Detecta atajos de resolución como solve(x)"""
|
||||||
return line.endswith('=?') or line.startswith('solve(')
|
return line.startswith('solve(')
|
||||||
|
|
||||||
def _is_comparison(self, line: str) -> bool:
|
def _is_comparison(self, line: str) -> bool:
|
||||||
"""Detecta comparaciones como ==, <=, >=, !="""
|
"""Detecta comparaciones como ==, <=, >=, !="""
|
||||||
|
@ -215,25 +224,25 @@ class PureAlgebraicEngine:
|
||||||
def _evaluate_solve_shortcut(self, line: str) -> EvaluationResult:
|
def _evaluate_solve_shortcut(self, line: str) -> EvaluationResult:
|
||||||
"""Evalúa atajos de resolución"""
|
"""Evalúa atajos de resolución"""
|
||||||
try:
|
try:
|
||||||
if line.endswith('=?'):
|
if line.startswith('solve('):
|
||||||
# Atajo x=?
|
# Función solve() - manejar casos especiales primero
|
||||||
var_name = line[:-2].strip()
|
# Extraer el contenido dentro de solve()
|
||||||
var_symbol = sp.Symbol(var_name)
|
import re
|
||||||
solution = self._solve_for_variable(var_symbol)
|
match = re.match(r'solve\(([^)]+)\)', line)
|
||||||
|
if match:
|
||||||
# Output conciso
|
var_content = match.group(1).strip()
|
||||||
if solution != var_symbol:
|
# Si es una variable simple, usar nuestra lógica mejorada
|
||||||
output = str(solution)
|
if re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', var_content):
|
||||||
numeric = self._get_numeric_approximation(solution)
|
# Crear símbolo directamente sin usar context para evitar sustitución
|
||||||
if numeric and str(solution) != str(numeric):
|
var_symbol = sp.Symbol(var_content)
|
||||||
|
solution_result = self._smart_solve(var_symbol)
|
||||||
|
output = str(solution_result)
|
||||||
|
numeric = self._get_numeric_approximation(solution_result)
|
||||||
|
if numeric and str(solution_result) != str(numeric):
|
||||||
output += f" ≈ {numeric}"
|
output += f" ≈ {numeric}"
|
||||||
else:
|
|
||||||
output = str(var_symbol)
|
|
||||||
|
|
||||||
return EvaluationResult(line, output, "symbolic", True, is_solve_query=True)
|
return EvaluationResult(line, output, "symbolic", True, is_solve_query=True)
|
||||||
|
|
||||||
elif line.startswith('solve('):
|
# Para casos más complejos, usar sympify
|
||||||
# Función solve() - usar sympify unificado
|
|
||||||
result = self._evaluate_expression(line)
|
result = self._evaluate_expression(line)
|
||||||
result.is_solve_query = True
|
result.is_solve_query = True
|
||||||
return result
|
return result
|
||||||
|
@ -360,8 +369,23 @@ class PureAlgebraicEngine:
|
||||||
return "Sin solución"
|
return "Sin solución"
|
||||||
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:
|
||||||
|
# solve(variable) - resolver para una variable específica y devolver ecuación
|
||||||
|
var_symbol = args[0]
|
||||||
|
solution_value = self._solve_for_variable(var_symbol)
|
||||||
|
|
||||||
|
# Si encontramos una solución, devolver como ecuación
|
||||||
|
if solution_value != var_symbol:
|
||||||
|
return Eq(var_symbol, solution_value)
|
||||||
else:
|
else:
|
||||||
# solve() con argumentos específicos
|
# Si no hay solución en las ecuaciones, verificar en symbol_table
|
||||||
|
var_name = str(var_symbol)
|
||||||
|
if var_name in self.symbol_table:
|
||||||
|
return Eq(var_symbol, self.symbol_table[var_name])
|
||||||
|
else:
|
||||||
|
return var_symbol
|
||||||
|
else:
|
||||||
|
# solve() con argumentos específicos (múltiples variables, ecuaciones, etc.)
|
||||||
return solve(*args, **kwargs)
|
return solve(*args, **kwargs)
|
||||||
|
|
||||||
def _solve_for_variable(self, var_symbol):
|
def _solve_for_variable(self, var_symbol):
|
||||||
|
@ -370,19 +394,81 @@ class PureAlgebraicEngine:
|
||||||
return var_symbol
|
return var_symbol
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Intentar resolver la variable en el contexto del sistema
|
# 1. Buscar si la variable tiene asignación directa en symbol_table
|
||||||
solution = solve(self.equations, var_symbol, dict=True)
|
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]
|
||||||
|
|
||||||
if solution and var_symbol in solution[0]:
|
# 2. Buscar ecuaciones que contengan esta variable
|
||||||
return solution[0][var_symbol]
|
|
||||||
else:
|
|
||||||
# Intentar resolver solo las ecuaciones que contienen 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:
|
||||||
solution = solve(relevant_eqs, var_symbol)
|
# Estrategia 1: Buscar asignación directa
|
||||||
if solution:
|
for eq in relevant_eqs:
|
||||||
return solution[0] if isinstance(solution, list) else solution
|
left_expr = eq.lhs
|
||||||
|
right_expr = eq.rhs
|
||||||
|
|
||||||
|
# Caso directo: variable = expresión
|
||||||
|
if left_expr == var_symbol:
|
||||||
|
return right_expr
|
||||||
|
elif right_expr == var_symbol:
|
||||||
|
return left_expr
|
||||||
|
|
||||||
|
# Estrategia 2: Resolver algebraicamente ecuación por ecuación
|
||||||
|
for eq in relevant_eqs:
|
||||||
|
try:
|
||||||
|
single_solution = solve(eq, var_symbol)
|
||||||
|
if single_solution and isinstance(single_solution, list) and single_solution:
|
||||||
|
result = single_solution[0]
|
||||||
|
if result != var_symbol:
|
||||||
|
return result
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Estrategia 3: Resolver el sistema completo para obtener expresiones
|
||||||
|
# en términos de otras variables
|
||||||
|
try:
|
||||||
|
# Obtener todas las variables del sistema excepto la que queremos resolver
|
||||||
|
all_vars = list(self.variables)
|
||||||
|
other_vars = [v for v in all_vars if v != var_symbol]
|
||||||
|
|
||||||
|
if other_vars:
|
||||||
|
# Intentar resolver el sistema para todas las variables
|
||||||
|
# esto nos dará expresiones en términos de variables libres
|
||||||
|
solution = solve(self.equations, all_vars, dict=True)
|
||||||
|
if solution and var_symbol in solution[0]:
|
||||||
|
return solution[0][var_symbol]
|
||||||
|
|
||||||
|
# Alternativa: resolver en términos de una variable específica
|
||||||
|
for other_var in other_vars:
|
||||||
|
try:
|
||||||
|
# Resolver el sistema dejando other_var como variable libre
|
||||||
|
vars_to_solve = [v for v in all_vars if v != other_var]
|
||||||
|
if var_symbol in vars_to_solve:
|
||||||
|
partial_solution = solve(self.equations, vars_to_solve, dict=True)
|
||||||
|
if partial_solution and var_symbol in partial_solution[0]:
|
||||||
|
result = partial_solution[0][var_symbol]
|
||||||
|
# Verificar que la solución contenga la otra variable
|
||||||
|
if other_var in result.free_symbols:
|
||||||
|
return result
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Estrategia 4: Si todo falla, usar la primera ecuación relevante
|
||||||
|
eq = relevant_eqs[0]
|
||||||
|
try:
|
||||||
|
expr_to_solve = eq.lhs - eq.rhs
|
||||||
|
solution = solve(expr_to_solve, var_symbol)
|
||||||
|
if solution:
|
||||||
|
result = solution[0] if isinstance(solution, list) else solution
|
||||||
|
if result != var_symbol:
|
||||||
|
return result
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 5. Si nada funciona, devolver la variable tal como está
|
||||||
return var_symbol
|
return var_symbol
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -467,18 +553,17 @@ if __name__ == "__main__":
|
||||||
engine = PureAlgebraicEngine()
|
engine = PureAlgebraicEngine()
|
||||||
|
|
||||||
test_lines = [
|
test_lines = [
|
||||||
"x = 5",
|
"a = b + 5", # Ecuación con variables
|
||||||
"y = x + 3",
|
"b=?", # ✅ Tokenización: b=? → solve(b)
|
||||||
"solve()",
|
"solve(b)", # ✅ Debería dar: Eq(b, a - 5)
|
||||||
|
"x = 10", # Asignación directa
|
||||||
|
"y = x + 3", # Asignación usando variable
|
||||||
|
"x=?", # ✅ Tokenización: x=? → solve(x)
|
||||||
|
"solve(x)", # ✅ Debería dar: Eq(x, 10)
|
||||||
|
"solve()", # Resolver todo el sistema
|
||||||
"ip = IP4(10.1.1.1)",
|
"ip = IP4(10.1.1.1)",
|
||||||
"ip + 1", # ✅ Aritmética IP con _op_priority
|
"ip + 1", # ✅ Aritmética IP con _op_priority
|
||||||
"ip.to_hex()",
|
|
||||||
"10.1.1.1", # ✅ Tokenización automática
|
|
||||||
"16#FF + 1", # ✅ Aritmética con IntBase y _op_priority
|
"16#FF + 1", # ✅ Aritmética con IntBase y _op_priority
|
||||||
"16#FF", # IntBase directo
|
|
||||||
"16#FF.to_hex()", # Método directo
|
|
||||||
"n = 16#FF", # Asignación IntBase
|
|
||||||
"n.to_hex()" # Método del objeto asignado
|
|
||||||
]
|
]
|
||||||
|
|
||||||
print("=== DEMO MOTOR ALGEBRAICO UNIFICADO ===")
|
print("=== DEMO MOTOR ALGEBRAICO UNIFICADO ===")
|
||||||
|
|
|
@ -22,7 +22,7 @@ from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
# Importar motores de evaluación
|
# Importar motores de evaluación
|
||||||
from main_evaluation import HybridEvaluationEngine
|
from main_evaluation_OLD import HybridEvaluationEngine
|
||||||
|
|
||||||
|
|
||||||
def run_debug(input_file: str, output_file: str = None, verbose: bool = False):
|
def run_debug(input_file: str, output_file: str = None, verbose: bool = False):
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Test final con el ejemplo exacto del usuario
|
||||||
|
"""
|
||||||
|
|
||||||
|
import main_evaluation_puro
|
||||||
|
|
||||||
|
def test_ejemplo_usuario():
|
||||||
|
print("=== EJEMPLO ORIGINAL DEL USUARIO ===")
|
||||||
|
|
||||||
|
engine = main_evaluation_puro.PureAlgebraicEngine()
|
||||||
|
|
||||||
|
casos = [
|
||||||
|
"y = x + 3",
|
||||||
|
"z = y + x",
|
||||||
|
"solve(x)",
|
||||||
|
"solve(z)"
|
||||||
|
]
|
||||||
|
|
||||||
|
for caso in casos:
|
||||||
|
result = engine.evaluate_line(caso)
|
||||||
|
print(f"{caso} → {result.output}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_ejemplo_usuario()
|
Loading…
Reference in New Issue