Implementación de un contexto limpio por evaluación, garantizando que cada modificación reevalúe todo desde cero. Se eliminan opciones de menú obsoletas relacionadas con la limpieza de variables y ecuaciones. Se añade la funcionalidad para limpiar el historial de entradas y se actualiza la documentación para reflejar estos cambios.

This commit is contained in:
Miguel 2025-06-02 23:23:52 +02:00
parent 449d503213
commit 589bab03b2
6 changed files with 248 additions and 142 deletions

View File

@ -0,0 +1,150 @@
# Solución: Contexto Limpio en Cada Evaluación
## Problema Identificado
La aplicación tenía un comportamiento inesperado donde al evaluar una secuencia como:
```
x
x=1
y+x
x=x+1
x
```
El primer `x` ya mostraba un valor (en este caso `2[Integer]`) cuando debería estar indefinido inicialmente.
## Causa Raíz REAL
El problema **NO era solo el historial**, sino que la aplicación mantenía el contexto de variables entre evaluaciones. Cuando el usuario modificaba cualquier línea, la aplicación reevaluaba **manteniendo las variables previamente definidas**, en lugar de construir el contexto desde cero.
Esto significaba que:
1. Si había `x=1` en alguna línea anterior
2. Y luego el usuario añadía una línea `x` al principio
3. El `x` del principio usaba el valor de la evaluación anterior en lugar de iniciar limpio
## Solución Implementada
### Modificación Principal: Contexto Limpio en Cada Evaluación
**Antes:**
```python
def _evaluate_and_update(self):
"""Evalúa todas las líneas y actualiza la salida"""
try:
input_content = self.input_text.get("1.0", tk.END)
if not input_content.strip():
self._clear_output()
return
lines = input_content.splitlines()
self._evaluate_lines(lines) # ← Mantenía contexto anterior
except Exception as e:
self._show_error(f"Error durante evaluación: {e}")
```
**Después:**
```python
def _evaluate_and_update(self):
"""Evalúa todas las líneas y actualiza la salida"""
try:
input_content = self.input_text.get("1.0", tk.END)
if not input_content.strip():
self._clear_output()
return
# NUEVO: Limpiar completamente el contexto antes de cada evaluación
# Esto garantiza que cada modificación reevalúe todo desde cero
self.engine.clear_all()
lines = input_content.splitlines()
self._evaluate_lines(lines)
except Exception as e:
self._show_error(f"Error durante evaluación: {e}")
```
### Cambios Adicionales
1. **Eliminación de llamadas redundantes**: Los métodos `clear_variables()`, `clear_equations()` y `clear_all()` ya no llaman a `_evaluate_and_update()` porque ahora cada evaluación limpia automáticamente.
2. **Limpieza del historial**: También se limpió el historial, pero esto era secundario al problema real.
3. **Opción manual para limpiar historial**: Se añadió en el menú **Editar → Limpiar historial**.
## Comportamiento Resultante
Ahora **cada vez que se modifica cualquier línea**:
1. **Se limpia completamente el contexto** - `engine.clear_all()`
2. **Se reevalúa TODO desde la línea 1** - construcción paso a paso
3. **El contexto se construye de arriba hacia abajo** - sin memoria de evaluaciones anteriores
4. **Variables solo existen si están definidas en líneas anteriores** - comportamiento predictible
## Prueba de Verificación
El script `test_contexto_limpio.py` confirma el comportamiento:
```
=== PRUEBA DE CONTEXTO LIMPIO POR EVALUACIÓN ===
--- PRIMERA EVALUACIÓN: x solo ---
Resultado: x # ← Símbolo puro, sin valor
Variables después: {} # ← Contexto limpio
--- TERCERA EVALUACIÓN: x, x=1, y+x ---
x (antes de asignar): x # ← Siempre símbolo puro al inicio
x=1: 1 # ← Se asigna
y+x: y + 1 # ← Usa el x=1 asignado arriba
Variables después: {'x': 1} # ← Contexto construido paso a paso
```
## Beneficios de la Solución Real
- ✅ **Contexto predecible**: Cada evaluación inicia completamente limpia
- ✅ **Construcción desde arriba**: Las variables solo existen si se definen arriba
- ✅ **Sin memoria persistente**: No hay variables "fantasma" de evaluaciones anteriores
- ✅ **Comportamiento intuitivo**: Lo que ves es lo que tienes
- ✅ **Reevaluación completa**: Cada cambio reconstruye todo desde cero
## Archivos Modificados
1. `main_calc_app.py` - Método `_evaluate_and_update()` con limpieza automática
2. `main_calc_app.py` - Métodos `clear_*()` simplificados
3. `main_calc_app.py` - **Menús simplificados**: Eliminadas opciones redundantes
4. `hybrid_calc_history.txt` - Limpiado (cambio menor)
5. `test_contexto_limpio.py` - Script de prueba (nuevo)
### Cambios en la Interfaz de Usuario
**Opciones ELIMINADAS del menú (ya no tienen sentido):**
- **Menú Editar**:
- ❌ "Limpiar variables"
- ❌ "Limpiar ecuaciones"
- ❌ "Limpiar todo"
- **Menú CAS completo**:
- ❌ "Mostrar variables"
- ❌ "Mostrar ecuaciones"
- ❌ "Resolver sistema"
**Opciones CONSERVADAS (aún útiles):**
- **Menú Editar**:
- ✅ "Limpiar entrada" - limpia el editor de texto
- ✅ "Limpiar salida" - limpia el panel de resultados
- ✅ "Limpiar historial" - elimina el archivo de historial
- **Menú Archivo**:
- ✅ "Nuevo" - inicia sesión nueva (limpia entrada y salida)
- ✅ "Cargar..." / "Guardar como..." - manejo de archivos
**La solución real no era el historial, sino garantizar que cada evaluación construye el contexto completamente desde cero.**
## Impacto en la Experiencia de Usuario
**✅ Interfaz más limpia**: Sin opciones confusas que no funcionan como se espera
**✅ Comportamiento predecible**: Lo que ves en el editor es exactamente lo que tienes
**✅ Simplicidad**: Menos opciones que manejar, enfoque en la funcionalidad principal
**✅ Consistencia**: El comportamiento es coherente con la filosofía "de arriba hacia abajo"

