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
|
||||
z = y + x
|
||||
solve(x)
|
||||
solve(z)
|
||||
|
||||
x=?
|
||||
solve()
|
||||
# Instanciación via sympify
|
||||
ip = IP4(120.11.255.2,30)
|
||||
ip.Nodes()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"window_geometry": "1020x700+356+1216",
|
||||
"sash_pos_x": 327,
|
||||
"sash_pos_x": 343,
|
||||
"symbolic_mode": true,
|
||||
"show_numeric_approximation": true,
|
||||
"keep_symbolic_fractions": true,
|
||||
|
|
|
@ -138,6 +138,15 @@ class PureAlgebraicEngine:
|
|||
|
||||
def _apply_tokenization(self, line: str) -> str:
|
||||
"""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:
|
||||
return line
|
||||
|
||||
|
@ -204,8 +213,8 @@ class PureAlgebraicEngine:
|
|||
return EvaluationResult(line, error_msg, "error", False, str(e))
|
||||
|
||||
def _is_solve_shortcut(self, line: str) -> bool:
|
||||
"""Detecta atajos de resolución como x=? o solve(x)"""
|
||||
return line.endswith('=?') or line.startswith('solve(')
|
||||
"""Detecta atajos de resolución como solve(x)"""
|
||||
return line.startswith('solve(')
|
||||
|
||||
def _is_comparison(self, line: str) -> bool:
|
||||
"""Detecta comparaciones como ==, <=, >=, !="""
|
||||
|
@ -215,25 +224,25 @@ class PureAlgebraicEngine:
|
|||
def _evaluate_solve_shortcut(self, line: str) -> EvaluationResult:
|
||||
"""Evalúa atajos de resolución"""
|
||||
try:
|
||||
if line.endswith('=?'):
|
||||
# Atajo x=?
|
||||
var_name = line[:-2].strip()
|
||||
var_symbol = sp.Symbol(var_name)
|
||||
solution = self._solve_for_variable(var_symbol)
|
||||
if line.startswith('solve('):
|
||||
# Función solve() - manejar casos especiales primero
|
||||
# Extraer el contenido dentro de solve()
|
||||
import re
|
||||
match = re.match(r'solve\(([^)]+)\)', line)
|
||||
if match:
|
||||
var_content = match.group(1).strip()
|
||||
# Si es una variable simple, usar nuestra lógica mejorada
|
||||
if re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', var_content):
|
||||
# Crear símbolo directamente sin usar context para evitar sustitución
|
||||
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}"
|
||||
return EvaluationResult(line, output, "symbolic", True, is_solve_query=True)
|
||||
|
||||
# Output conciso
|
||||
if solution != var_symbol:
|
||||
output = str(solution)
|
||||
numeric = self._get_numeric_approximation(solution)
|
||||
if numeric and str(solution) != str(numeric):
|
||||
output += f" ≈ {numeric}"
|
||||
else:
|
||||
output = str(var_symbol)
|
||||
|
||||
return EvaluationResult(line, output, "symbolic", True, is_solve_query=True)
|
||||
|
||||
elif line.startswith('solve('):
|
||||
# Función solve() - usar sympify unificado
|
||||
# Para casos más complejos, usar sympify
|
||||
result = self._evaluate_expression(line)
|
||||
result.is_solve_query = True
|
||||
return result
|
||||
|
@ -360,8 +369,23 @@ class PureAlgebraicEngine:
|
|||
return "Sin solución"
|
||||
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 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:
|
||||
# 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
|
||||
# solve() con argumentos específicos (múltiples variables, ecuaciones, etc.)
|
||||
return solve(*args, **kwargs)
|
||||
|
||||
def _solve_for_variable(self, var_symbol):
|
||||
|
@ -370,20 +394,82 @@ class PureAlgebraicEngine:
|
|||
return var_symbol
|
||||
|
||||
try:
|
||||
# Intentar resolver la variable en el contexto del sistema
|
||||
solution = solve(self.equations, var_symbol, dict=True)
|
||||
# 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]
|
||||
|
||||
if solution and var_symbol in solution[0]:
|
||||
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]
|
||||
if relevant_eqs:
|
||||
solution = solve(relevant_eqs, var_symbol)
|
||||
if solution:
|
||||
return solution[0] if isinstance(solution, list) else solution
|
||||
# 2. Buscar ecuaciones que contengan esta variable
|
||||
relevant_eqs = [eq for eq in self.equations if var_symbol in eq.free_symbols]
|
||||
if relevant_eqs:
|
||||
# Estrategia 1: Buscar asignación directa
|
||||
for eq in relevant_eqs:
|
||||
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
|
||||
|
||||
return var_symbol
|
||||
# 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
|
||||
|
||||
except Exception as e:
|
||||
self.logger.debug(f"Error resolviendo {var_symbol}: {e}")
|
||||
|
@ -467,18 +553,17 @@ if __name__ == "__main__":
|
|||
engine = PureAlgebraicEngine()
|
||||
|
||||
test_lines = [
|
||||
"x = 5",
|
||||
"y = x + 3",
|
||||
"solve()",
|
||||
"a = b + 5", # Ecuación con variables
|
||||
"b=?", # ✅ Tokenización: b=? → solve(b)
|
||||
"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 + 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", # 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 ===")
|
||||
|
|
|
@ -22,7 +22,7 @@ from datetime import datetime
|
|||
from pathlib import Path
|
||||
|
||||
# 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):
|
||||
|
|
|
@ -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