Mejorado del Motor algebraico

This commit is contained in:
Miguel 2025-06-06 11:40:34 +02:00
parent 556c63ad31
commit c0e638ec79
21 changed files with 490 additions and 5378 deletions

165
.doc/DESCRIPTION.md Normal file
View File

@ -0,0 +1,165 @@
# MAV Calculator Application Logic Documentation
## Overview
The MAV Calculator is a hybrid Computer Algebra System (CAS) built around a pure algebraic engine that treats all assignments as equations. The application follows a clean pipeline from user input to result display, with sophisticated tokenization and symbolic computation capabilities.
### The application has this main components:
* Algebraic components using sympy engine with sympify, solve, evalf. This includes all the mathematical functions and the functions of sympy.
* Special objects called Types or classes under custom_types folder.
* This classes are automatically discovered at startup.
* every class has functions that some are for the interaction with other clases o with sympy. Other functions can be used directly by the user with parameters and returning the same object or other object.
* special tokenization patterns & substitution using data collected from classes under custom_types folder.
* every class has the Helper function to assist the user when on the line it is detected an error and the line starts with some patter
* every class has a descriptor of functions that can be used for this object to permit the autocomplete popup help the user when they press "."
### Concepts
* Types : Special classes under custom_types folder. That are automatically discovered at startup.
* Cycle: every time the user change the input panel start a cycle that ends when all lines are evaluated and produced an output
* Input panel: tk text area where the user can write or modify text.
* Output panel: read only tk area text correlated 1:1 to every line on the input panel . Every input line must correspond to only 1 line on the output. The output lines can have colors and binds to click for opening the plots or to show matrix or lists.
* Persistence: The app maintain the state of all configurated setup and dimension of the window and all the text on the input panel.
## Application Architecture
### Entry Point and Initialization
The application starts through `calc.py`, which serves as a launcher with comprehensive logging and error handling. It initializes the main GUI application (`HybridCalculatorApp`) which in turn creates a `PureAlgebraicEngine` instance as its computational core.
During initialization, the system performs auto-discovery of custom types from the `custom_types/` directory. Each type module can define tokenization patterns, helper functions, and computational behaviors. This creates a registry of available types and their associated transformation rules.
## Calculation Cycle Flow
### 1. Input Capture and Triggering
The calculation cycle begins when the user types in the input panel. The GUI uses a debounced key release handler that triggers evaluation after a 300ms delay, preventing excessive computation during active typing.
### 2. Line Processing Pipeline
The engine processes all input lines sequentially, maintaining a clean context for each evaluation cycle:
**Context Reset**: Before each evaluation cycle, the engine clears its internal context completely. This ensures that each modification to the input re-evaluates everything from scratch, maintaining consistency.
**Line Classification**: Each line is categorized as:
- Empty or comment (ignored)
- Equation (contains `=` but not as comparison operator)
- Solve shortcut (pattern `variable=?`)
- Expression (everything else)
### 3. Tokenization System
The tokenization system operates through a distributed pattern-matching architecture:
**Pattern Discovery**: During initialization, the system discovers tokenization patterns from all registered type classes. Each type can define multiple patterns with priorities and replacement functions.
**Pattern Application**: Tokenization applies patterns in priority order (higher priority first). Each pattern consists of:
- A regular expression to match
- A replacement function that transforms the match
- Priority level for ordering
- Description for debugging
**Example Transformations**:
- `192.168.1.1` becomes `FourBytes("192.168.1.1")`
- `16#FF` becomes `IntBase("FF", 16)`
- `2#1010` becomes `IntBase("1010", 2)`
**Bracket Parser Integration**: After tokenization, the bracket parser processes any remaining bracket syntax transformations for legacy compatibility. ==Must be removed==
Also every constructor of every Type must be instantiated using eval. For example if a line has "a = IP4(10.1.1.1)" the tokeniser first will translate to "a = IP4(FourBytes("10.1.1.1"))" then eval needs to instantiate the IP4 object so the a will be equal to an object IP4.
### 4. Algebraic Engine Processing
The `PureAlgebraicEngine` implements a pure algebraic approach where all assignments become equations:
**Equation Detection**: The engine distinguishes between:
- Simple assignments (`x = 5`) - creates both a variable assignment and an implicit equation-
- Complex equations (`x**2 + 2*x = 8`) - added directly to the equation system
- Solve shortcuts (`x=?`) - equivalent to `solve(x)` using the current equation system
**Symbol Management**: Variables are automatically and must maintain the type as long as possible. Also if there are aritmetic use with Types we need to cast the result to the Type involved. For example if we have "IP4(10.1.1.1)+1" the result must be IP4 object. The engine maintains a symbol table and equation list that increase every line that persist until the end of the cycle.
**Context Building**: For each evaluation, the engine builds a complete context including:
- Base mathematical functions (sin, cos, solve, etc.)
- Dynamically registered custom types
- Current variable assignments
- Helper functions from type registry
### 5. Expression Evaluation Strategy
The engine uses a hybrid evaluation strategy:
**Symbolic Priority**: Expressions are first attempted through SymPy's `sympify` to maintain symbolic forms. This preserves exact mathematical representations.
**Automatic Substitution**:
* The engine automatically substitutes known numerical values into symbolic expressions when possible, while preserving symbolic forms for unknown variables.
* ==Funtions
**Numerical Approximation**: When beneficial, the engine provides numerical approximations alongside symbolic results. The decision is based on whether the numerical form differs meaningfully from the symbolic representation.
### 6. Result Processing and Display
**Result Classification**: Each evaluation produces an `EvaluationResult` with:
- The computed result (symbolic or numerical)
- Result type classification
- Success/error status
- Optional numerical approximation
- Metadata about the evaluation
**Interactive Elements**: The display system identifies results that benefit from interactivity:
- Large matrices become expandable views
- Plot commands create interactive matplotlib windows
- Long lists become scrollable displays
- Complex objects get detailed inspection windows
**Tag-Based Formatting**: Results are displayed with color-coded tags based on their type and semantic meaning. The GUI applies appropriate formatting for equations, errors, symbolic expressions, and custom type outputs.
## Type System Integration
### Dynamic Type Loading
The type system loads custom classes from the `custom_types/` directory at startup. Each type module can define:
- Class behaviors and arithmetic operations
- Tokenization patterns for automatic recognition
- Helper functions for contextual assistance
- Display and conversion methods
### Inheritance Patterns
Types inherit from either:
- `ClassBase` - for basic custom types
- `SympyClassBase` - for types requiring full SymPy integration
This allows seamless interaction between custom types and the symbolic algebra system.
### Method Discovery
The system automatically discovers and exposes methods from custom types for autocompletion and help systems. This includes both instance methods and static helper functions.
## Error Handling and Recovery
The application implements comprehensive error handling at each stage:
**Tokenization Errors**: Failed tokenization patterns are logged but don't halt processing, allowing partial transformations to proceed.
**Evaluation Errors**: Helper from classes first, then if there is no match SymPy evaluation errors trigger fallback strategies, including symbol creation for undefined variables and alternative parsing approaches.
**Display Errors**: Rendering failures fall back to string representations, ensuring results are always visible even if formatting fails.
## Performance Characteristics
**Lazy Evaluation**: Complex computations are deferred until needed, with caching of intermediate results where appropriate.
**Incremental Processing**: Only changed content triggers re-evaluation, though the current implementation re-evaluates everything for consistency.
**Memory Management**: The system manages symbol tables and equation lists efficiently, with cleanup mechanisms for large sessions.
## Session Persistence
The application maintains session continuity through:
**History Persistence**: Input content is automatically saved and restored between sessions.
**Context Preservation**: Variable assignments and equations persist during the scope of every cycle. The context is added on every line and cleared at the begining of ever cycle. This means that every time the user changes the input panel the context is cleared.
**Settings Management**: UI state and preferences are preserved across application restarts.

View File