View File

@ -9,6 +9,7 @@ Este documento describe el estado actual y los objetivos de desarrollo para la *
- Integrar todas las funciones de SymPy directamente
- SymPy maneja toda la evaluación algebraica y ecuaciones
- Cada linea de ingreso corresponde a una sola linea de resultados
- **CONTEXTO LIMPIO POR EVALUACIÓN**: Cada vez que se hace una evaluación se comienza con el contexto completamente limpio y se evalúa desde arriba hacia abajo, línea por línea. Esto garantiza comportamiento predecible sin "memoria" de evaluaciones anteriores.
- La interfaz de usuario se divide en 2 columnas, a la izquierda el area de ingreso de datos y equaciones a ser evaluadas, a la derecha el area de resultados que se colorean segun cada tipo de respuesta.
### 2. **Sintaxis Simplificada con Corchetes (Única)**
@ -454,6 +455,47 @@ else:
- **eval/exec opcional**: Solo disponible con sintaxis especial (ej: `@eval: código_python`)
- **Contexto unificado**: Un solo namespace SymPy para toda la sesión
### **Comportamiento de Contexto Limpio (IMPLEMENTADO)**
**Principio fundamental**: Cada modificación del usuario resulta en una evaluación completa desde cero.
#### Implementación
- **Limpieza automática**: Cada evaluación inicia con `engine.clear_all()`
- **Construcción incremental**: El contexto se construye línea por línea, de arriba hacia abajo
- **Sin persistencia**: No hay variables "fantasma" de evaluaciones anteriores
- **Predictibilidad total**: El primer `x` en cualquier secuencia siempre es un símbolo puro
- **Evaluación inicial del historial**: Al cargar la aplicación, se evalúa el historial una vez para mostrar resultados
#### Ejemplo de Comportamiento
```python
# Primera evaluación: solo "x"
x # → Symbol('x') puro, sin valor
# Segunda evaluación: "x, x=1"
x # → Symbol('x') puro (contexto limpio)
x=1 # → Asigna x=1
# Tercera evaluación: "x, x=1, y+x"
x # → Symbol('x') puro (contexto limpio)
x=1 # → Asigna x=1
y+x # → y + 1 (usa x=1 definido arriba)
```
#### Implicaciones para el Desarrollo
- **No necesidad de gestión manual de contexto**: El sistema lo maneja automáticamente
- **Comportamiento determinista**: Misma entrada → mismo resultado, siempre
- **Simplicidad de debugging**: El estado siempre es predecible
- **Eliminación de opciones de menú obsoletas**: "Limpiar variables/ecuaciones" no tienen sentido
#### Cambios en la Interfaz de Usuario
**Opciones ELIMINADAS (redundantes):**
- Menú CAS completo (variables, ecuaciones, resolver sistema)
- "Limpiar variables", "Limpiar ecuaciones", "Limpiar todo"
**Opciones CONSERVADAS (útiles):**
- "Limpiar entrada/salida" (afecta interfaz visual)
- "Limpiar historial" (afecta archivo persistente)
## Métricas de Éxito
- [X] Sintaxis `Class[args]` funciona consistentemente (`bracket_parser.py`, `hybrid_base_types.py`).

View File

