Eliminación de archivos innecesarios (icon.png y MaVCalcv2.lnk). Actualización del historial de cálculos con nuevos formatos de salario y tarifas. Refactorización del motor algebraico para mejorar la salida de resultados y la gestión de ecuaciones, implementando un nuevo formato de salida que incluye aproximaciones numéricas. Mejora en la generación de contenido LaTeX para ecuaciones y asignaciones.
This commit is contained in:
parent
e51e6bf1ae
commit
639081c0d0
|
@ -1,12 +1,10 @@
|
||||||
|
|
||||||
ex = (t * 8) / w
|
salario=horas*tarifa
|
||||||
|
salario=8000
|
||||||
|
tarifa=36
|
||||||
|
|
||||||
|
horas=?
|
||||||
|
|
||||||
|
|
||||||
var1 = 2
|
|
||||||
var2 = 4
|
|
||||||
vatt1 = 4
|
|
||||||
|
|
||||||
vatvatt1()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
@ -361,10 +361,8 @@ class PureAlgebraicEngine:
|
||||||
var_symbol = sp.Symbol(var_content)
|
var_symbol = sp.Symbol(var_content)
|
||||||
solution_result_obj = self._smart_solve(var_symbol)
|
solution_result_obj = self._smart_solve(var_symbol)
|
||||||
|
|
||||||
output = str(solution_result_obj)
|
# Usar nuevo formato de salida
|
||||||
numeric = self._get_numeric_approximation(solution_result_obj)
|
output = self._format_output_with_approximation(solution_result_obj)
|
||||||
if numeric and str(solution_result_obj) != str(numeric):
|
|
||||||
output += f" ≈ {numeric}"
|
|
||||||
|
|
||||||
current_algebraic_type = type(solution_result_obj).__name__
|
current_algebraic_type = type(solution_result_obj).__name__
|
||||||
# Los resultados de solve() generalmente no son plots
|
# Los resultados de solve() generalmente no son plots
|
||||||
|
@ -383,22 +381,16 @@ class PureAlgebraicEngine:
|
||||||
# Para casos más complejos de solve() o si el regex no coincide,
|
# Para casos más complejos de solve() o si el regex no coincide,
|
||||||
# usar _evaluate_expression que ya maneja 'last' y los tipos.
|
# usar _evaluate_expression que ya maneja 'last' y los tipos.
|
||||||
# _evaluate_expression se encargará de self.last_result_object.
|
# _evaluate_expression se encargará de self.last_result_object.
|
||||||
result = self._evaluate_expression(line) # Llama a la versión ya modificada
|
result = self._evaluate_expression(line)
|
||||||
result.is_solve_query = True # Mantener esta bandera
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# Si no es solve(), podría ser otro tipo de atajo (si se añaden más tarde)
|
|
||||||
# Por ahora, si no empieza con solve(, lo tratamos como una expresión normal.
|
|
||||||
return self._evaluate_expression(line)
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_msg = f"Error en atajo de resolución '{line}': {type(e).__name__}: {str(e)}"
|
error_msg = f"Error en solve(): {type(e).__name__}: {str(e)}"
|
||||||
self.logger.error(error_msg)
|
self.logger.error(error_msg)
|
||||||
# No actualizar last_result_object en caso de error
|
|
||||||
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 CON FUNCIONALIDAD DUAL: asignación al contexto + ecuación a sympy"""
|
"""Evalúa una asignación y gestiona 'last'"""
|
||||||
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()
|
||||||
|
@ -439,7 +431,8 @@ class PureAlgebraicEngine:
|
||||||
# Si falla como ecuación, continuar solo con la asignación
|
# 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}")
|
self.logger.warning(f"No se pudo agregar '{line}' como ecuación: {eq_error}")
|
||||||
|
|
||||||
output = f"{var_name} = {result_obj}"
|
# Usar nuevo formato de salida consistente
|
||||||
|
output = self._format_output_with_approximation(Eq(sp.Symbol(var_name), result_obj))
|
||||||
|
|
||||||
# Devolver el resultado de la asignación
|
# Devolver el resultado de la asignación
|
||||||
return EvaluationResult(
|
return EvaluationResult(
|
||||||
|
@ -489,7 +482,9 @@ class PureAlgebraicEngine:
|
||||||
for free_symbol in equation_obj.free_symbols:
|
for free_symbol in equation_obj.free_symbols:
|
||||||
self.variables.add(str(free_symbol))
|
self.variables.add(str(free_symbol))
|
||||||
|
|
||||||
output = str(equation_obj)
|
# Usar nuevo formato de salida
|
||||||
|
output = self._format_equation_output(equation_obj)
|
||||||
|
|
||||||
# No actualizar last_result_object para ecuaciones
|
# No actualizar last_result_object para ecuaciones
|
||||||
return EvaluationResult(
|
return EvaluationResult(
|
||||||
input_line=line,
|
input_line=line,
|
||||||
|
@ -518,20 +513,12 @@ class PureAlgebraicEngine:
|
||||||
if isinstance(result_obj, PlotResult) and not result_obj.original_expression:
|
if isinstance(result_obj, PlotResult) and not result_obj.original_expression:
|
||||||
result_obj.original_expression = line
|
result_obj.original_expression = line
|
||||||
|
|
||||||
output = str(result_obj)
|
# Usar nuevo formato de salida que maneja Eq() automáticamente
|
||||||
|
output = self._format_output_with_approximation(result_obj)
|
||||||
|
|
||||||
result_type_str = "symbolic" # Tipo por defecto
|
result_type_str = "symbolic" # Tipo por defecto
|
||||||
current_algebraic_type = type(result_obj).__name__
|
current_algebraic_type = type(result_obj).__name__
|
||||||
|
|
||||||
# Manejo especial para tipos de sympy que pueden necesitar aproximación numérica
|
|
||||||
if hasattr(result_obj, 'evalf') and not isinstance(result_obj, (sp.Matrix, sp.Basic, sp.Expr)):
|
|
||||||
# Evitar evalf en matrices directamente o en tipos ya específicos como Integer, Float
|
|
||||||
pass
|
|
||||||
|
|
||||||
numeric_approximation = self._get_numeric_approximation(result_obj)
|
|
||||||
if numeric_approximation and output != numeric_approximation:
|
|
||||||
output += f" ≈ {numeric_approximation}"
|
|
||||||
# Considerar si esto cambia el result_type a "numeric_approx"
|
|
||||||
|
|
||||||
# Determinar si es un objeto de plotting (para no asignarlo a 'last')
|
# Determinar si es un objeto de plotting (para no asignarlo a 'last')
|
||||||
is_plot_object = False
|
is_plot_object = False
|
||||||
if isinstance(result_obj, PlotResult):
|
if isinstance(result_obj, PlotResult):
|
||||||
|
@ -825,10 +812,21 @@ class PureAlgebraicEngine:
|
||||||
try:
|
try:
|
||||||
float_val = float(numeric_val)
|
float_val = float(numeric_val)
|
||||||
if abs(float_val) > 1e-10:
|
if abs(float_val) > 1e-10:
|
||||||
return f"{float_val:.6f}".rstrip('0').rstrip('.')
|
# Formatear número eliminando ceros innecesarios
|
||||||
|
if float_val == int(float_val):
|
||||||
|
# Es un entero, mostrarlo como tal
|
||||||
|
return str(int(float_val))
|
||||||
|
else:
|
||||||
|
# Es decimal, formatear con precisión limitada
|
||||||
|
formatted = f"{float_val:.10f}".rstrip('0').rstrip('.')
|
||||||
|
# Si queda muy largo, usar notación más compacta
|
||||||
|
if len(formatted) > 12:
|
||||||
|
formatted = f"{float_val:.6g}"
|
||||||
|
return formatted
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Para otros tipos (complejos, expresiones, etc.)
|
||||||
return str(numeric_val)
|
return str(numeric_val)
|
||||||
return None
|
return None
|
||||||
except:
|
except:
|
||||||
|
@ -872,6 +870,63 @@ class PureAlgebraicEngine:
|
||||||
self._load_tokenization_patterns()
|
self._load_tokenization_patterns()
|
||||||
self.logger.info("Tipos y patrones recargados")
|
self.logger.info("Tipos y patrones recargados")
|
||||||
|
|
||||||
|
def _format_equation_output(self, result_obj) -> str:
|
||||||
|
"""Convierte Eq(var, valor) a formato legible var = valor"""
|
||||||
|
try:
|
||||||
|
if hasattr(result_obj, 'func') and result_obj.func.__name__ == 'Equality':
|
||||||
|
# Es una ecuación Eq(lhs, rhs)
|
||||||
|
lhs = result_obj.lhs
|
||||||
|
rhs = result_obj.rhs
|
||||||
|
return f"{lhs} = {rhs}"
|
||||||
|
else:
|
||||||
|
# No es una ecuación, devolver string normal
|
||||||
|
return str(result_obj)
|
||||||
|
except Exception:
|
||||||
|
return str(result_obj)
|
||||||
|
|
||||||
|
def _format_output_with_approximation(self, result_obj) -> str:
|
||||||
|
"""Formatea salida con aproximación numérica, convirtiendo Eq() a formato legible"""
|
||||||
|
main_output = self._format_equation_output(result_obj)
|
||||||
|
|
||||||
|
# Obtener aproximación numérica
|
||||||
|
numeric_approximation = self._get_numeric_approximation(result_obj)
|
||||||
|
|
||||||
|
if numeric_approximation and main_output != numeric_approximation:
|
||||||
|
# Para ecuaciones, formatear también la aproximación
|
||||||
|
if hasattr(result_obj, 'func') and result_obj.func.__name__ == 'Equality':
|
||||||
|
# Crear aproximación en formato var = valor_aproximado
|
||||||
|
try:
|
||||||
|
lhs = result_obj.lhs
|
||||||
|
rhs_numeric = result_obj.rhs.evalf() if hasattr(result_obj.rhs, 'evalf') else result_obj.rhs
|
||||||
|
|
||||||
|
# Formatear la parte numérica con el mismo sistema
|
||||||
|
rhs_numeric_str = self._get_numeric_approximation(result_obj.rhs)
|
||||||
|
if rhs_numeric_str is None:
|
||||||
|
rhs_numeric_str = str(rhs_numeric)
|
||||||
|
|
||||||
|
numeric_output = f"{lhs} = {rhs_numeric_str}"
|
||||||
|
|
||||||
|
# Comparar si son realmente diferentes
|
||||||
|
# Extraer solo las partes de valor para comparar
|
||||||
|
main_value = str(result_obj.rhs)
|
||||||
|
if main_value != rhs_numeric_str:
|
||||||
|
return f"{main_output} ≈ {numeric_output}"
|
||||||
|
else:
|
||||||
|
# Son iguales, no mostrar aproximación
|
||||||
|
return main_output
|
||||||
|
|
||||||
|
except:
|
||||||
|
return f"{main_output} ≈ {numeric_approximation}"
|
||||||
|
else:
|
||||||
|
# Para expresiones no-ecuación, comparar directamente
|
||||||
|
if str(result_obj) != numeric_approximation:
|
||||||
|
return f"{main_output} ≈ {numeric_approximation}"
|
||||||
|
else:
|
||||||
|
# Son iguales, no mostrar aproximación
|
||||||
|
return main_output
|
||||||
|
|
||||||
|
return main_output
|
||||||
|
|
||||||
|
|
||||||
# ========== FUNCIÓN DE EVALUACIÓN DIRECTA ==========
|
# ========== FUNCIÓN DE EVALUACIÓN DIRECTA ==========
|
||||||
|
|
||||||
|
|
|
@ -417,17 +417,22 @@ class LatexProcessor:
|
||||||
main_content = ""
|
main_content = ""
|
||||||
if result.actual_result_object is not None:
|
if result.actual_result_object is not None:
|
||||||
try:
|
try:
|
||||||
|
# Verificar si es una ecuación Eq()
|
||||||
|
if hasattr(result.actual_result_object, 'func') and result.actual_result_object.func.__name__ == 'Equality':
|
||||||
|
# Es una ecuación, convertir a formato var = valor
|
||||||
|
lhs = result.actual_result_object.lhs
|
||||||
|
rhs = result.actual_result_object.rhs
|
||||||
|
lhs_latex = sympy.latex(lhs)
|
||||||
|
rhs_latex = sympy.latex(rhs)
|
||||||
|
main_content = f"{lhs_latex} = {rhs_latex}"
|
||||||
|
else:
|
||||||
# Intentar generar LaTeX de SymPy para el objeto matemático
|
# Intentar generar LaTeX de SymPy para el objeto matemático
|
||||||
main_content = sympy.latex(result.actual_result_object)
|
main_content = sympy.latex(result.actual_result_object)
|
||||||
|
|
||||||
# Para asignaciones, necesitamos agregar el lado izquierdo
|
# Para asignaciones, el resultado ya viene formateado
|
||||||
if result.is_assignment and result.input_line:
|
if result.is_assignment and not main_content:
|
||||||
# Extraer la variable del lado izquierdo
|
# Extraer del output ya formateado
|
||||||
if '=' in result.input_line:
|
main_content = result.output.split(" ≈")[0] if " ≈" in result.output else result.output
|
||||||
left_side = result.input_line.split('=')[0].strip()
|
|
||||||
# Limpiar posibles símbolos LaTeX del lado izquierdo
|
|
||||||
left_side = left_side.replace('$$', '').strip()
|
|
||||||
main_content = f"{left_side} = {main_content}"
|
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
# Si falla el LaTeX de SymPy, usar el output textual
|
# Si falla el LaTeX de SymPy, usar el output textual
|
||||||
|
@ -446,18 +451,7 @@ class LatexProcessor:
|
||||||
if ";" in approx_value:
|
if ";" in approx_value:
|
||||||
approx_value = approx_value.split(";")[0].strip()
|
approx_value = approx_value.split(";")[0].strip()
|
||||||
|
|
||||||
# Intentar convertir la aproximación a LaTeX si es una ecuación
|
# La aproximación ya viene en formato var = valor, mantenerla así
|
||||||
try:
|
|
||||||
if "Eq(" in approx_value:
|
|
||||||
# Es una ecuación, intentar parserarla para LaTeX
|
|
||||||
approx_obj = eval(approx_value, {'Eq': sympy.Eq, 'sqrt': sympy.sqrt})
|
|
||||||
approx_latex = sympy.latex(approx_obj)
|
|
||||||
latex_parts.append(f"\\approx {approx_latex}")
|
|
||||||
else:
|
|
||||||
# Es un valor numérico simple
|
|
||||||
latex_parts.append(f"\\approx {approx_value}")
|
|
||||||
except:
|
|
||||||
# Si falla, usar la aproximación como texto
|
|
||||||
latex_parts.append(f"\\approx {approx_value}")
|
latex_parts.append(f"\\approx {approx_value}")
|
||||||
|
|
||||||
# PARTE 3: Indicador de tipo (si está en el output)
|
# PARTE 3: Indicador de tipo (si está en el output)
|
||||||
|
|
|
@ -3,6 +3,7 @@ Calculadora MAV CAS Híbrida - Aplicación principal PySide6 (Refactorizada)
|
||||||
VERSIÓN MODULAR: Código organizado en módulos especializados
|
VERSIÓN MODULAR: Código organizado en módulos especializados
|
||||||
"""
|
"""
|
||||||
import sys
|
import sys
|
||||||
|
import os
|
||||||
import logging
|
import logging
|
||||||
from typing import Optional, Dict, Any, List
|
from typing import Optional, Dict, Any, List
|
||||||
|
|
||||||
|
@ -11,7 +12,7 @@ from PySide6.QtWidgets import (
|
||||||
QSplitter, QStatusBar
|
QSplitter, QStatusBar
|
||||||
)
|
)
|
||||||
from PySide6.QtCore import Qt, QTimer
|
from PySide6.QtCore import Qt, QTimer
|
||||||
from PySide6.QtGui import QKeySequence, QShortcut
|
from PySide6.QtGui import QKeySequence, QShortcut, QPixmap, QIcon
|
||||||
|
|
||||||
# Importar componentes del CAS híbrido
|
# Importar componentes del CAS híbrido
|
||||||
from .evaluation import PureAlgebraicEngine
|
from .evaluation import PureAlgebraicEngine
|
||||||
|
@ -41,6 +42,9 @@ class HybridCalculatorPySide6(QMainWindow):
|
||||||
logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(message)s')
|
logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(message)s')
|
||||||
self.logger = logging.getLogger(__name__)
|
self.logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Configurar icono de la aplicación
|
||||||
|
self._setup_application_icon()
|
||||||
|
|
||||||
# Motor y managers
|
# Motor y managers
|
||||||
self.engine = PureAlgebraicEngine()
|
self.engine = PureAlgebraicEngine()
|
||||||
self.interactive_manager = None
|
self.interactive_manager = None
|
||||||
|
@ -305,6 +309,16 @@ class HybridCalculatorPySide6(QMainWindow):
|
||||||
self.settings_manager.save_all()
|
self.settings_manager.save_all()
|
||||||
event.accept()
|
event.accept()
|
||||||
|
|
||||||
|
def _setup_application_icon(self):
|
||||||
|
"""Configura el icono de la aplicación"""
|
||||||
|
# Buscar el icono en el directorio raíz del proyecto
|
||||||
|
icon_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), ".res", "icon.png")
|
||||||
|
if os.path.exists(icon_path):
|
||||||
|
self.setWindowIcon(QIcon(icon_path))
|
||||||
|
self.logger.debug(f"✅ Icono cargado desde: {icon_path}")
|
||||||
|
else:
|
||||||
|
self.logger.warning(f"⚠️ Icono no encontrado en: {icon_path}")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Función principal para ejecutar la aplicación"""
|
"""Función principal para ejecutar la aplicación"""
|
||||||
|
|
Loading…
Reference in New Issue