@ -1,426 +0,0 @@
# Guía de Desarrollo - Calculadora MAV CAS Híbrido
## Visión General
Este documento describe el estado actual y los objetivos de desarrollo para la **Calculadora MAV**, un **Sistema de Álgebra Computacional (CAS) híbrido**. El proyecto busca combinar la potencia de SymPy como motor algebraico central con capacidades especializadas (IP4, Hex, etc.) integradas de forma nativa.
## Objetivos Principales
### 1. **SymPy como Motor Central**
- ✅ Integrar todas las funciones de SymPy directamente
- ✅ SymPy maneja toda la evaluación algebraica y ecuaciones
- ✅ Cada línea de ingreso corresponde a una sola línea 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 área de ingreso de datos y ecuaciones a ser evaluadas, a la derecha el área de resultados que se colorean según cada tipo de respuesta.
### 2. **Sistema de Tokenización Automática** ⭐ **ACTUALIZADO**
- ❌ ~~Usar **exclusivamente** `Class[args]` en lugar de `Class("args")`~~ **ELIMINADO**
- ✅ **Tokenización automática de patrones específicos**:
- `16#FF``IntBase('FF', 16)` automáticamente
- `192.168.1.1``FourBytes('192.168.1.1')` automáticamente
- ✅ **Sistema distribuido**: Cada clase define sus propios patrones de tokenización
- ✅ **Precedencia automática**: Patrones más específicos tienen mayor prioridad
- ✅ **Parser genérico**: No hardcodea lógica específica de tipos
### 3. **Detección Automática y Manejo de Ecuaciones**
- ✅ Ecuaciones ingresadas directamente (ej. `3+b=5+c`) se detectan y añaden al sistema interno de SymPy.
- ✅ Soporte para comparaciones SymPy (ej. `x > 5`, `a == b`, `x <= 10`) como expresiones evaluables.
- ✅ Sintaxis de atajo para solve: `variable=?` equivale a `solve(variable)`
### 4. **Evaluación Híbrida con Variables SymPy Puras**
- ✅ Resultado simbólico (siempre disponible)
- ✅ Evaluación numérica con `.evalf()` (cuando sea aplicable y las variables estén definidas). Esta evaluación se muestra a la derecha del resultado simbólico.
- ✅ Las asignaciones son siempre simbólicas, solo los resultados se muestra la evaluación numérica.
- ✅ **Todas las variables son símbolos SymPy**: Sin variables Python tradicionales
- 🔄 **Conversión perezosa a SymPy**: Objetos nativos hasta que se necesite álgebra compleja
### 5. **Resultados Interactivos**
- ✅ **Tags clickeables** en el widget Text para resultados complejos que necesitan más de una línea de resultado como Plot, Matrices y Listas.
- ✅ **Detección automática** de tipos que requieren visualización especial:
- ✅ Plots de SymPy → "📊 Ver Plot" (abre ventana matplotlib).
- ✅ Matrices → "📋 Ver Matriz" (muestra matriz formateada).
- ✅ Listas largas → "📋 Ver Lista" (muestra contenido expandido).
- ✅ Objetos complejos → "🔍 Ver Detalles" (representación completa).
- ✅ **Implementación con tags**: Usar `text.tag_bind()` en widget existente
- ✅ **Ventanas popup** para contenido que no cabe en línea.
### 6. **Sistema de Tipos Auto-Descubrible** ⭐ **NUEVO**
- ✅ **Directorio unificado**: Todos los tipos en `custom_types/`
- ✅ **Auto-registro**: Sistema automático de descubrimiento de clases
- ✅ **Función de registro**: Cada módulo tiene `register_classes_in_module()`
- ✅ **Metadatos**: Categorías, opciones y descripciones por tipo
- ✅ **Helpers dinámicos**: Sistema de ayuda contextual distribuido
### 7. **Clases Base Universales** ⭐ **NUEVO**
- ✅ **IntBase**: Representación universal de números en cualquier base
- ✅ **FourBytes**: Representación universal de patrones x.x.x.x
- ✅ **Manejo interno de símbolos**: Sin conversión prematura a SymPy
- ✅ **Aritmética nativa**: Operaciones que mantienen el tipo original
- ✅ **Conversión explícita**: `.to_sympy()` cuando se necesite álgebra compleja
## Arquitectura Actual ⭐ **ACTUALIZADA**
### Estructura de archivos
```
/
├── logs/ # Subcarpeta de logs
├── docs/ # Documentación técnica
├── custom_types/ # ⭐ NUEVO: Sistema de tipos unificado
│ ├── intbase_type.py # IntBase + tokenización + registro
│ ├── fourbytes_type.py # FourBytes + tokenización + registro
│ ├── hex_type.py # Hex (usa IntBase)
│ ├── bin_type.py # Bin (usa IntBase)
│ ├── dec_type.py # Dec
│ ├── chr_type.py # Chr
│ ├── ip4_type.py # IP4 + IP4Mask (usa FourBytes)
│ └── latex_type.py # LaTeX
├── calc.py # Launcher principal
├── main_calc_app.py # Aplicación principal
├── main_evaluation.py # Motor de evaluación híbrido
├── type_registry.py # ⭐ NUEVO: Auto-descubrimiento de tipos
├── tl_popup.py # Motor de ventanas emergentes
├── tl_bracket_parser.py # ⭐ ACTUALIZADO: Tokenizador universal
├── class_base.py # Clases base
├── sympy_Base.py # Base para integración SymPy
└── sympy_helper.py # Helpers para SymPy
```
### Flujo de Procesamiento ⭐ **ACTUALIZADO**
```
Entrada Usuario → [Universal Tokenizer] → [Evaluación Híbrida] → {
1. Resultado Nativo (FourBytes, IntBase, etc.)
2. Conversión a SymPy (solo si es necesario)
3. Evaluación numérica (evalf si aplica)
4. Métodos especializados disponibles
}
```
### Transformación de Sintaxis ⭐ **ACTUALIZADA**
```python
# Tokenización automática (NUEVO):
16#FF + 2#1010 → IntBase("FF", 16) + IntBase("1010", 2)
192.168.1.1 + 5 → FourBytes("192.168.1.1") + 5
IP4(10.1.1.1, 255.255.0.0) → IP4(FourBytes("10.1.1.1"), FourBytes("255.255.0.0"))
# Detección contextual de ecuaciones (EXISTENTE):
3+b=5+c → Se detecta como ecuación standalone (agregar al sistema SymPy)
"x > 5" → Se procesa como desigualdad SymPy
x**2 + 2*x == 0 → Se detecta como igualdad lógica standalone
# Sintaxis de atajo para solve (EXISTENTE):
x=? → solve(x)
```
## Componentes Técnicos ⭐ **ACTUALIZADOS**
### 1. **Sistema de Auto-Descubrimiento de Tipos**
```python
# type_registry.py
class TypeRegistry:
def discover_and_register_all(self):
"""Descubre y registra todas las clases en custom_types/"""
for type_file in self.types_directory.glob("*_type.py"):
self._process_type_file(type_file)
def _register_classes_from_info(self, class_info_list):
"""Registra clases basándose en metadatos"""
for name, class_obj, category, options in class_info_list:
self._register_single_class(name, class_obj, category, options)
```
### 2. **Tokenizador Universal Distribuido**
```python
# tl_bracket_parser.py
class UniversalTokenizer:
def _discover_tokenization_rules(self):
"""Auto-descubre reglas desde todas las clases registradas"""
for class_name, class_obj in registered_classes.items():
if hasattr(class_obj, 'get_tokenization_patterns'):
patterns = class_obj.get_tokenization_patterns()
for pattern_info in patterns:
self.tokenization_rules.append({
'class_name': class_name,
'class_obj': class_obj,
**pattern_info
})
```
### 3. **Clases con Tokenización Propia**
```python
# custom_types/intbase_type.py
class IntBase(ClassBase):
@staticmethod
def get_tokenization_patterns():
return [
{
'pattern': r'(\d+)#([0-9A-Fa-fx]+)',
'replacement': lambda match: f'IntBase("{match.group(2)}", {match.group(1)})',
'priority': 5,
'description': 'Números con base: 16#FF, 2#1010'
}
]
```
### 4. **Conversión Perezosa a SymPy** ⭐ **NUEVO CONCEPTO**
```python
class FourBytes(ClassBase): # No SympyClassBase
def substitute(self, **kwargs):
"""Sustitución interna sin involucrar SymPy"""
# Lógica nativa
def to_sympy(self):
"""Conversión EXPLÍCITA cuando se necesite álgebra"""
# Solo convertir cuando se requiera
```
### 5. **Sistema de Evaluación Integrado**
```python
# main_evaluation.py
class HybridEvaluationEngine:
def __init__(self, auto_discover_types=True):
# Auto-descubrir tipos dinámicamente
self.registered_types_info = discover_and_register_types()
# Configurar parser con tokenización distribuida
self.parser = BracketParser(enable_tokenization=True)
# Configurar contexto con tipos descubiertos
self._setup_base_context()
```
## Capacidades Expandidas ⭐ **ACTUALIZADAS**
### 1. **Funciones SymPy Completas con Objetos Nativos**
```python
# Objetos nativos en álgebra (conversión automática cuando es necesario):
diff(IP4(192.168.x.1) + offset, x) # FourBytes → SymPy automático
integrate(Hex(16#x0) * sin(x), x) # IntBase → SymPy automático
solve([IP4(192.168.x.y) == IP4(192.168.1.10)], [x, y])
# Aritmética nativa (mantiene tipos):
base_ip = 192.168.1.1 # → FourBytes automático
next_ip = base_ip + 5 # → FourBytes('192.168.1.6')
hex_val = 16#FF + 16#10 # → IntBase('10F', 16)
```
### 2. **Conversiones Automáticas Bidireccionales**
```python
# Conversiones fluidas entre tipos:
ip = 192.168.1.1 # → FourBytes automático
ip_hex = ip.ToHex() # → "16#C0.16#A8.16#1.16#1"
mask = 255.255.255.0 # → FourBytes automático
mask_cidr = IP4Mask(mask) # → /24 automático
# Constructores inteligentes:
IP4(192.168.1.1, 16#ffffff00) # FourBytes + IntBase → IP4
Hex(192.168.1.1) # FourBytes → Hex automático
```
### 3. **Sistema de Ayuda Dinámico**
```python
# Helpers auto-descubiertos:
help_functions = get_registered_helper_functions() # De todas las clases
help_context = obtener_ayuda("16#FF") # Helper de IntBase
autocompletado = obj.PopupFunctionList() # Métodos disponibles
```
## Ejemplos de Uso Objetivo ⭐ **ACTUALIZADOS**
```python
# Tokenización automática de patrones:
16#FF + 2#1010 # → IntBase('FF', 16) + IntBase('1010', 2)
192.168.1.1 + 5 # → FourBytes('192.168.1.6')
10.x.1.y # → FourBytes('10.x.1.y') simbólico
# Constructores inteligentes:
IP4(192.168.1.1, 24) # → IP4(FourBytes('192.168.1.1'), 24)
IP4(10.1.1.1, 255.255.0.0) # → Ambos FourBytes automáticamente
Hex(192.168.1.1) # → Conversión FourBytes → Hex
# Conversiones fluidas:
mask = 255.255.255.0 # → FourBytes automático
mask.ToHex() # → "16#FF.16#FF.16#FF.16#0"
mask.ToBase(2) # → "2#11111111.2#11111111.2#11111111.2#0"
# Álgebra con objetos nativos:
network = 10.x.0.0 # → FourBytes simbólico
solve(network + 256 == 10.5.0.0, x) # → x = 5
# Aritmética que preserva tipos:
base = 192.168.0.0 # → FourBytes
for i in range(4):
subnet = base + (i * 256) # → Cada resultado es FourBytes
print(f"Red {i}: {subnet}")
# Evaluación directa con SymPy:
solve(x + 10 - 15, x) # → [5]
diff(16#x0, x) # → 16*log(16) (conversión automática)
# Variables puras SymPy:
x = 5 # → x es Symbol('x') con valor 5
y = x + 2 # → y es expresión simbólica: Symbol('x') + 2
# Funciones avanzadas con resultados interactivos:
plot(sin(2*pi*16#x/256), (x, 0, 255)) # → "📊 Ver Plot"
Matrix([[1, 2, 3], [4, 5, 6]]) # → "📋 Ver Matriz"
```
## Beneficios Logrados ⭐ **ACTUALIZADOS**
### 1. **Usabilidad Mejorada**
- ✅ Sintaxis natural sin artificios (no más `Class[args]`)
- ✅ Tokenización invisible al usuario
- ✅ Acceso completo a capacidades de CAS
- ✅ Evaluación automática simbólica + numérica
### 2. **Potencia Matemática Expandida**
- ✅ Todas las funciones de SymPy disponibles
- ✅ Objetos especializados participan en álgebra cuando es necesario
- ✅ Aritmética nativa que preserva tipos
- ✅ Conversiones automáticas bidireccionales
### 3. **Extensibilidad Real**
- ✅ Sistema verdaderamente modular sin hardcoding
- ✅ Fácil agregar nuevos tipos sin modificar código core
- ✅ Tokenización distribuida y auto-descubrible
- ✅ Compatible con ecosystem SymPy completo
### 4. **Arquitectura Limpia**
- ✅ Responsabilidad única: cada clase maneja su tokenización
- ✅ Parser genérico sin conocimiento específico de tipos
- ✅ Auto-descubrimiento completo del sistema de tipos
- ✅ Manejo unificado de errores
## Sistema de Autocompletado y Ayuda Contextual ⭐ **IMPLEMENTADO**
### 1. **Helpers Dinámicos**
- ✅ **Auto-descubrimiento**: Sistema obtiene helpers de todas las clases registradas
- ✅ **Ayuda contextual**: Cada tipo define su propio `Helper(input_str)`
- ✅ **Integración con SymPy**: Helper especializado para funciones SymPy
- ✅ **Manejo centralizado**: Lista dinámica de helpers disponibles
### 2. **Autocompletado Inteligente**
- ✅ **Popup tras punto**: Evaluación automática del objeto para métodos disponibles
- ✅ **PopupFunctionList()**: Cada clase define sus métodos sugeridos
- ✅ **Filtrado inteligente**: Solo métodos útiles y públicos
- ✅ **No invasivo**: Solo aparece cuando el usuario lo solicita
### 3. **Ejemplos de Integración**
```python
# Sistema distribuido:
HELPERS = get_registered_helper_functions() # Auto-descubierto
# Ayuda contextual:
16#FF. # → Popup con métodos de IntBase
192.168.1.1. # → Popup con métodos de FourBytes
IP4(10.1.1.1). # → Popup con métodos de IP4
# Helpers específicos:
ayuda = obtener_ayuda("16#FF") # → "Números con base: 16#FF, 2#1010..."
```
## Estado de Implementación ⭐ **ACTUALIZADO**
### ✅ **Completamente Implementado**
- **Sistema de auto-descubrimiento**: `type_registry.py`
- **Tokenizador universal**: `tl_bracket_parser.py` refactorizado
- **Clases base universales**: `intbase_type.py`, `fourbytes_type.py`
- **Motor híbrido integrado**: `main_evaluation.py` con auto-descubrimiento
- **Tipos en custom_types/**: Todos los tipos migrados al sistema unificado
- **Helpers dinámicos**: Sistema de ayuda contextual distribuido
- **Resultados interactivos**: Tags clickeables y ventanas popup
- **Contexto limpio**: Evaluación completa desde cero en cada cambio
### 🔄 **En Progreso**
- **Conversión perezosa a SymPy**: Algunos objetos aún se convierten prematuramente
- **Aritmética que preserva tipos**: Necesita refinamiento para todos los casos
- **Optimización de precedencia**: Ajuste fino de prioridades de tokenización
### 📋 **Pendiente**
- **Tipos adicionales**: MAC addresses, timestamps, coordenadas
- **Performance optimization**: Caching y evaluación lazy
- **Documentación de usuario**: Guías y ejemplos actualizados
## Métricas de Éxito ⭐ **ACTUALIZADAS**
- ✅ **Sistema de tokenización automática funcional**:
- ✅ Patrones `16#FF`, `2#1010` → IntBase automático
- ✅ Patrones `192.168.1.1` → FourBytes automático
- ✅ Precedencia automática por especificidad
- ✅ Parser genérico sin hardcoding
- ✅ **Sistema de tipos auto-descubrible**:
- ✅ Todas las clases en `custom_types/`
- ✅ Función `register_classes_in_module()` en cada módulo
- ✅ Auto-registro con metadatos y opciones
- ✅ Helpers dinámicos desde todas las clases
- ✅ **Clases base universales funcionales**:
- ✅ IntBase con aritmética nativa y tokenización propia
- ✅ FourBytes con aritmética nativa y tokenización propia
- ✅ Conversión explícita `.to_sympy()` cuando sea necesario
- ✅ Operadores que mantienen tipos nativos
- ✅ **Motor híbrido integrado**:
- ✅ Auto-descubrimiento de tipos al inicializar
- ✅ Tokenización distribuida automática
- ✅ Contexto limpio por evaluación
- ✅ Evaluación simbólica + numérica
- 🔄 **Conversión perezosa optimizada**:
- ✅ Objetos nativos por defecto
- 🔄 Conversión solo cuando se necesite álgebra compleja
- 🔄 Aritmética preservando tipos en todos los casos
- ✅ **Detección contextual de ecuaciones**:
- ✅ Ecuaciones standalone detectadas y agregadas al sistema
- ✅ Sintaxis de atajo `variable=?``solve(variable)`
- ✅ Protección contra detección en argumentos de función
- ✅ **Resultados interactivos**:
- ✅ Tags clickeables para plots, matrices, listas
- ✅ Ventanas popup con posicionamiento inteligente
- ✅ Detección automática de tipos complejos
- ✅ **Sistema de ayuda avanzado**:
- ✅ Helpers auto-descubiertos desde todas las clases
- ✅ Autocompletado tras punto con métodos disponibles
- ✅ Ayuda contextual no invasiva
- ✅ **Performance aceptable**: Debounce y evaluación optimizada
- ✅ **Manejo robusto de errores**: Logging centralizado y presentación clara
- ✅ **Documentación actualizada**: Guías técnicas y de desarrollo
## Consideraciones Futuras
### **Tipos Adicionales Planeados**
```python
custom_types/
├── mac_type.py # Direcciones MAC: AA:BB:CC:DD:EE:FF
├── time_type.py # Timestamps: HH:MM:SS, ISO format
├── coordinate_type.py # Coordenadas: lat,lon
├── ipv6_type.py # IPv6: 2001:db8::1
└── range_type.py # Rangos: 1..100, a..z
```
### **Optimizaciones de Performance**
- Caching de patrones de tokenización frecuentes
- Evaluación lazy de `evalf()` solo cuando se muestre
- Memoización de conversiones SymPy costosas
### **Extensiones del Parser**
- Soporte para sintaxis de múltiples líneas
- Macros y templates definidos por usuario
- Validación contextual más sofisticada
## Conclusión
La calculadora MAV ha evolucionado hacia un **sistema verdaderamente híbrido y extensible** que combina:
1. **Potencia algebraica completa** de SymPy
2. **Objetos nativos especializados** con aritmética propia
3. **Tokenización automática invisible** al usuario
4. **Arquitectura modular** sin hardcoding
5. **Auto-descubrimiento completo** del sistema de tipos
El resultado es una herramienta que es **más simple para el usuario** (sintaxis natural) pero **más poderosa internamente** (álgebra simbólica + tipos especializados), con una **arquitectura limpia y extensible** que facilita agregar nuevas capacidades sin modificar código existente.

View File

@ -1,712 +0,0 @@
# Calculadora MAV - CAS Híbrido
## Descripción General
La Calculadora MAV es un **Sistema de Álgebra Computacional (CAS) Híbrido** que combina la potencia de SymPy con clases especializadas para networking, programación y análisis numérico, usando un **sistema de tokenización automática** que convierte patrones específicos en objetos tipados.
### Características Principales
- **Motor SymPy completo**: Todas las funciones de cálculo simbólico
- **Tokenización automática invisible**: `16#FF` y `192.168.1.1` se convierten automáticamente en objetos tipados
- **Sistema de tipos dinámico**: Auto-descubrimiento desde `custom_types/`
- **Detección automática de ecuaciones**: Sin necesidad de comillas especiales
- **Resultados interactivos**: Plots, matrices y listas clickeables
- **Clases especializadas**: IntBase, FourBytes, IP4, Hex, Bin, Chr y más
- **Variables SymPy puras**: Todas las variables son símbolos automáticamente
- **Contexto limpio por evaluación**: Comportamiento predecible sin "memoria" de evaluaciones anteriores
## Instalación
### Método 1: Instalación Automática
```bash
python calc.py --setup
```
### Método 2: Instalación Manual
```bash
# Instalar dependencias
pip install sympy matplotlib numpy
# En Linux: instalar tkinter
sudo apt-get install python3-tk
# Ejecutar tests (opcional)
python test_suite.py
# Iniciar aplicación
python calc.py
```
### Dependencias Requeridas
- **Python 3.8+**
- **SymPy ≥ 1.12** (motor algebraico)
- **Matplotlib ≥ 3.7.0** (plotting)
- **NumPy ≥ 1.24.0** (cálculos numéricos)
- **Tkinter** (interfaz gráfica, incluido con Python)
### Dependencias Opcionales
- **Markdown ≥ 3.4.0** (ayuda mejorada)
- **pytest ≥ 7.0.0** (testing)
## Guía de Uso
### Tokenización Automática ⭐ **NUEVO**
La aplicación reconoce patrones específicos y los convierte automáticamente en objetos tipados:
#### Números con Base (IntBase)
```python
# Tokenización automática de números con base
16#FF # → IntBase('FF', 16) = 255
2#1010 # → IntBase('1010', 2) = 10
8#777 # → IntBase('777', 8) = 511
16#x0 # → IntBase('x0', 16) = simbólico
# Aritmética que mantiene la base original
16#FF + 16#10 # → IntBase('10F', 16) = 271
2#1010 * 3 # → IntBase('11110', 2) = 30
```
#### Patrones x.x.x.x (FourBytes)
```python
# Tokenización automática de patrones dotted
192.168.1.1 # → FourBytes('192.168.1.1')
255.255.255.0 # → FourBytes('255.255.255.0')
10.x.1.y # → FourBytes('10.x.1.y') = simbólico
# Aritmética de direcciones (32-bit)
192.168.1.1 + 5 # → FourBytes('192.168.1.6')
10.0.0.0 + 256 # → FourBytes('10.0.1.0')
```
### Clases Especializadas
#### Uso Natural con Constructores
```python
# Los constructores reciben objetos ya tokenizados
IP4(192.168.1.100, 24) # FourBytes automático
IP4(10.0.0.1, 255.255.0.0) # Ambos son FourBytes
Hex(16#FF) # IntBase automático
Dec(255) # Entero normal
Chr(65) # Carácter ASCII
```
#### Métodos de Clases Especializadas
```python
# Métodos de IP4
ip = IP4(192.168.1.100, 24)
ip.NetworkAddress() # → IP4(192.168.1.0, 24)
ip.BroadcastAddress() # → IP4(192.168.1.255, 24)
ip.Nodes() # → 254 (hosts disponibles)
# Conversiones de IntBase
val = 16#FF # → IntBase('FF', 16)
val.to_decimal() # → 255
val.to_base(2) # → IntBase('11111111', 2)
# Conversiones de FourBytes
addr = 192.168.1.1 # → FourBytes('192.168.1.1')
addr.ToHex() # → "16#C0.16#A8.16#1.16#1"
addr.ToBinary() # → "2#11000000.2#10101000.2#1.2#1"
```
### Conversiones Automáticas Bidireccionales
#### Flujo Natural Entre Tipos
```python
# IP con máscara hexadecimal
IP4(192.168.1.1, 16#ffffff00) # IntBase → IP4Mask automático
# Conversión desde IP a Hex
ip_bytes = 192.168.1.1 # → FourBytes
hex_ip = Hex(ip_bytes) # → Hex con valor 32-bit
# Análisis de máscara en múltiples bases
mask = 255.255.255.0 # → FourBytes
mask_hex = Hex(mask) # → Hex basado en 32-bit
mask_bin = Bin(mask) # → Bin por elementos
mask_cidr = IP4Mask(mask) # → /24
# Operaciones mixtas
base_ip = 192.168.0.0 # → FourBytes
offset = 16#100 # → IntBase('100', 16) = 256
next_ip = base_ip + offset # → FourBytes('192.168.1.0')
```
### Ecuaciones y Álgebra
#### Detección Automática de Ecuaciones
```python
# Ecuaciones simples (detectadas automáticamente)
x + 2 = 5
3*a + b = 10
y**2 = 16
# Desigualdades
x > 5
a <= 10
b != 0
# Ecuaciones complejas
sin(x) = 1/2
log(y) + 3 = 5
# Ecuaciones con objetos tipados
10.x.1.1 + 256 = 10.5.1.1 # Resuelve: x = 4
```
#### Resolución de Ecuaciones
```python
# Resolver ecuación específica
solve(x**2 + 2*x - 8, x) # [-4, 2]
# Atajo para resolver variable
x=? # Equivale a solve(x)
# Resolver sistema de ecuaciones
x + y = 10
x - y = 2
solve([x + y - 10, x - y - 2], [x, y]) # {x: 6, y: 4}
# Sistemas con objetos tipados
network = 10.a.b.0
solve(network + 256 == 10.5.1.0, [a, b]) # Encuentra valores de a, b
```
### Variables y Símbolos
#### Variables SymPy Automáticas
```python
# Todas las variables son símbolos SymPy automáticamente
x + 2*y # Expresión simbólica
z = 5 # z es Symbol('z') con valor 5
w = z**2 + 3 # w es expresión: Symbol('z')**2 + 3
# Con objetos tipados
ip_base = 10.x.1.1 # FourBytes simbólico
ip_final = ip_base + 10 # Aritmética simbólica
substitute(ip_final, x=5) # → FourBytes('10.5.1.11')
```
#### Contexto Limpio por Evaluación
```python
# Cada modificación reevalúa todo desde cero:
x # → Symbol('x') puro (sin valor)
x = 1 # → Asigna x = 1
y = x + 2 # → y = 3 (usa x=1 definido arriba)
# Si modifica cualquier línea, se reevalúa todo nuevamente
# Esto garantiza comportamiento predecible y determinista
```
### Funciones Matemáticas
#### Cálculo Diferencial e Integral
```python
# Derivadas con objetos tipados
diff(16#x0, x) # → 16*log(16)
diff(sin(192.168.x.1), x) # → cos(3232235777 + x)
# Integrales
integrate(x**2, x) # → x**3/3
integrate(sin(x), (x, 0, pi)) # → 2
# Límites
limit(sin(x)/x, x, 0) # → 1
# Series de Taylor
series(exp(x), x, 0, 5) # → 1 + x + x**2/2 + x**3/6 + x**4/24 + O(x**5)
```
#### Funciones Trigonométricas
```python
# Funciones básicas
sin(pi/2) # → 1
cos(0) # → 1
tan(pi/4) # → 1
# Con valores hexadecimales
sin(16#FF / 255 * pi) # → Seno de π (aproximadamente)
```
#### Álgebra y Simplificación
```python
# Simplificación
simplify((x**2 - 1)/(x - 1)) # → x + 1
expand((x + 1)**3) # → x**3 + 3*x**2 + 3*x + 1
factor(x**2 - 1) # → (x - 1)*(x + 1)
# Con objetos especializados
simplify(16#FF + 2#1010 - 265) # → 0 (IntBase convertido automáticamente)
```
### Álgebra Lineal
#### Matrices
```python
# Crear matrices
M = Matrix([[1, 2], [3, 4]])
N = Matrix([[5, 6], [7, 8]])
# Operaciones básicas
M + N # Suma de matrices
M * N # Multiplicación
M**2 # Potencia
# Propiedades (clickeables en interfaz)
det(M) # Determinante: -2
inv(M) # Matriz inversa
M.transpose() # Transpuesta
```
### Plotting Interactivo
#### Plots 2D
```python
# Plot básico
plot(sin(x), (x, -2*pi, 2*pi))
# Múltiples funciones
plot(sin(x), cos(x), (x, 0, 2*pi))
# Plot con objetos tipados
plot(16#x/256, (x, 0, 255)) # Hex values
plot(sin(192.168.x.1 / 1000), (x, 0, 255)) # IP arithmetic
```
#### Plots 3D
```python
# Superficie 3D
plot3d(x**2 + y**2, (x, -5, 5), (y, -5, 5))
# Con funciones trigonométricas
plot3d(sin(x)*cos(y), (x, 0, 2*pi), (y, 0, 2*pi))
# Con objetos tipados
plot3d(16#x + 16#y, (x, 0, 255), (y, 0, 255))
```
### Resultados Interactivos
#### Elementos Clickeables
- **📊 Ver Plot**: Abre ventana matplotlib para plots
- **📋 Ver Matriz**: Muestra matriz formateada con operaciones
- **📋 Ver Lista**: Expande listas largas
- **🔍 Ver Detalles**: Información completa de objetos
#### Ejemplo de Uso
```python
# Estos resultados serán clickeables en la interfaz
Matrix([[1, 2, 3], [4, 5, 6]]) # → 📋 Ver Matriz 2×3
plot(x**2, (x, -10, 10)) # → 📊 Ver Plot
solve(x**3 - 6*x**2 + 11*x - 6, x) # → 📋 Ver Soluciones
```
## Casos de Uso Avanzados
### Análisis de Redes con Álgebra
```python
# Definir red con variables
network = 192.168.x.0 # → FourBytes simbólico
subnet_size = 2#100000000 # → IntBase('100000000', 2) = 256
# Encontrar valores específicos
solve(network + subnet_size == 192.168.5.0, x) # → x = 4
# Análisis de rangos
base_ip = 10.a.b.0
constraints = [
base_ip[1] >= 0, # a >= 0
base_ip[1] <= 255, # a <= 255
base_ip[2] >= 0, # b >= 0
base_ip[2] <= 255 # b <= 255
]
valid_ranges = solve(constraints, [a, b])
```
### Programación y Conversiones Avanzadas
```python
# Análisis de valores hex con variables
hex_pattern = 16#x0 # → IntBase simbólico
solve(hex_pattern + 16#10 == 256, x) # → x = 15 (0xF)
# Conversiones automáticas en cadena
ip = 192.168.1.1 # → FourBytes
ip_hex = ip.ToHex() # → "16#C0.16#A8.16#1.16#1"
ip_bin = ip.ToBinary() # → "2#11000000.2#10101000.2#1.2#1"
# Operaciones bit a bit con conversión automática
mask1 = 255.255.255.0 # → FourBytes
mask2 = 255.255.0.0 # → FourBytes
combined = mask1 & mask2 # → Operación bit a bit
```
### Análisis Matemático con Tipos Especializados
```python
# Función compleja con valores hex
f = sin(16#x * pi / 256) # IntBase convertido automáticamente
# Análisis completo
df_dx = diff(f, x) # Derivada
critical_points = solve(df_dx, x) # Puntos críticos
integral = integrate(f, (x, 0, 255)) # Integral en rango hex
# Visualización
plot(f, df_dx, (x, 0, 255)) # Plot función y derivada
```
### Sistemas de Ecuaciones con Redes
```python
# Sistema con direcciones IP
ip1 = 192.168.x.y
ip2 = 10.a.b.c
# Condiciones de red
ip1 + 256 = 192.168.5.10
ip2.NetworkAddress() = 10.1.0.0
# Resolver para encontrar valores válidos
solve([
ip1 + 256 - 192.168.5.10,
ip2[1] - 1, # a = 1
ip2[2] - 0 # b = 0
], [x, y, a, b, c])
```
## Sistema de Tipos Dinámico ⭐ **NUEVO**
### Auto-descubrimiento de Tipos
```python
# El sistema automáticamente descubre tipos desde custom_types/
custom_types/
├── intbase_type.py # IntBase + tokenización + registro
├── fourbytes_type.py # FourBytes + tokenización + registro
├── hex_type.py # Hex (usa IntBase)
├── bin_type.py # Bin (usa IntBase)
├── ip4_type.py # IP4 + IP4Mask (usa FourBytes)
├── chr_type.py # Chr
└── latex_type.py # LaTeX
```
### Tokenización Distribuida
Cada clase define sus propios patrones de reconocimiento:
```python
# En intbase_type.py
@staticmethod
def get_tokenization_patterns():
return [
{
'pattern': r'(\d+)#([0-9A-Fa-fx]+)',
'replacement': lambda match: f'IntBase("{match.group(2)}", {match.group(1)})',
'priority': 5,
'description': 'Números con base: 16#FF, 2#1010'
}
]
```
### Precedencia Automática
- **IntBase**: Prioridad 5 (alta) - patrón muy específico
- **FourBytes**: Prioridad 10 (media) - patrón más general
- Sistema ordena automáticamente por especificidad
### Información de Tipos
Use **Menú Tipos → Información de tipos** para ver tipos descubiertos automáticamente.
## Interfaz de Usuario
### Paneles
- **Panel Izquierdo**: Entrada de código
- **Panel Derecho**: Resultados con colores y elementos interactivos
### Sistema de Ayuda Dinámico
- **Helpers auto-descubiertos**: Cada tipo define su ayuda contextual
- **Autocompletado inteligente**: Escribir `.` muestra métodos del objeto
- **PopupFunctionList**: Lista de métodos disponibles por tipo
### Menús Actualizados
- **Archivo**: Nuevo, Cargar, Guardar
- **Editar**: Limpiar entrada/salida, Limpiar historial
- **Configuración**: Modo simbólico, Recargar tipos personalizados
- **Tipos**: Información de tipos, Sintaxis de tipos ⭐ **NUEVO**
- **Ayuda**: Guías, sintaxis, funciones SymPy
### Autocompletado Avanzado
```python
# Ejemplos de autocompletado tras punto:
192.168.1.1. # → Métodos de FourBytes
16#FF. # → Métodos de IntBase
IP4(10.1.1.1). # → Métodos de IP4
Matrix([[1,2]]). # → Métodos de SymPy Matrix
```
## Configuración y Personalización
### Archivos de Configuración
- **`hybrid_calc_settings.json`**: Configuración de ventana y UI
- **`hybrid_calc_history.txt`**: Historial de sesión anterior
- **`logs/`**: Archivos de log para debugging
### Modo Simbólico Configurable
- **Resultado simbólico**: Siempre disponible
- **Aproximación numérica**: Configurable (mostrar/ocultar)
- **Fracciones simbólicas**: Mantener como fracción vs decimal
- **Auto-simplificación**: Activar/desactivar
## Resolución de Problemas
### Errores Comunes
#### Dependencias Faltantes
```bash
# Error: ModuleNotFoundError: No module named 'sympy'
pip install sympy matplotlib numpy
# Linux: tkinter no disponible
sudo apt-get install python3-tk
```
#### Problemas de Tokenización
```python
# Problema: Pattern no reconocido
192.168.1 # No es x.x.x.x completo, no se tokeniza
# Solución: Usar patrón completo
192.168.1.1 # → FourBytes automático
# Verificar tipos cargados
# Menú Tipos → Información de tipos
```
#### Problemas de Variables
```python
# Las variables son símbolos automáticamente
x = 5 # → x es Symbol('x') con valor 5, no variable Python
y = x + 2 # → y es Symbol('x') + 2, evaluado como 7
# Con objetos tipados
ip = 10.x.1.1 # → FourBytes simbólico
ip.substitute(x=5) # → FourBytes('10.5.1.1')
```
### Performance
#### Optimizaciones Implementadas
- **Contexto limpio**: Cada evaluación es independiente y predecible
- **Tokenización cacheada**: Patrones frecuentes se cachean
- **Evaluación lazy**: `evalf()` solo cuando se muestra resultado
- **Auto-descubrimiento optimizado**: Una sola carga al inicio
#### Límites Conocidos
- Sistemas de ecuaciones muy grandes pueden ser lentos
- Plots 3D complejos requieren tiempo de renderizado
- Matrices muy grandes pueden consumir memoria
- Objetos simbólicos complejos necesitan más tiempo de evaluación
### Debugging del Sistema de Tipos
#### Verificación de Auto-descubrimiento
```python
# En código o logs
print(f"Tipos descubiertos: {len(registered_classes)}")
print(f"Reglas de tokenización: {len(tokenization_rules)}")
# En interfaz
# Menú Tipos → Información de tipos
```
#### Recarga de Tipos en Desarrollo
```python
# Para desarrollo en tiempo real
# Menú Configuración → Recargar Tipos Personalizados
# O reiniciar aplicación para cambios en custom_types/
```
## Desarrollo y Extensión
### Estructura Actual del Proyecto
```
calculadora-mav-cas/
├── calc.py # Launcher principal
├── main_calc_app.py # Aplicación principal
├── main_evaluation.py # Motor CAS híbrido
├── type_registry.py # Auto-descubrimiento de tipos ⭐
├── tl_bracket_parser.py # Tokenizador universal ⭐
├── tl_popup.py # Resultados interactivos
├── class_base.py # Clases base
├── sympy_Base.py # Base para integración SymPy
├── sympy_helper.py # Helpers para SymPy
├── custom_types/ # ⭐ Sistema de tipos unificado
│ ├── intbase_type.py # IntBase + tokenización
│ ├── fourbytes_type.py # FourBytes + tokenización
│ ├── hex_type.py # Hex (usa IntBase)
│ ├── bin_type.py # Bin (usa IntBase)
│ ├── ip4_type.py # IP4 + IP4Mask (usa FourBytes)
│ ├── chr_type.py # Chr
│ └── latex_type.py # LaTeX
├── logs/ # Logs de debugging
└── docs/ # Documentación técnica
```
### Agregar Nuevos Tipos ⭐ **SIMPLIFICADO**
#### 1. Crear Archivo en `custom_types/`
```python
# custom_types/ejemplo_type.py
from class_base import ClassBase
import re
class Class_Ejemplo(ClassBase):
def __init__(self, value_input):
# Procesar entrada
super().__init__(processed_value, original_str)
@staticmethod
def get_tokenization_patterns():
"""Define cómo reconocer y tokenizar este tipo"""
return [
{
'pattern': r'@([a-zA-Z0-9_]+)',
'replacement': lambda match: f'Ejemplo("{match.group(1)}")',
'priority': 8,
'description': 'Patrones @ejemplo'
}
]
@staticmethod
def Helper(input_str):
if re.match(r"^\s*@\w+", input_str):
return "Ej: @usuario, @sistema. Funciones: .validate(), .expand()"
return None
@staticmethod
def PopupFunctionList():
return [
("validate", "Valida formato del ejemplo"),
("expand", "Expande el valor del ejemplo")
]
def register_classes_in_module():
return [
("Ejemplo", Class_Ejemplo, "ClassBase", {
"add_lowercase": True,
"supports_brackets": False,
"has_tokenization": True,
"description": "Ejemplos con @patron"
})
]
```
#### 2. Usar Automáticamente
```python
# Después de crear el archivo, automáticamente funciona:
@usuario # → Ejemplo('usuario')
@sistema.validate() # → Autocompletado disponible
```
### Tokenización Personalizada Avanzada
#### Múltiples Patrones por Tipo
```python
@staticmethod
def get_tokenization_patterns():
return [
{
'pattern': r'([0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2})',
'replacement': lambda match: f'MAC("{match.group(1)}", format="colon")',
'priority': 6,
'description': 'MAC con dos puntos: AA:BB:CC:DD:EE:FF'
},
{
'pattern': r'([0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2})',
'replacement': lambda match: f'MAC("{match.group(1)}", format="dash")',
'priority': 6,
'description': 'MAC con guiones: AA-BB-CC-DD-EE-FF'
}
]
```
### Herencia de Tipos Base
#### Usar IntBase para Nuevas Bases
```python
# custom_types/octal_type.py
from sympy_Base import SympyClassBase
class Class_Octal(SympyClassBase):
def __init__(self, value_input):
# Obtener IntBase dinámicamente del registro
IntBase = get_intbase_class()
if isinstance(value_input, IntBase):
if value_input.base == 8:
self.int_base = value_input
else:
# Convertir a octal
octal_value = IntBase._convert_to_base_string(value_input._numeric_value, 8)
self.int_base = IntBase(octal_value, 8)
super().__init__(self.int_base.value, str(self.int_base))
# Automáticamente disponible: 8#777 → IntBase, Octal(8#777) → Class_Octal
```
## Changelog
### Versión 2.1 (Sistema de Tipos Dinámico) ⭐ **ACTUAL**
- ✅ **Tokenización automática**: Patrones `16#FF` y `192.168.1.1` convertidos automáticamente
- ✅ **Sistema de tipos dinámico**: Auto-descubrimiento desde `custom_types/`
- ✅ **Clases base universales**: IntBase y FourBytes como tipos fundamentales
- ✅ **Tokenización distribuida**: Cada clase define sus propios patrones
- ✅ **Parser genérico**: Sin hardcoding de tipos específicos
- ✅ **Conversión perezosa a SymPy**: Objetos nativos hasta que se necesite álgebra
- ✅ **Helpers dinámicos**: Sistema de ayuda contextual auto-descubierto
- ✅ **Aritmética nativa**: Operaciones que preservan tipos originales
### Versión 2.0 (CAS Híbrido) - **ANTERIOR**
- ✅ Motor SymPy completo como base
- ❌ ~~Sintaxis con corchetes únicamente~~ **ELIMINADO**
- ✅ Detección automática de ecuaciones
- ✅ Variables SymPy puras
- ✅ Resultados interactivos clickeables
- ✅ Sistema de plotting integrado
- ✅ Arquitectura modular extensible
### Diferencias vs Versión Anterior
| Característica | v2.0 | v2.1 |
|---|---|---|
| Sintaxis | `Class[args]` | Tokenización automática |
| Tipos | Hardcodeados | Auto-descubrimiento |
| Parser | Específico | Genérico distribuido |
| Extensibilidad | Manual | Automática |
| Aritmética | SymPy siempre | Nativa + SymPy cuando se necesite |
| Tokenización | Centralizada | Distribuida por clase |
## FAQ
### ¿Cómo funciona la tokenización automática?
El sistema reconoce patrones como `16#FF` y `192.168.1.1` automáticamente y los convierte en objetos `IntBase` y `FourBytes` respectivamente. No necesita sintaxis especial.
### ¿Puedo usar la sintaxis de corchetes?
No. La v2.1 usa tokenización automática invisible que es más natural e intuitiva.
### ¿Cómo agregar nuevos tipos?
1. Crear archivo en `custom_types/nuevo_type.py`
2. Implementar clase con `get_tokenization_patterns()` y `register_classes_in_module()`
3. El sistema lo detecta automáticamente
### ¿Los resultados son exactos?
Sí. Los objetos mantienen precisión nativa hasta que se convierten a SymPy para álgebra compleja.
### ¿Cómo funcionan las conversiones entre tipos?
Son automáticas y bidireccionales. Por ejemplo: `Hex(192.168.1.1)` convierte FourBytes a Hex automáticamente.
### ¿Puedo crear tipos que usen múltiples patrones?
Sí. Cada tipo puede definir múltiples patrones con diferentes prioridades en `get_tokenization_patterns()`.
### ¿Cómo debuggear problemas de tipos?
Use **Menú Tipos → Información de tipos** para ver tipos descubiertos y **Menú Configuración → Recargar Tipos** para desarrollo.
---
*Calculadora MAV - CAS Híbrido v2.1*
*Sistema extensible con tokenización automática para cálculo matemático avanzado*

View File

@ -1,234 +0,0 @@
# Guía de Principios Arquitectónicos - Calculadora Algebraica Híbrida
## Filosofía Central: Álgebra Simbólica con Evaluación Numérica
### Concepto Fundamental
La calculadora mantiene **forma simbólica como representación primaria** y proporciona **evaluación numérica como información complementaria** cuando es posible y útil.
**Principio de Evaluación Numérica**: El resultado siempre se intenta calcular numéricamente y se muestra cuando la representación string del resultado numérico difiere del resultado algebraico.
## Sistema de Asignaciones y Ecuaciones
### Principio: Separación clara entre asignaciones y ecuaciones
```python
# Asignación de variable
x = 5 # → Se guarda el valor simbólico (NO se agrega como ecuación)
y = x + a # → Se guarda la expresión simbólica
# Ecuación pura (detección automática)
x**2 + 2*x = 8 # → Se agrega como ecuación Eq(x**2 + 2*x, 8)
a + b = 10 # → Se agrega como ecuación Eq(a + b, 10)
a > b + 1 # → Se agrega como desigualdad
```
### Criterios de Detección de Ecuaciones
**Se considera ecuación si:**
- Contiene `=` Y NO es una asignación simple de variable
- Contiene operadores de comparación: `==`, `>`, `<`, `>=`, `<=`
- Tiene estructura algebraica en ambos lados del `=`
**NO se considera ecuación:**
- Asignaciones simples: `x = 5`, `y = expresión`
- Líneas con solo números o comentarios
---
## Uso de `solve()` y el Atajo `=?`
### Principio: `variable=?` es equivalente a `solve(variable)`
```python
# Ambas formas son idénticas:
solve(a) # Resuelve 'a' usando el sistema de ecuaciones
a=? # Atajo sintáctico para solve(a)
```
El comando intenta resolver algebraicamente y numéricamente en paralelo cuando es posible.
---
## Sistema de Tokenización con Prioridades
### Principio: Las prioridades son números arbitrarios que determinan el orden de aplicación
```
Prioridad 5: IntBase → Patrón: 16#FF (muy específico)
Prioridad 6: Hex/Bin → Patrón: 0xFF, 0b1010 (específico)
Prioridad 10: FourBytes → Patrón: x.x.x.x (general)
```
**Regla**: Menor número = se aplica primero
Esto garantiza que `16#10.10.10.10` se tokenice como IntBase antes de considerar FourBytes.
---
## Conversión Perezosa y Tipos Especializados
### Principio: Mantener el tipo especializado siempre que sea posible
**Se evita convertir a SymPy al máximo**. Los objetos especializados mantienen su tipo cuando pueden resolver la operación internamente.
```python
# Operaciones que mantienen el tipo especializado:
Hex(15) + 1 → Hex(16) # Hex maneja la suma
16#15 + 1 → 16#16 # IntBase maneja la suma
10.1.1.1 + 1 → 10.1.1.2 # FourBytes maneja la suma
# Conversión a SymPy solo cuando es necesario:
sin(16#FF) → sin(255) # sin() requiere SymPy
solve(x + 16#10) → solve() # Álgebra compleja requiere SymPy
```
**Regla**: Solo se convierte a SymPy cuando el token no es atómico o la operación requiere capacidades algebraicas avanzadas.
---
## Contexto Limpio por Evaluación
### Principio: Cada evaluación comienza desde cero
**Contexto Limpio** significa:
- Se eliminan todas las ecuaciones previas
- Se eliminan todas las variables definidas
- Se re-evalúa todo el contenido línea por línea
- Comportamiento idéntico a iniciar una nueva sesión
Esto garantiza resultados predecibles y sin efectos secundarios acumulados.
---
## Resultados Interactivos
### Principio: Activación mediante clicks en elementos con binding
Los resultados interactivos se crean cuando el tipo de resultado requiere visualización expandida:
```python
plot(sin(x)) → "📊 Ver Plot" # Click abre ventana matplotlib
Matrix([[1,2],[3,4]]) → "📋 Ver Matriz" # Click muestra matriz formateada
[1,2,3,4,5,6,7,8] → "📋 Ver Lista" # Click expande contenido
```
**Activación**: Click en el texto con binding dispara la ventana emergente correspondiente.
---
## Sistema de Autocompletado
### Principio: Sistema extensible con prioridades (por implementar)
Se propone usar un sistema de prioridades numéricas similar al de tokenización:
```
Prioridad 1: Métodos del objeto específico
Prioridad 2: Métodos de la clase base
Prioridad 3: Funciones SymPy relevantes
Prioridad 4: Helpers contextuales
```
---
## Integración con SymPy
### Principio: En casos de conflicto, siempre prevalece SymPy
Cuando hay ambigüedad o conflicto entre tipos personalizados y SymPy:
- Funciones SymPy tienen precedencia
- Símbolos SymPy (como `e`, `pi`) mantienen su significado matemático
- Las conversiones fallidas retornan a comportamiento SymPy estándar
---
## Arquitectura de Tipos Personalizados
### Clases Base Universales
**IntBase**: Números en cualquier base
- Aritmética nativa que preserva la base
- Conversión a SymPy solo cuando necesario
- Soporte para símbolos algebraicos
**FourBytes**: Patrones x.x.x.x
- Aritmética de 32-bit para IPs
- Soporte para elementos simbólicos
- Base para tipos como IP4
### Principio de Extensibilidad
Cada tipo en `custom_types/` define:
1. Su lógica de tokenización
2. Sus operaciones aritméticas
3. Sus métodos de conversión
4. Su ayuda contextual
5. Sus sugerencias de autocompletado
---
## Flujo de Evaluación Completo
```
Entrada Usuario
[Tokenización Universal]
¿Asignación o Ecuación?
├─ Asignación → Guardar valor simbólico
└─ Ecuación → Agregar al sistema
[Evaluación]
├─ Mantener tipo especializado si es posible
└─ Convertir a SymPy si es necesario
[Resultado]
├─ Forma simbólica (siempre)
└─ Evaluación numérica (si difiere como string)
```
---
## Ejemplos Integrales
```python
# Tokenización y tipos especializados
16#FF + 2#1010 → 16#109 # IntBase preservado
192.168.1.1 + 5 → 192.168.1.6 # FourBytes preservado
# Asignaciones vs ecuaciones
x = 10 # Asignación (solo guarda valor)
x + y = 15 # Ecuación (se agrega al sistema)
y=? # solve(y) → y = 5
# Evaluación numérica automática
4/5 → 4/5 ≈ 0.8 # Difiere como string
sqrt(2) → √2 ≈ 1.414 # Difiere como string
2 + 3 → 5 # NO se muestra ≈ (igual string)
# Resultados interactivos
plot(sin(x)) → "📊 Ver Plot" [clickeable]
Matrix([[1,2]]) → "📋 Ver Matriz" [clickeable]
```
---
## Principios de Diseño Resumidos
1. **Álgebra primero**: Mantener forma simbólica siempre
2. **Evaluación numérica inteligente**: Mostrar solo cuando agrega valor
3. **Tipos especializados preservados**: Conversión a SymPy solo cuando necesario
4. **Tokenización ordenada**: Sistema de prioridades simple y predecible
5. **Contexto limpio**: Cada evaluación desde cero
6. **Extensibilidad**: Nuevos tipos se integran automáticamente
7. **SymPy prevalece**: En conflictos, el comportamiento matemático estándar gana
Este documento ahora refleja con precisión la arquitectura implementada y sirve como guía coherente para el desarrollo futuro.

View File

@ -1,462 +0,0 @@
# Simple Debug API - Guía para LLM
## Propósito
Esta API permite debuggear la **Calculadora MAV CAS** sin modificar código fuente ni crear scripts adicionales.
**Principio**: **texto → texto** tal como se muestra en la aplicación.
**NO duplica lógica**, solo encapsula llamadas directas al motor existente.
Como LLM, puedes usar esta herramienta para:
- **Diagnosticar problemas** en el motor de evaluación
- **Verificar comportamiento** de tipos personalizados (FourBytes, IntBase, IP4Mask, etc.)
- **Inspeccionar el estado interno** del motor (variables, contexto, tipos registrados)
- **Testing de regresión** para verificar que cambios no rompan funcionalidad existente
## Flujo de Trabajo Recomendado
### 1. Crear archivo JSON con queries
### 2. Ejecutar: `python simple_debug.py archivo.json`
### 3. Analizar resultados en el archivo `*_results.json`
---
## Tipos de Query
### Query tipo `input`
Evalúa expresiones como si el usuario las escribiera en la calculadora.
**Resultado**: texto tal como se muestra en la aplicación.
```json
{"index": 0, "type": "input", "content": "10.1.1.1 + 1"}
```
### Query tipo `exec`
Ejecuta código Python para inspeccionar el estado interno del motor.
**Resultado**: valor directo de la evaluación Python.
```json
{"index": 1, "type": "exec", "content": "type(engine.last_result).__name__"}
```
---
## Plantilla Base
```json
{
"queries": [
{"index": 0, "type": "input", "content": "EXPRESION_A_EVALUAR"},
{"index": 1, "type": "exec", "content": "CODIGO_PYTHON_INSPECCION"}
]
}
```
---
## Casos de Uso Comunes
### Debugging de Tipos Personalizados
**Problema**: Verificar si FourBytes maneja correctamente operaciones IP.
```json
{
"queries": [
{"index": 0, "type": "input", "content": "192.168.1.1 + 1"},
{"index": 1, "type": "exec", "content": "type(engine.last_result).__name__"},
{"index": 2, "type": "exec", "content": "engine.last_result.original"},
{"index": 3, "type": "exec", "content": "engine.last_result._numeric_value"},
{"index": 4, "type": "input", "content": "10.0.0.0/8 + 256"},
{"index": 5, "type": "exec", "content": "engine.last_result.has_symbols"}
]
}
```
### Debugging de Tokenización
**Problema**: La expresión `192.168.1.x + 16#FF` no se tokeniza correctamente.
```json
{
"queries": [
{"index": 0, "type": "exec", "content": "engine.parser.process_expression('192.168.1.x + 16#FF')"},
{"index": 1, "type": "input", "content": "192.168.1.x + 16#FF"},
{"index": 2, "type": "exec", "content": "engine.parser.get_tokenization_info()"},
{"index": 3, "type": "exec", "content": "len(engine.parser.tokenizer.tokenization_rules)"}
]
}
```
### Debugging de Errores
**Problema**: IP4Mask rechaza máscaras que deberían ser válidas.
```json
{
"queries": [
{"index": 0, "type": "input", "content": "mask = 255.240.0.0"},
{"index": 1, "type": "input", "content": "IP4Mask(mask)"},
{"index": 2, "type": "exec", "content": "engine.last_result"},
{"index": 3, "type": "input", "content": "IP4Mask(255.240.0.3)"},
{"index": 4, "type": "exec", "content": "engine.last_result"}
]
}
```
### Debugging de Estado del Motor
**Problema**: Las variables no se están guardando correctamente.
```json
{
"queries": [
{"index": 0, "type": "input", "content": "x = 5"},
{"index": 1, "type": "input", "content": "y = x + 10"},
{"index": 2, "type": "exec", "content": "engine.symbol_table"},
{"index": 3, "type": "exec", "content": "len(engine.symbol_table)"},
{"index": 4, "type": "exec", "content": "list(engine.symbol_table.keys())"},
{"index": 5, "type": "input", "content": "solve(z**2 + x, z)"},
{"index": 6, "type": "exec", "content": "len(engine.equations)"}
]
}
```
---
## Interpretación de Resultados
### Estructura del Resultado
```json
{
"execution_info": {
"timestamp": "2025-06-05T18:25:22.256442Z",
"total_queries": 5,
"successful": 4,
"failed": 1
},
"results": [...]
}
```
### Resultado Individual (Query `input`)
```json
{
"index": 0,
"input": "10.1.1.1 + 1",
"output": "10.1.1.2", // Texto tal como se muestra en la app
"result_type": "FourBytes", // Tipo del objeto resultado
"success": true,
"error": null
}
```
### Resultado Individual (Query `exec`)
```json
{
"index": 1,
"input": "type(engine.last_result).__name__",
"output": "FourBytes", // String del resultado
"result_type": "str", // Tipo del resultado de la evaluación
"success": true,
"error": null,
"exec_result": "FourBytes" // Valor directo (serializado si es necesario)
}
```
### Resultado con Error
```json
{
"index": 2,
"input": "IP4Mask(255.240.0.3)",
"output": "None",
"result_type": "NoneType",
"success": false,
"error": "❌ Máscara inválida: 255.240.0.3..."
}
```
---
## Funciones de Inspección Útiles
### Estado del Motor
```python
"engine.symbol_table" # Variables actuales
"engine.last_result" # Último resultado
"engine.symbolic_mode" # ¿Modo simbólico activo?
"len(engine.equations)" # Cantidad de ecuaciones en el sistema
"engine.debug" # ¿Debug habilitado?
"list(engine.base_context.keys())[:10]" # Funciones disponibles (muestra 10)
```
### Información de Tipos
```python
"engine.get_available_types()" # Info completa de tipos registrados
"list(engine.registered_types_info['registered_classes'].keys())" # Lista de tipos
"engine.registered_types_info['class_count']" # Cantidad de tipos registrados
"type(engine.last_result).__name__" # Tipo del último resultado
"hasattr(engine.last_result, 'has_symbols')" # ¿El resultado tiene símbolos?
```
### Tokenización y Parsing
```python
"engine.parser.get_tokenization_info()" # Info completa de tokenización
"engine.parser.process_expression('test')" # Procesar expresión específica
"len(engine.parser.tokenizer.tokenization_rules)" # Cantidad de reglas
"engine._classify_line('x = 5')" # Clasificar tipo de línea
"engine._extract_variable_names('x + y')" # Extraer nombres de variables
```
### Análisis de Objetos Específicos
```python
# Para FourBytes
"engine.last_result.original" # String original
"engine.last_result._numeric_value" # Valor numérico interno
"engine.last_result.has_symbols" # ¿Tiene símbolos?
# Para IntBase
"engine.last_result.base" # Base numérica (10, 16, 8, 2)
"engine.last_result.value_str" # String del valor
"engine.last_result._symbols" # Símbolos detectados
# Para IP4Mask
"engine.last_result.get_prefix_int()" # Prefijo como entero
"engine.last_result.is_valid()" # ¿Es máscara válida?
```
---
## Patrones de Debugging
### 1. Debugging de Regresión
**Cuándo usar**: Verificar que cambios no rompan funcionalidad existente.
```json
{
"queries": [
{"index": 0, "type": "input", "content": "10.1.1.1 + 1"},
{"index": 1, "type": "exec", "content": "type(engine.last_result).__name__"},
{"index": 2, "type": "input", "content": "16#FF + 10"},
{"index": 3, "type": "exec", "content": "engine.last_result.base"},
{"index": 4, "type": "input", "content": "IP4Mask(255.255.0.0)"},
{"index": 5, "type": "exec", "content": "engine.last_result.get_prefix_int()"}
]
}
```
### 2. Debugging de Nuevas Funcionalidades
**Cuándo usar**: Verificar que nueva funcionalidad trabaja correctamente.
```json
{
"queries": [
{"index": 0, "type": "input", "content": "NUEVA_FUNCIONALIDAD_AQUI"},
{"index": 1, "type": "exec", "content": "type(engine.last_result)"},
{"index": 2, "type": "exec", "content": "dir(engine.last_result)"},
{"index": 3, "type": "exec", "content": "str(engine.last_result)"},
{"index": 4, "type": "exec", "content": "engine.symbol_table"}
]
}
```
### 3. Debugging de Performance
**Cuándo usar**: Identificar operaciones lentas o problemáticas.
```json
{
"queries": [
{"index": 0, "type": "exec", "content": "import time; start = time.time()"},
{"index": 1, "type": "input", "content": "OPERACION_LENTA"},
{"index": 2, "type": "exec", "content": "time.time() - start"},
{"index": 3, "type": "exec", "content": "len(engine.symbol_table)"}
]
}
```
### 4. Debugging de Comportamiento
**Cuándo usar**: Verificar comportamiento específico de tipos o funciones.
```json
{
"queries": [
{"index": 0, "type": "input", "content": "EXPRESION"},
{"index": 1, "type": "exec", "content": "str(engine.last_result)"},
{"index": 2, "type": "exec", "content": "repr(engine.last_result)"},
{"index": 3, "type": "exec", "content": "type(engine.last_result).__name__"}
]
}
```
---
## Comandos de Ejecución
```bash
# Ejecución básica
python simple_debug.py mi_debug.json
# Con archivo de salida específico
python simple_debug.py mi_debug.json --output resultados.json
# Modo verboso (para ver progreso)
python simple_debug.py mi_debug.json --verbose
```
---
## Templates Existentes para Reutilizar
### Casos Básicos
**Archivo**: `debug_templates/basic_test.json`
- Operaciones con FourBytes e IntBase
- Variables y SymPy básico
### Testing de Errores
**Archivo**: `debug_templates/error_debug.json`
- Máscaras inválidas
- IPs fuera de rango
- Expresiones malformadas
### Información de Contexto
**Archivo**: `debug_templates/context_debug.json`
- Estado completo del motor
- Tipos registrados
- Sistema de ecuaciones
### Tokenización
**Archivo**: `debug_templates/tokenization_test.json`
- Debug del sistema de parsing
- Reglas de tokenización
---
## Flujo de Resolución de Problemas
### 1. Identificar el Problema
- ¿Es un error de evaluación?
- ¿Es un problema de tokenización?
- ¿Es un problema de estado del motor?
### 2. Crear Query de Diagnóstico
- Usar query `input` para reproducir el problema
- Usar query `exec` para inspeccionar el estado
### 3. Analizar Resultados
- Verificar `success: true/false`
- Examinar `error` si hay fallo
- Comparar `output` (texto de la app) con `exec_result` (valor interno)
### 4. Iterar
- Crear nuevas queries basadas en hallazgos
- Profundizar en áreas problemáticas
- Verificar soluciones con queries adicionales
---
## Ejemplo Completo de Debugging
**Problema**: "La operación `192.168.1.x + 1` no funciona correctamente"
### Paso 1: Crear archivo de debug
```json
{
"queries": [
{"index": 0, "type": "input", "content": "192.168.1.x + 1"},
{"index": 1, "type": "exec", "content": "type(engine.last_result).__name__"},
{"index": 2, "type": "exec", "content": "engine.last_result.has_symbols"},
{"index": 3, "type": "exec", "content": "engine.parser.process_expression('192.168.1.x + 1')"},
{"index": 4, "type": "input", "content": "ip = 192.168.1.x"},
{"index": 5, "type": "exec", "content": "type(engine.symbol_table['ip'])"},
{"index": 6, "type": "input", "content": "ip.substitute(x=5)"}
]
}
```
### Paso 2: Ejecutar
```bash
python simple_debug.py debug_problema.json
```
### Paso 3: Analizar resultados
- Verificar si `192.168.1.x + 1` se evalúa correctamente (campo `output`)
- Comprobar el tipo resultante con `exec`
- Verificar si tiene símbolos
- Examinar cómo se tokeniza la expresión
- Probar operaciones relacionadas
Este flujo te permite identificar exactamente dónde está el problema y verificar la solución.
---
## Consejos para LLMs
1. **Siempre usa índices secuenciales** en las queries para facilitar la lectura
2. **Combina queries `input` y `exec`** para obtener contexto completo
3. **El campo `output` es texto tal como se muestra en la aplicación**
4. **El campo `exec_result` es el valor directo de la evaluación Python**
5. **Usa los templates existentes** como punto de partida
6. **Examina `success` y `error`** antes de analizar resultados
7. **Crea queries incrementales** que construyan sobre resultados anteriores
8. **NO intentes duplicar lógica de la aplicación** - usa solo llamadas directas
---
## Referencia Rápida
### Query Básica
```json
{"index": N, "type": "input|exec", "content": "CONTENIDO"}
```
### Comandos Esenciales
```bash
python simple_debug.py archivo.json # Ejecutar debug
python simple_debug.py archivo.json --verbose # Con detalles
python simple_debug.py archivo.json -o resultado.json # Salida específica
```
### Inspección Básica del Motor
```python
"engine.last_result" # Último resultado
"type(engine.last_result)" # Tipo del resultado
"engine.symbol_table" # Variables actuales
"engine.get_available_types()" # Tipos registrados
"engine.parser.get_tokenization_info()" # Info de parsing
```
### Análisis de Resultado
```python
"success": true/false # ¿Éxito?
"error": "mensaje" # Error si falla
"output": "resultado" # Texto tal como se muestra en la app
"exec_result": valor # Valor directo (exec queries)
```
### Templates Disponibles
- `debug_templates/basic_test.json` - Pruebas básicas
- `debug_templates/error_debug.json` - Testing de errores
- `debug_templates/context_debug.json` - Estado del motor
- `debug_templates/tokenization_test.json` - Debug de parsing
### Workflow Típico
1. **Identificar problema** → Crear query `input` para reproducir
2. **Inspeccionar estado** → Añadir queries `exec` para diagnosticar
3. **Analizar resultados** → Examinar `success`, `error`, `output`
4. **Iterar** → Crear nuevas queries basadas en hallazgos
**Principio clave**: texto → texto. La API no interpreta ni procesa, solo encapsula llamadas directas al motor existente.

View File

@ -1,166 +0,0 @@
# Sistema de Tokenización Distribuida - IMPLEMENTADO
## ✅ IMPLEMENTACIÓN COMPLETADA
Se ha implementado exitosamente el sistema de tokenización distribuida según las especificaciones, reemplazando completamente el sistema de corchetes por un tokenizador universal que auto-descubre reglas.
## 🏗️ Arquitectura Implementada
### 1. **UniversalTokenizer** (en `tl_bracket_parser.py`)
- **Auto-descubrimiento**: Descubre automáticamente reglas de tokenización desde todas las clases registradas
- **Prioridad**: Ordena reglas por prioridad (menor número = mayor prioridad)
- **Aplicación secuencial**: Aplica reglas en orden de prioridad
- **Debug integrado**: Sistema completo de debug y estadísticas
### 2. **TokenizationParser** (en `tl_bracket_parser.py`)
- **Integración completa**: Integra tokenización con el parser existente
- **Compatibilidad**: Mantiene interfaz compatible con BracketParser
- **Estadísticas**: Tracking de conversiones y rendimiento
### 3. **Clases Base Universales**
#### **IntBase** (en `custom_types/intbase_type.py`)
- **Patrón**: `(\d+)#([0-9A-Fa-fx]+)`
- **Prioridad**: 5 (ALTA - patrón específico)
- **Ejemplos**: `16#FF``IntBase("FF", 16)`, `2#1010``IntBase("1010", 2)`
- **Capacidades**: Aritmética nativa, símbolos algebraicos, conversión de bases
#### **FourBytes** (en `custom_types/fourbytes_type.py`)
- **Patrón**: `(?<!FourBytes\(")(?<!")([a-zA-Z0-9_]+\.[a-zA-Z0-9_]+\.[a-zA-Z0-9_]+\.[a-zA-Z0-9_]+)(?!")`
- **Prioridad**: 10 (MENOR - patrón general)
- **Ejemplos**: `192.168.1.1``FourBytes("192.168.1.1")`, `10.x.y.z``FourBytes("10.x.y.z")`
- **Capacidades**: Aritmética de 32-bit, símbolos algebraicos, conversiones
### 4. **Clases Especializadas Adaptadas**
#### **Hex** (en `custom_types/hex_type.py`)
- **Patrón adicional**: `\b0x([0-9A-Fa-f]+)\b`
- **Prioridad**: 6 (MEDIA - específica de hex)
- **Ejemplo**: `0xFF``Hex("FF")`
- **Delegación**: Usa IntBase internamente
#### **Bin** (en `custom_types/bin_type.py`)
- **Patrón adicional**: `\b0b([01]+)\b`
- **Prioridad**: 6 (MEDIA - específica de binario)
- **Ejemplo**: `0b1010``Bin("1010")`
- **Delegación**: Usa IntBase internamente
#### **IP4** (en `custom_types/ip4_type.py`)
- **Sin tokenización directa**: Usa FourBytes desde tokenización automática
- **Constructor mejorado**: Acepta FourBytes, IntBase para máscaras
- **Ejemplos**: `IP4(FourBytes("192.168.1.1"), IntBase("ffffff00", 16))`
## 🔧 Integración con Motor de Evaluación
### **HybridEvaluationEngine** (en `main_evaluation.py`)
- **Tokenización automática**: Aplica tokenización en cada expresión
- **Contexto dinámico**: Clases base cargadas automáticamente desde el registro
- **Debug sincronizado**: Sistema de debug coordinado entre motor, parser y tokenizador
## 🧪 Validación Completa
### **Pruebas Exitosas**
```bash
# Todas las pruebas pasaron exitosamente:
✅ Registro de tipos: 9 clases registradas
✅ Reglas de tokenización: 8 reglas activas
✅ IntBase: '16#ff' → IntBase("ff", 16)
✅ FourBytes: '192.168.1.1' → FourBytes("192.168.1.1")
✅ Hex: '0xFF' → Hex("FF")
✅ Bin: '0b1010' → Bin("1010")
✅ Evaluación directa funcional
✅ Contexto del motor completo
```
### **Casos de Uso Validados**
```python
# Tokenización automática funcionando:
a = 16#FF # → IntBase("FF", 16)
b = 192.168.1.1 # → FourBytes("192.168.1.1")
c = 0xFF # → Hex("FF")
d = 0b1010 # → Bin("1010")
# Operaciones mixtas:
resultado = a + 5 # IntBase mantiene base
ip_suma = b + 256 # FourBytes mantiene tipo
# Símbolos algebraicos:
symb_ip = 10.x.y.0 # → FourBytes("10.x.y.0")
symb_hex = 16#x0 # → IntBase("x0", 16)
```
## 🎯 Beneficios Logrados
### **1. Simplicidad para el Usuario**
- ✅ **Sintaxis natural**: Usuario escribe Python estándar
- ✅ **Sin curva de aprendizaje**: No hay sintaxis especial
- ✅ **Tokenización invisible**: Funciona automáticamente
### **2. Potencia del Sistema**
- ✅ **Extensibilidad**: Fácil agregar nuevos tipos con tokenización
- ✅ **Flexibilidad**: Cada clase define sus propios patrones
- ✅ **Modularidad**: Sistema completamente distribuido
### **3. Robustez Técnica**
- ✅ **Auto-descubrimiento**: Sistema dinámico, no hardcodeado
- ✅ **Prioridades**: Control preciso de precedencia
- ✅ **Compatibilidad**: Mantiene interfaz existente
- ✅ **Debug completo**: Trazabilidad total del proceso
## 🔄 Migración Completada
### **Antes: Sistema de Corchetes**
```python
# Sintaxis compleja y específica:
ip = [IP4: 192.168.1.1, 24]
hex_val = [Hex: ff]
```
### **Después: Tokenización Distribuida**
```python
# Sintaxis Python natural:
ip = IP4(192.168.1.1, 24) # Automáticamente tokenizado
hex_val = 16#ff # Automáticamente tokenizado
```
## 🚀 Extensión Futura
### **Agregar Nuevos Tipos**
Para agregar un nuevo tipo con tokenización:
1. **Crear archivo**: `custom_types/mitype_type.py`
2. **Implementar método**:
```python
@staticmethod
def get_tokenization_patterns():
return [
{
'pattern': r'mi_patron_regex',
'replacement': lambda match: f'MiClase("{match.group(1)}")',
'priority': 7, # Elegir prioridad apropiada
'description': 'Descripción del patrón'
}
]
```
3. **Registrar**: El sistema auto-descubre automáticamente
### **Patrones Disponibles para Extensión**
- **Fechas/Tiempo**: `HH:MM:SS`, `YYYY-MM-DD`
- **MACs**: `xx:xx:xx:xx:xx:xx`
- **UUIDs**: `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
- **Coordenadas**: `lat,lng`
- **Cualquier patrón específico del dominio**
## 📋 Estado Final
**✅ SISTEMA COMPLETAMENTE IMPLEMENTADO Y FUNCIONAL**
- Sistema de tokenización distribuida operativo
- Auto-descubrimiento funcionando
- Todas las clases adaptadas correctamente
- Integración con motor de evaluación completa
- Pruebas exitosas en todos los componentes
- Documentación y ejemplos incluidos
El sistema está listo para producción y extensión futura según las especificaciones del documento `@tokenizacion_distribuida.md`.

View File

@ -1,392 +0,0 @@
# Simple Debug API - Calculadora MAV CAS
## Descripción
API CLI simple que usa el motor de evaluación existente para generar debug traces sin modificar el código base. Permite debuggear "como si usaras la aplicación" mediante archivos JSON.
---
## Uso
```bash
# Ejecutar debug
python simple_debug.py debug_input.json
# Con archivo de salida específico
python simple_debug.py debug_input.json --output debug_results.json
# Modo verboso
python simple_debug.py debug_input.json --verbose
```
---
## Formato de Entrada
### Estructura Simple
```json
{
"queries": [
{"index": 0, "type": "input", "content": "10.1.1.1 + 1"},
{"index": 1, "type": "input", "content": "16#FF + 10"},
{"index": 2, "type": "exec", "content": "engine.symbol_table"},
{"index": 3, "type": "input", "content": "x = 5"},
{"index": 4, "type": "exec", "content": "len(engine.symbol_table)"}
]
}
```
### Tipos de Query
#### Input Query
Evalúa expresiones como si las escribieras en la calculadora:
```json
{"index": 0, "type": "input", "content": "10.1.1.1 + 1"}
{"index": 1, "type": "input", "content": "mask = 255.255.0.0"}
{"index": 2, "type": "input", "content": "solve(x**2 + 1, x)"}
```
#### Exec Query
Ejecuta código Python para inspeccionar el estado interno:
```json
{"index": 3, "type": "exec", "content": "engine.symbol_table"}
{"index": 4, "type": "exec", "content": "engine.parser.get_tokenization_info()"}
{"index": 5, "type": "exec", "content": "list(engine.base_context.keys())[:10]"}
```
---
## Formato de Salida
### Estructura de Respuesta
```json
{
"execution_info": {
"timestamp": "2025-01-01T10:30:15Z",
"total_queries": 5,
"successful": 4,
"failed": 1
},
"results": [
{
"index": 0,
"input": "10.1.1.1 + 1",
"output": "10.1.1.2",
"result_type": "FourBytes",
"success": true
},
{
"index": 1,
"input": "16#FF + 10",
"output": "16#109",
"result_type": "IntBase",
"success": true
},
{
"index": 2,
"input": "engine.symbol_table",
"output": "{'x': Symbol('x'), 'mask': FourBytes('255.255.0.0')}",
"result_type": "dict",
"success": true
}
]
}
```
### Resultado Individual
```json
{
"index": 0,
"input": "10.1.1.1 + 1",
"output": "10.1.1.2",
"result_type": "FourBytes",
"success": true,
"error": null,
"display_class": "[FourBytes]"
}
```
### Resultado con Error
```json
{
"index": 3,
"input": "IP4Mask(255.240.0.3)",
"output": null,
"result_type": null,
"success": false,
"error": "ValueError: Máscara inválida: 255.240.0.3"
}
```
### Resultado de Exec
```json
{
"index": 4,
"input": "len(engine.symbol_table)",
"output": "3",
"result_type": "int",
"success": true,
"exec_result": 3
}
```
---
## Casos de Uso Comunes
### 1. Debug de Tokenización
```json
{
"queries": [
{"index": 0, "type": "input", "content": "192.168.1.1 + 16#FF"},
{"index": 1, "type": "exec", "content": "engine.parser.process_expression('192.168.1.1 + 16#FF')"},
{"index": 2, "type": "exec", "content": "engine.parser.get_tokenization_info()"}
]
}
```
### 2. Debug de Contexto
```json
{
"queries": [
{"index": 0, "type": "input", "content": "x = 5"},
{"index": 1, "type": "input", "content": "y = x + 10"},
{"index": 2, "type": "exec", "content": "engine.symbol_table"},
{"index": 3, "type": "exec", "content": "len(engine.equations)"}
]
}
```
### 3. Debug de Tipos
```json
{
"queries": [
{"index": 0, "type": "input", "content": "ip = 10.1.1.x"},
{"index": 1, "type": "exec", "content": "type(engine.symbol_table['ip'])"},
{"index": 2, "type": "exec", "content": "engine.symbol_table['ip'].has_symbols"},
{"index": 3, "type": "input", "content": "ip.substitute(x=5)"}
]
}
```
### 4. Debug de Errores
```json
{
"queries": [
{"index": 0, "type": "input", "content": "bad_mask = 255.240.0.3"},
{"index": 1, "type": "input", "content": "IP4Mask(bad_mask)"},
{"index": 2, "type": "exec", "content": "engine.last_result"}
]
}
```
### 5. Testing de Regresión
```json
{
"queries": [
{"index": 0, "type": "input", "content": "10.1.1.1 + 1"},
{"index": 1, "type": "exec", "content": "str(type(engine.last_result))"},
{"index": 2, "type": "exec", "content": "engine.last_result.original"},
{"index": 3, "type": "input", "content": "16#FF + 10"},
{"index": 4, "type": "exec", "content": "engine.last_result.base"}
]
}
```
---
## Funciones Útiles para Exec
### Estado del Motor
```python
# Contexto y variables
"engine.symbol_table" # Variables actuales
"list(engine.base_context.keys())" # Funciones disponibles
"len(engine.equations)" # Ecuaciones en el sistema
"engine.last_result" # Último resultado
# Configuración del motor
"engine.symbolic_mode" # ¿Modo simbólico?
"engine.debug" # ¿Debug habilitado?
```
### Información de Tipos
```python
# Tipos registrados
"engine.get_available_types()" # Info completa de tipos
"list(engine.registered_types_info['registered_classes'].keys())" # Tipos disponibles
"engine.registered_types_info['class_count']" # Cantidad de tipos
# Análisis de objetos
"type(engine.last_result)" # Tipo del último resultado
"engine.last_result.__class__.__name__" # Nombre de la clase
"hasattr(engine.last_result, 'has_symbols')" # ¿Tiene símbolos?
```
### Tokenización y Parsing
```python
# Tokenización
"engine.parser.get_tokenization_info()" # Info de tokenización
"engine.parser.process_expression('test')" # Procesar expresión
"len(engine.parser.tokenizer.tokenization_rules)" # Cantidad de reglas
# Análisis de expresiones
"engine._classify_line('x = 5')" # Clasificar línea
"engine._extract_variable_names('x + y')" # Extraer variables
```
### Testing de Funciones Específicas
```python
# Testing de FourBytes
"engine.last_result._numeric_value" # Valor numérico interno
"engine.last_result.has_symbols" # ¿Tiene símbolos?
"engine.last_result.original" # String original
# Testing de IntBase
"engine.last_result.base" # Base numérica
"engine.last_result.value_str" # String del valor
"engine.last_result._symbols" # Símbolos detectados
```
---
## Implementación Simple
### Estructura Mínima
```
simple_debug.py # CLI principal (~100 líneas)
debug_templates/ # Templates de ejemplo
├── basic_test.json
├── tokenization_test.json
└── regression_test.json
```
### CLI Principal (Pseudocódigo)
```python
# simple_debug.py
import json
from main_evaluation import HybridEvaluationEngine
def run_debug(input_file, output_file=None):
# Cargar queries
with open(input_file) as f:
data = json.load(f)
# Crear motor
engine = HybridEvaluationEngine()
results = []
# Ejecutar cada query
for query in data['queries']:
if query['type'] == 'input':
result = engine.evaluate_line(query['content'])
output = {
'index': query['index'],
'input': query['content'],
'output': str(result.result),
'result_type': type(result.result).__name__,
'success': not result.is_error,
'error': result.error if result.is_error else None
}
elif query['type'] == 'exec':
try:
exec_result = eval(query['content'], {'engine': engine})
output = {
'index': query['index'],
'input': query['content'],
'output': str(exec_result),
'result_type': type(exec_result).__name__,
'success': True,
'exec_result': exec_result
}
except Exception as e:
output = {
'index': query['index'],
'input': query['content'],
'success': False,
'error': str(e)
}
results.append(output)
# Guardar resultados
final_output = {
'execution_info': {...},
'results': results
}
with open(output_file, 'w') as f:
json.dump(final_output, f, indent=2)
```
---
## Templates de Ejemplo
### basic_test.json
```json
{
"queries": [
{"index": 0, "type": "input", "content": "10.1.1.1 + 1"},
{"index": 1, "type": "exec", "content": "type(engine.last_result).__name__"},
{"index": 2, "type": "input", "content": "16#FF"},
{"index": 3, "type": "exec", "content": "engine.last_result.base"}
]
}
```
### tokenization_test.json
```json
{
"queries": [
{"index": 0, "type": "exec", "content": "engine.parser.process_expression('192.168.1.1 + 16#FF')"},
{"index": 1, "type": "input", "content": "192.168.1.1 + 16#FF"},
{"index": 2, "type": "exec", "content": "engine.parser.get_tokenization_info()['rules'][:3]"}
]
}
```
### regression_test.json
```json
{
"queries": [
{"index": 0, "type": "input", "content": "mask=255.240.0.0"},
{"index": 1, "type": "exec", "content": "type(engine.symbol_table['mask']).__name__"},
{"index": 2, "type": "input", "content": "10.1.1.1 + 1"},
{"index": 3, "type": "exec", "content": "type(engine.last_result).__name__"},
{"index": 4, "type": "input", "content": "IP4Mask(255.255.0.0)"},
{"index": 5, "type": "exec", "content": "engine.last_result.get_prefix_int()"}
]
}
```
---
## Ventajas de este Diseño
**Simplicidad**: ~100 líneas de código total
**Sin modificaciones**: Usa el motor existente tal como está
**Flexibilidad**: Cualquier función del engine es accesible via exec
**Debugging real**: Exactamente como usar la aplicación
**Fácil testing**: JSON simple para casos de prueba
**Serialización automática**: Python maneja la conversión a string
Esta aproximación te permite debuggear efectivamente sin crear una infraestructura compleja, usando el poder del motor existente.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2
.gitignore vendored
View File

@ -6,6 +6,8 @@ __pycache__/
# C extensions
*.so
*.json
# Distribution / packaging
.Python
build/

View File

@ -1,81 +0,0 @@
{
"execution_info": {
"timestamp": "2025-06-05T18:25:22.256442Z",
"total_queries": 8,
"successful": 8,
"failed": 0,
"input_file": "debug_templates\\basic_test.json"
},
"results": [
{
"index": 0,
"input": "10.1.1.1 + 1",
"output": "10.1.1.2",
"result_type": "FourBytes",
"success": true,
"error": null
},
{
"index": 1,
"input": "type(engine.last_result).__name__",
"output": "FourBytes",
"result_type": "str",
"success": true,
"error": null,
"exec_result": "FourBytes"
},
{
"index": 2,
"input": "16#FF",
"output": "16#FF",
"result_type": "IntBase",
"success": true,
"error": null
},
{
"index": 3,
"input": "engine.last_result.base",
"output": "16",
"result_type": "int",
"success": true,
"error": null,
"exec_result": 16
},
{
"index": 4,
"input": "mask = 255.255.0.0",
"output": "255.255.0.0",
"result_type": "FourBytes",
"success": true,
"error": null
},
{
"index": 5,
"input": "engine.symbol_table",
"output": "{'mask': FourBytes('255.255.0.0')}",
"result_type": "dict",
"success": true,
"error": null,
"exec_result": {
"mask": "255.255.0.0"
}
},
{
"index": 6,
"input": "solve(x**2 + 1, x)",
"output": "[-I, I]",
"result_type": "list",
"success": true,
"error": null
},
{
"index": 7,
"input": "len(engine.symbol_table)",
"output": "1",
"result_type": "int",
"success": true,
"error": null,
"exec_result": 1
}
]
}

View File

@ -2,15 +2,19 @@
Clase base universal para números en cualquier base - TIPO REGISTRADO
"""
from class_base import ClassBase
from sympy_Base import SympyClassBase
import sympy
import re
class IntBase(ClassBase):
class IntBase(SympyClassBase):
"""
Representación universal de números en cualquier base
con manejo interno de símbolos y conversión perezosa a SymPy
"""
# Prioridad alta para que SymPy use nuestros operadores aritméticos
_op_priority = 15
def __init__(self, value_str, base=10):
self.value_str = str(value_str)
self.base = int(base)
@ -19,18 +23,20 @@ class IntBase(ClassBase):
self.has_symbols = self._has_algebraic_symbols()
if self.has_symbols:
# Modo algebraico: mantener símbolos INTERNAMENTE, no convertir a SymPy aún
# Modo algebraico: mantener símbolos INTERNAMENTE
self._symbols = self._extract_symbols()
self._numeric_value = None # No hay valor numérico directo
original_str = f"{self.base}#{self.value_str}"
super().__init__(self.value_str, original_str) # ClassBase, NO SympyClassBase
# Para SympyClassBase: (numeric_value, string_representation)
super().__init__(self.value_str, original_str)
else:
# Modo numérico: convertir a entero
try:
self._numeric_value = int(self.value_str, self.base)
self._symbols = []
original_str = f"{self.base}#{self.value_str}"
super().__init__(self._numeric_value, original_str) # ClassBase
# Para SympyClassBase: (numeric_value, string_representation)
super().__init__(self._numeric_value, original_str)
except ValueError:
raise ValueError(f"Valor inválido '{self.value_str}' para base {self.base}")
@ -154,6 +160,20 @@ class IntBase(ClassBase):
def __add__(self, other):
"""Suma nativa - mantiene como IntBase cuando es posible"""
# Manejar tipos de SymPy (Integer, One, etc.)
if hasattr(other, '__int__'):
try:
other_int = int(other)
if self.has_symbols:
new_expr = f"({self.value_str}) + {other_int}"
return IntBase(new_expr, self.base)
else:
result_value = self._numeric_value + other_int
result_str = self._convert_to_base_string(int(result_value), self.base)
return IntBase(result_str, self.base)
except (ValueError, TypeError):
pass
if self.has_symbols:
# Con símbolos, crear expresión simbólica pero mantener IntBase
if isinstance(other, IntBase):
@ -190,6 +210,20 @@ class IntBase(ClassBase):
def __sub__(self, other):
"""Resta nativa"""
# Manejar tipos de SymPy
if hasattr(other, '__int__'):
try:
other_int = int(other)
if self.has_symbols:
new_expr = f"({self.value_str}) - {other_int}"
return IntBase(new_expr, self.base)
else:
result_value = self._numeric_value - other_int
result_str = self._convert_to_base_string(int(result_value), self.base)
return IntBase(result_str, self.base)
except (ValueError, TypeError):
pass
if self.has_symbols:
if isinstance(other, IntBase):
if other.has_symbols:
@ -281,6 +315,10 @@ class IntBase(ClassBase):
"""Representación para debug"""
return f"IntBase('{self.value_str}', {self.base})"
def _sympystr(self, printer):
"""Controla cómo SymPy representa este objeto"""
return f"{self.base}#{self.value_str}"
@staticmethod
def Helper(input_str):
"""Ayuda contextual para IntBase"""
@ -337,10 +375,10 @@ Métodos disponibles:
def register_classes_in_module():
"""Registro de IntBase en el sistema de tipos"""
return [
("IntBase", IntBase, "ClassBase", {
("IntBase", IntBase, "SympyClassBase", {
"add_lowercase": True,
"supports_brackets": False, # Se maneja por tokenización
"is_fundamental": True, # Clase fundamental del sistema
"description": "Números universales en cualquier base con álgebra simbólica"
"description": "Números universales en cualquier base con álgebra simbólica completa"
}),
]

View File

@ -357,6 +357,9 @@ class IP4Mask(ClassBase):
class Class_IP4(SympyClassBase):
"""Clase híbrida para direcciones IPv4 - ADAPTADA AL NUEVO SISTEMA"""
# Prioridad alta para que SymPy use nuestros operadores en lugar de conversión a entero
_op_priority = 20
def __init__(self, address, mask=None):
"""
Constructor mejorado que acepta FourBytes desde tokenización automática
@ -524,6 +527,89 @@ class Class_IP4(SympyClassBase):
def is_symbolic(self):
"""¿Contiene símbolos?"""
return self._has_symbols
# ========== OPERADORES ARITMÉTICOS PARA SYMPY ==========
def __add__(self, other):
"""Suma aritmética de direcciones IP - mantiene tipo IP4"""
# Manejar tipos de SymPy (Integer, One, etc.)
if hasattr(other, '__int__'):
try:
other_int = int(other)
return self.add_hosts(other_int)
except (ValueError, TypeError):
pass
if isinstance(other, (int, float)):
# ip + entero = ip + hosts
return self.add_hosts(int(other))
elif isinstance(other, Class_IP4):
# ip1 + ip2 = suma de enteros convertida a IP
new_int = self.to_integer() + other.to_integer()
return Class_IP4(new_int, self._mask_obj)
else:
# Para otros tipos, dejar que SymPy maneje
return NotImplemented
def __radd__(self, other):
"""Suma reversa"""
return self.__add__(other)
def __sub__(self, other):
"""Resta aritmética de direcciones IP"""
# Manejar tipos de SymPy
if hasattr(other, '__int__'):
try:
other_int = int(other)
return self.subtract_hosts(other_int)
except (ValueError, TypeError):
pass
if isinstance(other, (int, float)):
# ip - entero = ip - hosts
return self.subtract_hosts(int(other))
elif isinstance(other, Class_IP4):
# ip1 - ip2 = diferencia en hosts
return self.to_integer() - other.to_integer()
else:
return NotImplemented
def __rsub__(self, other):
"""Resta reversa"""
if isinstance(other, (int, float)):
# entero - ip = nueva IP
new_int = int(other) - self.to_integer()
return Class_IP4(new_int, self._mask_obj)
else:
return NotImplemented
def __mul__(self, other):
"""Multiplicación (útil para cálculos de subred)"""
if isinstance(other, (int, float)):
new_int = self.to_integer() * int(other)
return Class_IP4(new_int, self._mask_obj)
else:
return NotImplemented
def __rmul__(self, other):
"""Multiplicación reversa"""
return self.__mul__(other)
def __floordiv__(self, other):
"""División entera"""
if isinstance(other, (int, float)):
new_int = self.to_integer() // int(other)
return Class_IP4(new_int, self._mask_obj)
else:
return NotImplemented
def __mod__(self, other):
"""Módulo (útil para cálculos en subredes)"""
if isinstance(other, (int, float)):
remainder = self.to_integer() % int(other)
return Class_IP4(remainder, self._mask_obj)
else:
return NotImplemented
@staticmethod
def Helper(input_str):

View File

@ -1,9 +1,26 @@
a = x + 5 / z
# x = 5
y = x + 3
z = y + x
x=?
solve()
# Instanciación via sympify
ip = IP4(120.11.255.2,30)
ip.Nodes()
ip.to_hex()
ip + 1
10.1.1.1
p=Dec(16#FF + 16#FF) / 18
p
t= 2#1010 + 16#f
t.to_base(8)
z=?
a=2
x=3
ip.bit_representation()
ip=ip+20
ip.bit_representation()
ip.mask()
ip.get_prefix_length()
IP4(10.1.1.2)
a = b + 5
solve(x)

View File

@ -1,6 +1,6 @@
{
"window_geometry": "1020x700+356+1216",
"sash_pos_x": 359,
"sash_pos_x": 327,
"symbolic_mode": true,
"show_numeric_approximation": true,
"keep_symbolic_fractions": true,

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python3
"""
Motor de Evaluación Algebraico Puro para Calculadora MAV
ARQUITECTURA SIMPLIFICADA: Todas las líneas con = son ecuaciones
VERSIÓN UNIFICADA: Un solo parser (sympify) con contexto completo
"""
import re
import sympy as sp
@ -16,7 +16,11 @@ try:
except ImportError:
HAS_SYMPY_HELPER = False
from type_registry import get_registered_base_context, get_registered_tokenization_patterns, discover_and_register_types
from type_registry import (
get_registered_base_context,
get_registered_tokenization_patterns,
discover_and_register_types
)
from tl_bracket_parser import BracketParser
@ -33,21 +37,22 @@ class EvaluationResult:
class PureAlgebraicEngine:
"""Motor algebraico puro - Todas las asignaciones son ecuaciones"""
"""Motor algebraico puro unificado - Un solo parser sympify"""
def __init__(self):
self.logger = logging.getLogger(__name__)
self.equations = [] # Lista de ecuaciones Eq()
self.variables = set() # Variables conocidas
self.context = {} # Contexto de evaluación
self.symbol_table = {} # Variables del usuario
self.unified_context = {} # Contexto unificado para sympify
self.bracket_parser = BracketParser()
self.tokenization_patterns = [] # Patrones de tokenización
# Cargar tipos personalizados PRIMERO
self._load_custom_types()
# Cargar contexto base
self._load_base_context()
# Construir contexto unificado
self._build_unified_context()
self._load_tokenization_patterns()
def _load_custom_types(self):
@ -58,64 +63,69 @@ class PureAlgebraicEngine:
except Exception as e:
self.logger.error(f"Error cargando tipos personalizados: {e}")
def _load_base_context(self):
"""Carga el contexto base con funciones y tipos"""
def _build_unified_context(self):
"""Construye contexto unificado para sympify con TODOS los componentes"""
# 1. FUNCIONES SYMPY BÁSICAS
sympy_functions = {
'sin': sp.sin, 'cos': sp.cos, 'tan': sp.tan,
'asin': sp.asin, 'acos': sp.acos, 'atan': sp.atan,
'sinh': sp.sinh, 'cosh': sp.cosh, 'tanh': sp.tanh,
'log': sp.log, 'ln': sp.ln, 'exp': sp.exp,
'sqrt': sp.sqrt, 'abs': sp.Abs,
'pi': sp.pi, 'e': sp.E, 'I': sp.I,
'oo': sp.oo, 'inf': sp.oo,
'solve': self._smart_solve,
'Eq': sp.Eq, 'simplify': sp.simplify,
'expand': sp.expand, 'factor': sp.factor,
'diff': sp.diff, 'integrate': sp.integrate,
'Matrix': sp.Matrix, 'symbols': sp.symbols,
'Symbol': sp.Symbol, 'Rational': sp.Rational,
'Float': sp.Float, 'Integer': sp.Integer,
'limit': sp.limit, 'series': sp.series,
'summation': sp.summation, 'product': sp.product,
'binomial': sp.binomial, 'factorial': sp.factorial,
'gcd': sp.gcd, 'lcm': sp.lcm,
'ceiling': sp.ceiling, 'floor': sp.floor,
'Piecewise': sp.Piecewise,
}
# 2. TIPOS PERSONALIZADOS REGISTRADOS (CLAVE PARA INSTANCIACIÓN)
registered_types = get_registered_base_context()
# 3. FUNCIONES DE PLOTTING
try:
# Contexto de SymPy básico
self.context.update({
'sin': sp.sin, 'cos': sp.cos, 'tan': sp.tan,
'asin': sp.asin, 'acos': sp.acos, 'atan': sp.atan,
'sinh': sp.sinh, 'cosh': sp.cosh, 'tanh': sp.tanh,
'log': sp.log, 'ln': sp.ln, 'exp': sp.exp,
'sqrt': sp.sqrt, 'abs': sp.Abs,
'pi': sp.pi, 'e': sp.E, 'I': sp.I,
'oo': sp.oo, 'inf': sp.oo,
'solve': self._smart_solve, # Usar nuestro solve inteligente
'Eq': sp.Eq, 'simplify': sp.simplify,
'expand': sp.expand, 'factor': sp.factor,
'diff': sp.diff, 'integrate': sp.integrate,
'Matrix': sp.Matrix, 'symbols': sp.symbols,
'Symbol': sp.Symbol, 'Rational': sp.Rational,
'Float': sp.Float, 'Integer': sp.Integer,
'limit': sp.limit, 'series': sp.series,
'summation': sp.summation, 'product': sp.product,
'binomial': sp.binomial, 'factorial': sp.factorial,
'gcd': sp.gcd, 'lcm': sp.lcm,
'ceiling': sp.ceiling, 'floor': sp.floor,
'Piecewise': sp.Piecewise,
})
# Funciones de plotting
try:
from sympy.plotting import plot, plot3d, plot_parametric, plot3d_parametric_line
self.context.update({
'plot': plot,
'plot3d': plot3d,
'plot_parametric': plot_parametric,
'plot3d_parametric_line': plot3d_parametric_line,
})
self.logger.debug("Funciones de plotting cargadas")
except Exception as e:
self.logger.warning(f"Error cargando funciones de plotting: {e}")
# Contexto dinámico de tipos personalizados
dynamic_context = get_registered_base_context()
self.context.update(dynamic_context)
# Verificar que las clases principales estén disponibles
required_classes = ['IP4', 'IP4Mask', 'FourBytes', 'IntBase', 'Hex', 'Bin', 'Dec', 'Chr', 'LaTeX']
missing_classes = []
for cls_name in required_classes:
if cls_name not in self.context:
missing_classes.append(cls_name)
if missing_classes:
self.logger.warning(f"Clases faltantes en contexto: {missing_classes}")
self.logger.debug(f"Contexto cargado: {len(self.context)} elementos")
from sympy.plotting import plot, plot3d, plot_parametric, plot3d_parametric_line
plotting_functions = {
'plot': plot,
'plot3d': plot3d,
'plot_parametric': plot_parametric,
'plot3d_parametric_line': plot3d_parametric_line,
}
except Exception as e:
self.logger.error(f"Error cargando contexto: {e}")
self.logger.warning(f"Error cargando funciones de plotting: {e}")
plotting_functions = {}
# 4. COMBINAR TODO EN CONTEXTO UNIFICADO
self.unified_context = {
**sympy_functions,
**registered_types, # IP4, FourBytes, IntBase, etc.
**plotting_functions
}
# 5. VERIFICAR CARGA DE TIPOS PRINCIPALES
required_classes = ['IP4', 'IP4Mask', 'FourBytes', 'IntBase', 'Hex', 'Bin', 'Dec', 'Chr', 'LaTeX']
missing_classes = [cls for cls in required_classes if cls not in self.unified_context]
if missing_classes:
self.logger.warning(f"Clases faltantes en contexto: {missing_classes}")
self.logger.debug(f"Contexto unificado construido: {len(self.unified_context)} elementos")
# Verificar que tipos principales tengan prioridad correcta para álgebra
for name, cls in registered_types.items():
if hasattr(cls, '_op_priority'):
self.logger.debug(f"{name} tiene prioridad: {cls._op_priority}")
def _load_tokenization_patterns(self):
"""Carga los patrones de tokenización dinámicos"""
@ -143,7 +153,6 @@ class PureAlgebraicEngine:
replacement_func = pattern_info['replacement']
try:
# Aplicar el patrón con su función de reemplazo
tokenized_line = re.sub(pattern, replacement_func, tokenized_line)
except Exception as e:
self.logger.debug(f"Error aplicando patrón {pattern}: {e}")
@ -154,17 +163,25 @@ class PureAlgebraicEngine:
return tokenized_line
def _get_complete_context(self) -> Dict[str, Any]:
"""Obtiene contexto completo incluyendo variables del usuario"""
complete_context = self.unified_context.copy()
complete_context.update(self.symbol_table)
return complete_context
def evaluate_line(self, line: str) -> EvaluationResult:
"""Evalúa una línea de entrada"""
"""Evalúa una línea de entrada usando sympify unificado"""
line = line.strip()
if not line or line.startswith('#'):
return EvaluationResult(line, "", "comment", True)
try:
# 1. Aplicar tokenización dinámica PRIMERO
# 1. Aplicar tokenización dinámica
tokenized_line = self._apply_tokenization(line)
# 2. Preprocesar con bracket parser
# Tokenización aplicada silenciosamente
# 2. Preprocesar con bracket parser (legacy)
processed_line = self.bracket_parser.process_expression(tokenized_line)
self.logger.debug(f"Línea procesada: {processed_line}")
@ -172,7 +189,12 @@ class PureAlgebraicEngine:
if self._is_solve_shortcut(processed_line):
return self._evaluate_solve_shortcut(processed_line)
elif '=' in processed_line and not self._is_comparison(processed_line):
return self._evaluate_equation(processed_line)
# Verificar si es una asignación simple (lado izquierdo es variable)
left_side = processed_line.split('=')[0].strip()
if re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', left_side):
return self._evaluate_assignment(processed_line)
else:
return self._evaluate_equation(processed_line)
else:
return self._evaluate_expression(processed_line)
@ -200,18 +222,18 @@ class PureAlgebraicEngine:
solution = self._solve_for_variable(var_symbol)
# Output conciso
if solution != var_symbol: # Si hay solución real
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) # Variable sin resolver
output = str(var_symbol)
return EvaluationResult(line, output, "symbolic", True, is_solve_query=True)
elif line.startswith('solve('):
# Función solve()
# Función solve() - usar sympify unificado
result = self._evaluate_expression(line)
result.is_solve_query = True
return result
@ -220,6 +242,44 @@ class PureAlgebraicEngine:
error_msg = f"Error en resolución: {str(e)}"
return EvaluationResult(line, error_msg, "error", False, str(e))
def _evaluate_assignment(self, line: str) -> EvaluationResult:
"""Evalúa una asignación manteniendo doble registro"""
try:
# Separar variable = expresión
var_name, expr_str = line.split('=', 1)
var_name = var_name.strip()
expr_str = expr_str.strip()
# Evaluar la expresión del lado derecho
context = self._get_complete_context()
result = sympify(expr_str, locals=context)
# 1. ASIGNACIÓN DIRECTA (para uso inmediato)
self.symbol_table[var_name] = result
# Variable asignada correctamente
# 2. ECUACIÓN IMPLÍCITA (para solve)
var_symbol = sp.Symbol(var_name)
equation = Eq(var_symbol, result)
self.equations.append(equation)
# Añadir símbolo a variables conocidas
self.variables.add(var_symbol)
# Output conciso - mostrar el valor asignado
output = str(result)
# Añadir aproximación numérica si es útil
numeric = self._get_numeric_approximation(result)
if numeric and str(result) != str(numeric):
output += f"{numeric}"
return EvaluationResult(line, output, "assignment", True)
except Exception as e:
error_msg = f"Error en asignación: {str(e)}"
return EvaluationResult(line, error_msg, "error", False, str(e))
def _evaluate_equation(self, line: str) -> EvaluationResult:
"""Evalúa una ecuación y la añade al sistema"""
try:
@ -228,9 +288,10 @@ class PureAlgebraicEngine:
left_str = left_str.strip()
right_str = right_str.strip()
# Convertir a expresiones SymPy
left_expr = sympify(left_str, locals=self.context)
right_expr = sympify(right_str, locals=self.context)
# USAR SYMPIFY UNIFICADO para ambos lados
context = self._get_complete_context()
left_expr = sympify(left_str, locals=context)
right_expr = sympify(right_str, locals=context)
# Crear ecuación
equation = Eq(left_expr, right_expr)
@ -242,10 +303,10 @@ class PureAlgebraicEngine:
eq_vars = equation.free_symbols
self.variables.update(eq_vars)
# Output conciso de una línea
# Output conciso
output = str(equation)
# Evaluación numérica si es posible (solo para lado derecho)
# Evaluación numérica si es posible
numeric = self._get_numeric_approximation(equation.rhs)
if numeric and str(equation.rhs) != str(numeric):
output += f"{numeric}"
@ -257,15 +318,17 @@ class PureAlgebraicEngine:
return EvaluationResult(line, error_msg, "error", False, str(e))
def _evaluate_expression(self, line: str) -> EvaluationResult:
"""Evalúa una expresión libre"""
"""Evalúa una expresión usando sympify unificado ÚNICAMENTE"""
try:
# Evaluar con SymPy
expr = sympify(line, locals=self.context)
# USAR SYMPIFY UNIFICADO - Un solo parser
context = self._get_complete_context()
result = sympify(line, locals=context)
# Evaluar la expresión
result = expr
if hasattr(expr, 'evalf'): # Es expresión SymPy, simplificar
result = simplify(expr)
# Nota: Las asignaciones ahora se manejan en _evaluate_assignment
# Simplificar si es expresión SymPy
if hasattr(result, 'simplify'):
result = simplify(result)
output = str(result)
@ -288,7 +351,6 @@ class PureAlgebraicEngine:
return "No hay ecuaciones en el sistema"
try:
# Resolver usando todas las ecuaciones
all_vars = list(self.variables)
solution = solve(self.equations, all_vars, dict=True)
@ -339,7 +401,7 @@ class PureAlgebraicEngine:
if hasattr(numeric_val, 'is_real') and numeric_val.is_real:
try:
float_val = float(numeric_val)
if abs(float_val) > 1e-10: # Evitar números muy pequeños
if abs(float_val) > 1e-10:
return f"{float_val:.6f}".rstrip('0').rstrip('.')
except:
pass
@ -353,6 +415,7 @@ class PureAlgebraicEngine:
"""Limpia el contexto de evaluación pero mantiene los tipos base"""
self.equations.clear()
self.variables.clear()
self.symbol_table.clear()
self.logger.info("Contexto limpio")
def get_context_info(self) -> Dict[str, Any]:
@ -360,26 +423,20 @@ class PureAlgebraicEngine:
return {
"equations": len(self.equations),
"variables": list(self.variables),
"context_size": len(self.context),
"symbol_table": len(self.symbol_table),
"context_size": len(self.unified_context),
"tokenization_patterns": len(self.tokenization_patterns),
"recent_equations": [str(eq) for eq in self.equations[-5:]] # Últimas 5
"recent_equations": [str(eq) for eq in self.equations[-5:]]
}
def _get_full_context(self) -> Dict[str, Any]:
"""Obtiene el contexto completo para autocompletado (compatibilidad)"""
# Este método es necesario para el autocompletado en la GUI
full_context = self.context.copy()
# Añadir variables actuales
for var in self.variables:
full_context[str(var)] = var
return full_context
return self._get_complete_context()
def get_available_types(self) -> List[str]:
"""Obtiene tipos disponibles (compatibilidad)"""
available_types = []
for name, obj in self.context.items():
for name, obj in self.unified_context.items():
if hasattr(obj, '__class__') and hasattr(obj.__class__, '__name__'):
if obj.__class__.__name__ not in ['function', 'builtin_function_or_method']:
available_types.append(name)
@ -387,7 +444,8 @@ class PureAlgebraicEngine:
def reload_types(self):
"""Recarga los tipos dinámicos (compatibilidad)"""
self._load_base_context()
self._load_custom_types()
self._build_unified_context()
self._load_tokenization_patterns()
self.logger.info("Tipos y patrones recargados")
@ -405,24 +463,32 @@ def evaluate_line(line: str, engine: PureAlgebraicEngine = None) -> EvaluationRe
# ========== EJEMPLO DE USO ==========
if __name__ == "__main__":
# Demo del motor puro
# Demo del motor unificado
engine = PureAlgebraicEngine()
test_lines = [
"x = 5",
"y = x + 3",
"z = y + x",
"x=?",
"solve()",
"10.1.1.1", # Debería tokenizarse a FourBytes
"16#FF", # Debería tokenizarse a IntBase
"2#1010" # Debería tokenizarse a IntBase
"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 PURO ===")
print("=== DEMO MOTOR ALGEBRAICO UNIFICADO ===")
print(f"Tipos personalizados cargados: {len([k for k in engine.unified_context.keys() if k in ['IP4', 'FourBytes', 'IntBase']])}")
print(f"Patrones de tokenización: {len(engine.tokenization_patterns)}")
print()
for line in test_lines:
result = engine.evaluate_line(line)
status = "" if result.success else ""
print(f"{status} {line}{result.output}")
print(f"\nContexto: {engine.get_context_info()}")
print(f"\nContexto: {engine.get_context_info()}")

View File

@ -1,84 +0,0 @@
{
"queries": [
{
"index": 0,
"type": "exec",
"content": "import sympy"
},
{
"index": 1,
"type": "exec",
"content": "from sympy import symbols, Eq, solve"
},
{
"index": 2,
"type": "exec",
"content": "x, y, z = symbols('x y z')"
},
{
"index": 3,
"type": "exec",
"content": "# Sistema puramente algebraico"
},
{
"index": 4,
"type": "exec",
"content": "eq1 = Eq(x, 5)"
},
{
"index": 5,
"type": "exec",
"content": "eq2 = Eq(y, x + 3)"
},
{
"index": 6,
"type": "exec",
"content": "eq3 = Eq(z, x + y)"
},
{
"index": 7,
"type": "exec",
"content": "sistema = [eq1, eq2, eq3]"
},
{
"index": 8,
"type": "exec",
"content": "solve(sistema)"
},
{
"index": 9,
"type": "exec",
"content": "# Test más complejo"
},
{
"index": 10,
"type": "exec",
"content": "m, t, u = symbols('m t u')"
},
{
"index": 11,
"type": "exec",
"content": "eq4 = Eq(m, t + u * 5)"
},
{
"index": 12,
"type": "exec",
"content": "eq5 = Eq(t, 4)"
},
{
"index": 13,
"type": "exec",
"content": "eq6 = Eq(m, 3)"
},
{
"index": 14,
"type": "exec",
"content": "sistema2 = [eq4, eq5, eq6]"
},
{
"index": 15,
"type": "exec",
"content": "solve(sistema2)"
}
]
}

View File

@ -1,139 +0,0 @@
{
"execution_info": {
"timestamp": "2025-06-05T22:55:36.685672Z",
"total_queries": 16,
"successful": 0,
"failed": 16,
"input_file": "test_ecuaciones_puras.json"
},
"results": [
{
"index": 0,
"input": "import sympy",
"output": null,
"result_type": null,
"success": false,
"error": "invalid syntax (<string>, line 1)"
},
{
"index": 1,
"input": "from sympy import symbols, Eq, solve",
"output": null,
"result_type": null,
"success": false,
"error": "invalid syntax (<string>, line 1)"
},
{
"index": 2,
"input": "x, y, z = symbols('x y z')",
"output": null,
"result_type": null,
"success": false,
"error": "invalid syntax (<string>, line 1)"
},
{
"index": 3,
"input": "# Sistema puramente algebraico",
"output": null,
"result_type": null,
"success": false,
"error": "invalid syntax (<string>, line 1)"
},
{
"index": 4,
"input": "eq1 = Eq(x, 5)",
"output": null,
"result_type": null,
"success": false,
"error": "invalid syntax (<string>, line 1)"
},
{
"index": 5,
"input": "eq2 = Eq(y, x + 3)",
"output": null,
"result_type": null,
"success": false,
"error": "invalid syntax (<string>, line 1)"
},
{
"index": 6,
"input": "eq3 = Eq(z, x + y)",
"output": null,
"result_type": null,
"success": false,
"error": "invalid syntax (<string>, line 1)"
},
{
"index": 7,
"input": "sistema = [eq1, eq2, eq3]",
"output": null,
"result_type": null,
"success": false,
"error": "invalid syntax (<string>, line 1)"
},
{
"index": 8,
"input": "solve(sistema)",
"output": null,
"result_type": null,
"success": false,
"error": "name 'solve' is not defined"
},
{
"index": 9,
"input": "# Test más complejo",
"output": null,
"result_type": null,
"success": false,
"error": "invalid syntax (<string>, line 1)"
},
{
"index": 10,
"input": "m, t, u = symbols('m t u')",
"output": null,
"result_type": null,
"success": false,
"error": "invalid syntax (<string>, line 1)"
},
{
"index": 11,
"input": "eq4 = Eq(m, t + u * 5)",
"output": null,
"result_type": null,
"success": false,
"error": "invalid syntax (<string>, line 1)"
},
{
"index": 12,
"input": "eq5 = Eq(t, 4)",
"output": null,
"result_type": null,
"success": false,
"error": "invalid syntax (<string>, line 1)"
},
{
"index": 13,
"input": "eq6 = Eq(m, 3)",
"output": null,
"result_type": null,
"success": false,
"error": "invalid syntax (<string>, line 1)"
},
{
"index": 14,
"input": "sistema2 = [eq4, eq5, eq6]",
"output": null,
"result_type": null,
"success": false,
"error": "invalid syntax (<string>, line 1)"
},
{
"index": 15,
"input": "solve(sistema2)",
"output": null,
"result_type": null,
"success": false,
"error": "name 'solve' is not defined"
}
]
}

View File

@ -1,80 +0,0 @@
{
"engine_module": "main_evaluation_puro",
"queries": [
{
"index": 0,
"type": "exec",
"content": "x = 5"
},
{
"index": 1,
"type": "exec",
"content": "y = x + 3"
},
{
"index": 2,
"type": "exec",
"content": "z = x + y"
},
{
"index": 3,
"type": "exec",
"content": "x=?"
},
{
"index": 4,
"type": "exec",
"content": "y=?"
},
{
"index": 5,
"type": "exec",
"content": "z=?"
},
{
"index": 6,
"type": "exec",
"content": "solve(x)"
},
{
"index": 7,
"type": "exec",
"content": "solve(y)"
},
{
"index": 8,
"type": "exec",
"content": "2 + 3"
},
{
"index": 9,
"type": "exec",
"content": "sin(pi/2)"
},
{
"index": 10,
"type": "exec",
"content": "16#FF + 10"
},
{
"index": 11,
"type": "exec",
"content": "a = b + 5"
},
{
"index": 12,
"type": "exec",
"content": "b = 3"
},
{
"index": 13,
"type": "exec",
"content": "a=?"
},
{
"index": 14,
"type": "exec",
"content": "4/5"
}
]
}

View File

@ -1,131 +0,0 @@
{
"execution_info": {
"timestamp": "2025-06-05T23:11:43.398040Z",
"total_queries": 15,
"successful": 15,
"failed": 0,
"input_file": "test_motor_puro.json"
},
"results": [
{
"index": 0,
"input": "x = 5",
"output": "Eq(x, 5)",
"result_type": "equation",
"success": true,
"error": null
},
{
"index": 1,
"input": "y = x + 3",
"output": "Eq(y, x + 3)",
"result_type": "equation",
"success": true,
"error": null
},
{
"index": 2,
"input": "z = x + y",
"output": "Eq(z, x + y)",
"result_type": "equation",
"success": true,
"error": null
},
{
"index": 3,
"input": "x=?",
"output": "x",
"result_type": "symbolic",
"success": true,
"error": null
},
{
"index": 4,
"input": "y=?",
"output": "y",
"result_type": "symbolic",
"success": true,
"error": null
},
{
"index": 5,
"input": "z=?",
"output": "x + y",
"result_type": "symbolic",
"success": true,
"error": null
},
{
"index": 6,
"input": "solve(x)",
"output": "[]",
"result_type": "symbolic",
"success": true,
"error": null
},
{
"index": 7,
"input": "solve(y)",
"output": "[]",
"result_type": "symbolic",
"success": true,
"error": null
},
{
"index": 8,
"input": "2 + 3",
"output": "5",
"result_type": "symbolic",
"success": true,
"error": null
},
{
"index": 9,
"input": "sin(pi/2)",
"output": "1",
"result_type": "symbolic",
"success": true,
"error": null
},
{
"index": 10,
"input": "16#FF + 10",
"output": "16",
"result_type": "symbolic",
"success": true,
"error": null
},
{
"index": 11,
"input": "a = b + 5",
"output": "Eq(a, b + 5)",
"result_type": "equation",
"success": true,
"error": null
},
{
"index": 12,
"input": "b = 3",
"output": "Eq(b, 3)",
"result_type": "equation",
"success": true,
"error": null
},
{
"index": 13,
"input": "a=?",
"output": "b + 5",
"result_type": "symbolic",
"success": true,
"error": null
},
{
"index": 14,
"input": "4/5",
"output": "4/5 ≈ 0.800000",
"result_type": "symbolic",
"success": true,
"error": null
}
]
}

View File

@ -1,72 +0,0 @@
#!/usr/bin/env python3
from sympy import symbols, Eq, solve, pprint
print("🧪 Probando Sistema de Ecuaciones Puras con SymPy")
print("=" * 50)
# Test 1: Sistema simple
print("\n📌 Test 1: Sistema simple")
x, y, z = symbols('x y z')
eq1 = Eq(x, 5)
eq2 = Eq(y, x + 3)
eq3 = Eq(z, x + y)
sistema1 = [eq1, eq2, eq3]
print("Sistema:")
for i, eq in enumerate(sistema1, 1):
print(f" eq{i}: {eq}")
result1 = solve(sistema1)
print(f"Solución: {result1}")
# Test 2: Sistema más complejo
print("\n📌 Test 2: Sistema con conflicto")
m, t, u = symbols('m t u')
eq4 = Eq(m, t + u * 5)
eq5 = Eq(t, 4)
eq6 = Eq(m, 3)
sistema2 = [eq4, eq5, eq6]
print("Sistema:")
for i, eq in enumerate(sistema2, 1):
print(f" eq{i}: {eq}")
result2 = solve(sistema2)
print(f"Solución: {result2}")
# Test 3: Sistema inconsistente
print("\n📌 Test 3: Sistema inconsistente")
a, b = symbols('a b')
eq7 = Eq(a, 5)
eq8 = Eq(a, 10)
sistema3 = [eq7, eq8]
print("Sistema:")
for i, eq in enumerate(sistema3, 1):
print(f" eq{i}: {eq}")
result3 = solve(sistema3)
print(f"Solución: {result3}")
# Test 4: Variables libres
print("\n📌 Test 4: Variables libres")
p, q, r = symbols('p q r')
eq9 = Eq(p, q + 2)
eq10 = Eq(r, p * 3)
sistema4 = [eq9, eq10]
print("Sistema:")
for i, eq in enumerate(sistema4, 1):
print(f" eq{i}: {eq}")
result4 = solve(sistema4)
print(f"Solución: {result4}")
# Test 5: Evaluación numérica automática
print("\n📌 Test 5: Evaluación numérica")
if result2:
print("Evaluación numérica automática:")
for var, val in result2.items():
print(f" {var} = {val}{val.evalf()}")
print("\n✅ Conclusión: SymPy maneja perfectamente sistemas de ecuaciones puras!")