@ -1,26 +1,10 @@
Hex[FF]
ip=IP4[110.1.30.70/24]
ip.NetworkAddress()
500/25
x=12
a=x
Dec[Hex[ff]]
x=2
b=x
Hex[ff]
Hex[ff].toDecimal()
n=IP4[110.1.30.70;255.255.255.0]
n.mask()
m=IP4Mask[23]
IP4Mask[22].to_hex()
n=IP4[110.1.30.70;255.255.255.0]
latex[x**z/rr]
latex(x**z/rr)
a
b

View File

@ -1,5 +1,5 @@
{
"window_geometry": "1020x700+238+107",
"window_geometry": "1020x700+144+161",
"sash_pos_x": 355,
"symbolic_mode": true,
"show_numeric_approximation": true,

View File

@ -339,17 +339,7 @@ CLASES DISPONIBLES:
edit_menu.add_command(label="Limpiar entrada", command=self.clear_input)
edit_menu.add_command(label="Limpiar salida", command=self.clear_output)
edit_menu.add_separator()
edit_menu.add_command(label="Limpiar variables", command=self.clear_variables)
edit_menu.add_command(label="Limpiar ecuaciones", command=self.clear_equations)
edit_menu.add_command(label="Limpiar todo", command=self.clear_all)
# Menú CAS
cas_menu = Menu(menubar, tearoff=0)
menubar.add_cascade(label="CAS", menu=cas_menu)
cas_menu.add_command(label="Mostrar variables", command=self.show_variables)
cas_menu.add_command(label="Mostrar ecuaciones", command=self.show_equations)
cas_menu.add_separator()
cas_menu.add_command(label="Resolver sistema", command=self.solve_system)
edit_menu.add_command(label="Limpiar historial", command=self.clear_history)
# Menú Configuración
config_menu = Menu(menubar, tearoff=0, bg="#3c3c3c", fg="white")
@ -690,6 +680,10 @@ CLASES DISPONIBLES:
self._clear_output()
return
# NUEVO: Limpiar completamente el contexto antes de cada evaluación
# Esto garantiza que cada modificación reevalúe todo desde cero
self.engine.clear_all()
lines = input_content.splitlines()
self._evaluate_lines(lines)
@ -920,7 +914,6 @@ CLASES DISPONIBLES:
"""Inicia nueva sesión"""
self.clear_input()
self.clear_output()
self.engine.clear_all()
def load_file(self):
"""Carga archivo en el editor"""
@ -977,20 +970,14 @@ CLASES DISPONIBLES:
"""Limpia panel de salida"""
self._clear_output()
def clear_variables(self):
"""Limpia variables del motor"""
self.engine.clear_variables()
self._evaluate_and_update()
def clear_equations(self):
"""Limpia ecuaciones del motor"""
self.engine.clear_equations()
self._evaluate_and_update()
def clear_all(self):
"""Limpia variables y ecuaciones"""
self.engine.clear_all()
self._evaluate_and_update()
def clear_history(self):
"""Limpia el archivo de historial"""
try:
if os.path.exists(self.HISTORY_FILE):
os.remove(self.HISTORY_FILE)
messagebox.showinfo("Éxito", "Historial limpiado correctamente.")
except Exception as e:
messagebox.showerror("Error", f"No se pudo limpiar el historial:\n{e}")
def copy_output(self):
"""Copia el contenido de la salida al portapapeles"""
@ -999,95 +986,6 @@ CLASES DISPONIBLES:
self.root.clipboard_clear()
self.root.clipboard_append(content)
def show_variables(self):
"""Muestra ventana con variables definidas"""
variables = self.engine.symbol_table
window = tk.Toplevel(self.root)
window.title("Variables Definidas")
window.geometry("500x400")
window.configure(bg="#2b2b2b")
text_widget = scrolledtext.ScrolledText(
window,
font=("Consolas", 11),
bg="#1e1e1e",
fg="#d4d4d4"
)
text_widget.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
if variables:
content = "Variables definidas:\n\n"
for name, value in variables.items():
content += f"{name} = {value}\n"
else:
content = "No hay variables definidas."
text_widget.insert("1.0", content)
text_widget.config(state="disabled")
def show_equations(self):
"""Muestra ventana con ecuaciones definidas"""
equations = self.engine.equations
window = tk.Toplevel(self.root)
window.title("Ecuaciones Definidas")
window.geometry("500x400")
window.configure(bg="#2b2b2b")
text_widget = scrolledtext.ScrolledText(
window,
font=("Consolas", 11),
bg="#1e1e1e",
fg="#d4d4d4"
)
text_widget.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
if equations:
content = "Ecuaciones en el sistema:\n\n"
for i, eq in enumerate(equations, 1):
content += f"{i}. {eq}\n"
else:
content = "No hay ecuaciones en el sistema."
text_widget.insert("1.0", content)
text_widget.config(state="disabled")
def solve_system(self):
"""Resuelve el sistema de ecuaciones"""
try:
if not self.engine.equations:
messagebox.showinfo("Info", "No hay ecuaciones para resolver.")
return
solutions = self.engine.solve_system()
window = tk.Toplevel(self.root)
window.title("Soluciones del Sistema")
window.geometry("500x400")
window.configure(bg="#2b2b2b")
text_widget = scrolledtext.ScrolledText(
window,
font=("Consolas", 11),
bg="#1e1e1e",
fg="#d4d4d4"
)
text_widget.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
content = "Soluciones del sistema:\n\n"
if isinstance(solutions, dict):
for var, value in solutions.items():
content += f"{var} = {value}\n"
else:
content += str(solutions)
text_widget.insert("1.0", content)
text_widget.config(state="disabled")
except Exception as e:
messagebox.showerror("Error", f"Error resolviendo sistema:\n{e}")
def show_types_syntax(self):
"""Muestra sintaxis de tipos disponibles - NUEVA FUNCIÓN"""
try:
@ -1295,7 +1193,7 @@ programación y análisis numérico.
text_widget.config(state="disabled")
def load_history(self):
"""Carga historial de entrada"""
"""Carga historial de entrada y realiza evaluación inicial"""
try:
if os.path.exists(self.HISTORY_FILE):
with open(self.HISTORY_FILE, "r", encoding="utf-8") as f:
@ -1303,6 +1201,8 @@ programación y análisis numérico.
if content.strip():
self.input_text.insert("1.0", content)
# Hacer evaluación inicial para mostrar resultados del historial
# Esto mantiene el comportamiento de contexto limpio pero muestra resultados
self.root.after_idle(self._evaluate_and_update)
except Exception as e:
print(f"Error cargando historial: {e}")

View File

@ -10,6 +10,7 @@ Sistema de Álgebra Computacional (CAS) que combina SymPy con clases especializa
- **Sistema de tipos dinámico**: Auto-descubrimiento desde `custom_types/`
- **Sintaxis simplificada**: `Tipo[args]` en lugar de `Tipo("args")`
- **Detección automática de ecuaciones**: Sin sintaxis especial
- **Contexto limpio por evaluación**: Cada modificación evalúa todo desde cero, garantizando comportamiento predecible
- **Resultados interactivos**: Elementos clickeables para plots, matrices y listas
- **Autocompletado inteligente**: Basado en tipos registrados dinámicamente
@ -106,6 +107,33 @@ y = x + 2 # y es 7 (evaluado)
z = x + a # z es Symbol('x') + Symbol('a') (simbólico)
```
### Comportamiento de Contexto Limpio
**Principio fundamental**: Cada vez que modifica cualquier línea, la aplicación reevalúa **todo** desde cero.
#### Ventajas
- **Predecible**: El primer `x` en cualquier secuencia siempre es un símbolo puro
- **Sin sorpresas**: No hay variables "fantasma" de evaluaciones anteriores
- **Contextual**: Las variables solo existen si están definidas en líneas anteriores
- **Determinista**: Misma entrada → mismo resultado, siempre
#### Ejemplo
```python
# Al escribir esta secuencia línea por línea:
x # → Symbol('x') puro (sin valor)
x=1 # → Asigna x=1
y+x # → y + 1 (usa x=1 definido arriba)
x=x+1 # → Incrementa x a 2
x # → Muestra 2
```
**Importante**: Cada modificación reconstruye el contexto desde la línea 1 hacia abajo.
#### Carga de Historial
- Al abrir la aplicación, se carga el historial anterior y se evalúa una vez para mostrar resultados
- A partir de ese momento, cada modificación limpia el contexto y reevalúa todo desde cero
- El historial se guarda automáticamente al cerrar la aplicación
## Interfaz de Usuario
### Paneles
@ -119,11 +147,13 @@ z = x + a # z es Symbol('x') + Symbol('a') (simbólico)
### Menús
- **Archivo**: Nuevo, Cargar, Guardar
- **Editar**: Limpiar, operaciones CAS
- **CAS**: Variables, ecuaciones, resolver sistema
- **Tipos**: Información de tipos, recargar sistema
- **Editar**: Limpiar entrada/salida, Limpiar historial
- **Configuración**: Modos simbólicos, Recargar tipos personalizados
- **Tipos**: Información de tipos, Sintaxis de tipos
- **Ayuda**: Guías y referencia
**Nota**: Se han eliminado las opciones relacionadas con limpiar variables/ecuaciones ya que el contexto se limpia automáticamente en cada evaluación.
## Sistema de Tipos Dinámico
### Auto-descubrimiento