This commit is contained in:
2025-07-20 04:04:41 -04:00
commit 89909d5b20
27 changed files with 11534 additions and 0 deletions

306
explorer/README.md Normal file
View File

@@ -0,0 +1,306 @@
# Visual SpaceTime Explorer
Interactive visualization tool for understanding and exploring space-time tradeoffs in algorithms and systems.
## Features
- **Interactive Plots**: Pan, zoom, and explore tradeoff curves in real-time
- **Live Parameter Updates**: See immediate impact of changing data sizes and strategies
- **Multiple Visualizations**: Memory hierarchy, checkpoint intervals, cost analysis, 3D views
- **Educational Mode**: Learn theoretical concepts through visual demonstrations
- **Export Capabilities**: Save analyses and plots for presentations or reports
## Installation
```bash
# From sqrtspace-tools root directory
pip install matplotlib numpy
# For full features including animations
pip install matplotlib numpy scipy
```
## Quick Start
```python
from explorer import SpaceTimeVisualizer
# Launch interactive explorer
visualizer = SpaceTimeVisualizer()
visualizer.create_main_window()
# The explorer will open with:
# - Main tradeoff curves
# - Memory hierarchy view
# - Checkpoint visualization
# - Cost analysis
# - Performance metrics
# - 3D space-time-cost plot
```
## Interactive Controls
### Sliders
- **Data Size**: Adjust n from 100 to 1 billion (log scale)
- See how different algorithms scale with data size
### Radio Buttons
- **Strategy**: Choose between sqrt_n, linear, log_n, constant
- **View**: Switch between tradeoff, animated, comparison views
### Mouse Controls
- **Pan**: Click and drag on plots
- **Zoom**: Scroll wheel or right-click drag
- **Reset**: Double-click to reset view
### Export Button
- Save current analysis as JSON
- Export plots as high-resolution PNG
## Visualization Types
### 1. Main Tradeoff Curves
Shows theoretical and practical space-time tradeoffs:
```python
# The main plot displays:
- O(n) space algorithms (standard)
- O(n) space algorithms (Williams' bound)
- O(log n) space algorithms (compressed)
- O(1) space algorithms (streaming)
- Feasible region (gray shaded area)
- Current configuration (red dot)
```
### 2. Memory Hierarchy View
Visualizes data distribution across cache levels:
```python
# Shows how data is placed in:
- L1 Cache (32KB, 1ns)
- L2 Cache (256KB, 3ns)
- L3 Cache (8MB, 12ns)
- RAM (32GB, 100ns)
- SSD (512GB, 10μs)
```
### 3. Checkpoint Intervals
Compares different checkpointing strategies:
```python
# Strategies visualized:
- No checkpointing (full memory)
- n intervals (optimal)
- Fixed intervals (e.g., every 1000)
- Exponential intervals (doubling)
```
### 4. Cost Analysis
Breaks down costs by component:
```python
# Cost factors:
- Memory cost (cloud storage)
- Time cost (compute hours)
- Total cost (combined)
- Comparison across strategies
```
### 5. Performance Metrics
Radar chart showing multiple dimensions:
```python
# Metrics evaluated:
- Memory Efficiency (0-100%)
- Speed (0-100%)
- Fault Tolerance (0-100%)
- Scalability (0-100%)
- Cost Efficiency (0-100%)
```
### 6. 3D Visualization
Three-dimensional view of space-time-cost:
```python
# Axes:
- X: log₁₀(Space)
- Y: log₁₀(Time)
- Z: log₁₀(Cost)
# Shows tradeoff surfaces for different strategies
```
## Example Visualizations
Run comprehensive examples:
```bash
python example_visualizations.py
```
This creates four sets of visualizations:
### 1. Algorithm Comparison
- Sorting algorithms (QuickSort vs MergeSort vs External Sort)
- Search structures (Array vs BST vs Hash vs B-tree)
- Matrix multiplication strategies
- Graph algorithms with memory constraints
### 2. Real-World Systems
- Database buffer pool strategies
- LLM inference with KV-cache optimization
- MapReduce shuffle strategies
- Mobile app memory management
### 3. Optimization Impact
- Memory reduction factors (10x to 1,000,000x)
- Time overhead analysis
- Cloud cost analysis
- Breakeven calculations
### 4. Educational Diagrams
- Williams' space-time bound
- Memory hierarchy and latencies
- Checkpoint strategy comparison
- Cache line utilization
- Algorithm selection guide
- Cost-benefit spider charts
## Use Cases
### 1. Algorithm Design
```python
# Compare different algorithm implementations
visualizer.current_n = 10**6 # 1 million elements
visualizer.update_all_plots()
# See which strategy is optimal for your data size
```
### 2. System Tuning
```python
# Analyze memory hierarchy impact
# Adjust parameters to match your system
hierarchy = MemoryHierarchy.detect_system()
visualizer.hierarchy = hierarchy
```
### 3. Education
```python
# Create educational visualizations
from example_visualizations import create_educational_diagrams
create_educational_diagrams()
# Perfect for teaching space-time tradeoffs
```
### 4. Research
```python
# Export data for analysis
visualizer._export_data(None)
# Creates JSON with all metrics and parameters
# Saves high-resolution plots
```
## Advanced Features
### Custom Strategies
Add your own algorithms:
```python
class CustomVisualizer(SpaceTimeVisualizer):
def _get_strategy_metrics(self, n, strategy):
if strategy == 'my_algorithm':
space = n ** 0.7 # Custom space complexity
time = n * np.log(n) ** 2 # Custom time
cost = space * 0.1 + time * 0.01
return space, time, cost
return super()._get_strategy_metrics(n, strategy)
```
### Animation Mode
View algorithms in action:
```python
# Launch animated view
visualizer.create_animated_view()
# Shows:
# - Processing progress
# - Checkpoint creation
# - Memory usage over time
```
### Comparison Mode
Side-by-side strategy comparison:
```python
# Launch comparison view
visualizer.create_comparison_view()
# Creates 2x2 grid comparing all strategies
```
## Understanding the Visualizations
### Space-Time Curves
- **Lower-left**: Better (less space, less time)
- **Upper-right**: Worse (more space, more time)
- **Gray region**: Theoretically impossible
- **Green region**: Feasible implementations
### Memory Distribution
- **Darker colors**: Faster memory (L1, L2)
- **Lighter colors**: Slower memory (RAM, SSD)
- **Bar width**: Amount of data in that level
- **Numbers**: Access latency in nanoseconds
### Checkpoint Timeline
- **Blocks**: Work between checkpoints
- **Width**: Amount of progress
- **Gaps**: Checkpoint operations
- **Colors**: Different strategies
### Cost Analysis
- **Log scale**: Costs vary by orders of magnitude
- **Red outline**: Currently selected strategy
- **Bar height**: Relative cost (lower is better)
## Tips for Best Results
1. **Start with your actual data size**: Use the slider to match your workload
2. **Consider all metrics**: Don't optimize for memory alone - check time and cost
3. **Test edge cases**: Try very small and very large data sizes
4. **Export findings**: Save configurations that work well
5. **Compare strategies**: Use the comparison view for thorough analysis
## Interpreting Results
### When to use O(√n) strategies:
- Data size >> available memory
- Memory is expensive (cloud/embedded)
- Can tolerate 10-50% time overhead
- Need fault tolerance
### When to avoid:
- Data fits in memory
- Latency critical (< 10ms)
- Simple algorithms sufficient
- Overhead not justified
## Future Enhancements
- Real-time profiling integration
- Custom algorithm import
- Collaborative sharing
- AR/VR visualization
- Machine learning predictions
## See Also
- [SpaceTimeCore](../core/spacetime_core.py): Core calculations
- [Profiler](../profiler/): Profile your applications

View File

@@ -0,0 +1,643 @@
#!/usr/bin/env python3
"""
Example visualizations demonstrating SpaceTime Explorer capabilities
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from spacetime_explorer import SpaceTimeVisualizer
import matplotlib.pyplot as plt
import numpy as np
def visualize_algorithm_comparison():
"""Compare different algorithms visually"""
print("="*60)
print("Algorithm Comparison Visualization")
print("="*60)
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
fig.suptitle('Space-Time Tradeoffs: Algorithm Comparison', fontsize=16)
# Data range
n_values = np.logspace(2, 9, 100)
# 1. Sorting algorithms
ax = axes[0, 0]
ax.set_title('Sorting Algorithms')
# QuickSort (in-place)
ax.loglog(n_values * 0 + 1, n_values * np.log2(n_values),
label='QuickSort (O(1) space)', linewidth=2)
# MergeSort (standard)
ax.loglog(n_values, n_values * np.log2(n_values),
label='MergeSort (O(n) space)', linewidth=2)
# External MergeSort (√n buffers)
ax.loglog(np.sqrt(n_values), n_values * np.log2(n_values) * 2,
label='External Sort (O(√n) space)', linewidth=2)
ax.set_xlabel('Space Usage')
ax.set_ylabel('Time Complexity')
ax.legend()
ax.grid(True, alpha=0.3)
# 2. Search structures
ax = axes[0, 1]
ax.set_title('Search Data Structures')
# Array (unsorted)
ax.loglog(n_values, n_values,
label='Array Search (O(n) time)', linewidth=2)
# Binary Search Tree
ax.loglog(n_values, np.log2(n_values),
label='BST (O(log n) average)', linewidth=2)
# Hash Table
ax.loglog(n_values, n_values * 0 + 1,
label='Hash Table (O(1) average)', linewidth=2)
# B-tree (√n fanout)
ax.loglog(n_values, np.log(n_values) / np.log(np.sqrt(n_values)),
label='B-tree (O(log_√n n))', linewidth=2)
ax.set_xlabel('Space Usage')
ax.set_ylabel('Search Time')
ax.legend()
ax.grid(True, alpha=0.3)
# 3. Matrix operations
ax = axes[1, 0]
ax.set_title('Matrix Multiplication')
n_matrix = np.sqrt(n_values) # Matrix dimension
# Standard multiplication
ax.loglog(n_matrix**2, n_matrix**3,
label='Standard (O(n²) space)', linewidth=2)
# Strassen's algorithm
ax.loglog(n_matrix**2, n_matrix**2.807,
label='Strassen (O(n²) space)', linewidth=2)
# Block multiplication (√n blocks)
ax.loglog(n_matrix**1.5, n_matrix**3 * 1.2,
label='Blocked (O(n^1.5) space)', linewidth=2)
ax.set_xlabel('Space Usage')
ax.set_ylabel('Time Complexity')
ax.legend()
ax.grid(True, alpha=0.3)
# 4. Graph algorithms
ax = axes[1, 1]
ax.set_title('Graph Algorithms')
# BFS/DFS
ax.loglog(n_values, n_values + n_values,
label='BFS/DFS (O(V+E) space)', linewidth=2)
# Dijkstra
ax.loglog(n_values * np.log(n_values), n_values * np.log(n_values),
label='Dijkstra (O(V log V) space)', linewidth=2)
# A* with bounded memory
ax.loglog(np.sqrt(n_values), n_values * np.sqrt(n_values),
label='Memory-bounded A* (O(√V) space)', linewidth=2)
ax.set_xlabel('Space Usage')
ax.set_ylabel('Time Complexity')
ax.legend()
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
def visualize_real_world_systems():
"""Visualize real-world system tradeoffs"""
print("\n" + "="*60)
print("Real-World System Tradeoffs")
print("="*60)
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
fig.suptitle('Space-Time Tradeoffs in Production Systems', fontsize=16)
# 1. Database systems
ax = axes[0, 0]
ax.set_title('Database Buffer Pool Strategies')
data_sizes = np.logspace(6, 12, 50) # 1MB to 1TB
memory_sizes = [8e9, 32e9, 128e9] # 8GB, 32GB, 128GB RAM
for mem in memory_sizes:
# Full caching
full_cache_perf = np.minimum(data_sizes / mem, 1.0)
# √n caching
sqrt_cache_size = np.sqrt(data_sizes)
sqrt_cache_perf = np.minimum(sqrt_cache_size / mem, 1.0) * 0.9
ax.semilogx(data_sizes / 1e9, full_cache_perf,
label=f'Full cache ({mem/1e9:.0f}GB RAM)', linewidth=2)
ax.semilogx(data_sizes / 1e9, sqrt_cache_perf, '--',
label=f'√n cache ({mem/1e9:.0f}GB RAM)', linewidth=2)
ax.set_xlabel('Database Size (GB)')
ax.set_ylabel('Cache Hit Rate')
ax.legend()
ax.grid(True, alpha=0.3)
# 2. LLM inference
ax = axes[0, 1]
ax.set_title('LLM Inference: KV-Cache Strategies')
sequence_lengths = np.logspace(1, 5, 50) # 10 to 100K tokens
# Full KV-cache
full_memory = sequence_lengths * 2048 * 4 * 2 # seq * dim * float32 * KV
full_speed = sequence_lengths * 0 + 200 # tokens/sec
# Flash Attention (√n memory)
flash_memory = np.sqrt(sequence_lengths) * 2048 * 4 * 2
flash_speed = 180 - sequence_lengths / 1000 # Slight slowdown
# Paged Attention
paged_memory = sequence_lengths * 2048 * 4 * 2 * 0.1 # 10% of full
paged_speed = 150 - sequence_lengths / 500
ax2 = ax.twinx()
l1 = ax.loglog(sequence_lengths, full_memory / 1e9, 'b-',
label='Full KV-cache (memory)', linewidth=2)
l2 = ax.loglog(sequence_lengths, flash_memory / 1e9, 'r-',
label='Flash Attention (memory)', linewidth=2)
l3 = ax.loglog(sequence_lengths, paged_memory / 1e9, 'g-',
label='Paged Attention (memory)', linewidth=2)
l4 = ax2.semilogx(sequence_lengths, full_speed, 'b--',
label='Full KV-cache (speed)', linewidth=2)
l5 = ax2.semilogx(sequence_lengths, flash_speed, 'r--',
label='Flash Attention (speed)', linewidth=2)
l6 = ax2.semilogx(sequence_lengths, paged_speed, 'g--',
label='Paged Attention (speed)', linewidth=2)
ax.set_xlabel('Sequence Length (tokens)')
ax.set_ylabel('Memory Usage (GB)')
ax2.set_ylabel('Inference Speed (tokens/sec)')
# Combine legends
lns = l1 + l2 + l3 + l4 + l5 + l6
labs = [l.get_label() for l in lns]
ax.legend(lns, labs, loc='upper left')
ax.grid(True, alpha=0.3)
# 3. Distributed computing
ax = axes[1, 0]
ax.set_title('MapReduce Shuffle Strategies')
data_per_node = np.logspace(6, 11, 50) # 1MB to 100GB per node
num_nodes = 100
# All-to-all shuffle
all_to_all_mem = data_per_node * num_nodes
all_to_all_time = data_per_node * num_nodes / 1e9 # Network time
# Tree aggregation (√n levels)
tree_levels = int(np.sqrt(num_nodes))
tree_mem = data_per_node * tree_levels
tree_time = data_per_node * tree_levels / 1e9
# Combiner optimization
combiner_mem = data_per_node * np.log2(num_nodes)
combiner_time = data_per_node * np.log2(num_nodes) / 1e9
ax.loglog(all_to_all_mem / 1e9, all_to_all_time,
label='All-to-all shuffle', linewidth=2)
ax.loglog(tree_mem / 1e9, tree_time,
label='Tree aggregation (√n)', linewidth=2)
ax.loglog(combiner_mem / 1e9, combiner_time,
label='With combiners', linewidth=2)
ax.set_xlabel('Memory per Node (GB)')
ax.set_ylabel('Shuffle Time (seconds)')
ax.legend()
ax.grid(True, alpha=0.3)
# 4. Mobile/embedded systems
ax = axes[1, 1]
ax.set_title('Mobile App Memory Strategies')
image_counts = np.logspace(1, 4, 50) # 10 to 10K images
image_size = 2e6 # 2MB per image
# Full cache
full_cache = image_counts * image_size / 1e9
full_load_time = image_counts * 0 + 0.1 # Instant from cache
# LRU cache (√n size)
lru_cache = np.sqrt(image_counts) * image_size / 1e9
lru_load_time = 0.1 + (1 - np.sqrt(image_counts) / image_counts) * 2
# No cache
no_cache = image_counts * 0 + 0.01 # Minimal memory
no_load_time = image_counts * 0 + 2 # Always load from network
ax2 = ax.twinx()
l1 = ax.loglog(image_counts, full_cache, 'b-',
label='Full cache (memory)', linewidth=2)
l2 = ax.loglog(image_counts, lru_cache, 'r-',
label='√n LRU cache (memory)', linewidth=2)
l3 = ax.loglog(image_counts, no_cache, 'g-',
label='No cache (memory)', linewidth=2)
l4 = ax2.semilogx(image_counts, full_load_time, 'b--',
label='Full cache (load time)', linewidth=2)
l5 = ax2.semilogx(image_counts, lru_load_time, 'r--',
label='√n LRU cache (load time)', linewidth=2)
l6 = ax2.semilogx(image_counts, no_load_time, 'g--',
label='No cache (load time)', linewidth=2)
ax.set_xlabel('Number of Images')
ax.set_ylabel('Memory Usage (GB)')
ax2.set_ylabel('Average Load Time (seconds)')
# Combine legends
lns = l1 + l2 + l3 + l4 + l5 + l6
labs = [l.get_label() for l in lns]
ax.legend(lns, labs, loc='upper left')
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
def visualize_optimization_impact():
"""Show impact of √n optimizations"""
print("\n" + "="*60)
print("Impact of √n Optimizations")
print("="*60)
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
fig.suptitle('Memory Savings and Performance Impact', fontsize=16)
# Common data sizes
n_values = np.logspace(3, 12, 50)
# 1. Memory savings
ax = axes[0, 0]
ax.set_title('Memory Reduction Factor')
reduction_factor = n_values / np.sqrt(n_values)
ax.loglog(n_values, reduction_factor, 'b-', linewidth=3)
# Add markers for common sizes
common_sizes = [1e3, 1e6, 1e9, 1e12]
common_names = ['1K', '1M', '1B', '1T']
for size, name in zip(common_sizes, common_names):
factor = size / np.sqrt(size)
ax.scatter(size, factor, s=100, zorder=5)
ax.annotate(f'{name}: {factor:.0f}x',
xy=(size, factor),
xytext=(size*2, factor*1.5),
arrowprops=dict(arrowstyle='->', color='red'))
ax.set_xlabel('Data Size (n)')
ax.set_ylabel('Memory Reduction (n/√n)')
ax.grid(True, alpha=0.3)
# 2. Time overhead
ax = axes[0, 1]
ax.set_title('Time Overhead of √n Strategies')
# Different overhead scenarios
low_overhead = np.ones_like(n_values) * 1.1 # 10% overhead
medium_overhead = 1 + np.log10(n_values) / 10 # Logarithmic growth
high_overhead = 1 + np.sqrt(n_values) / n_values * 100 # Diminishing
ax.semilogx(n_values, low_overhead, label='Low overhead (10%)', linewidth=2)
ax.semilogx(n_values, medium_overhead, label='Medium overhead', linewidth=2)
ax.semilogx(n_values, high_overhead, label='High overhead', linewidth=2)
ax.axhline(y=2, color='red', linestyle='--', label='2x slowdown limit')
ax.set_xlabel('Data Size (n)')
ax.set_ylabel('Time Overhead Factor')
ax.legend()
ax.grid(True, alpha=0.3)
# 3. Cost efficiency
ax = axes[1, 0]
ax.set_title('Cloud Cost Analysis')
# Cost model: memory cost + compute cost
memory_cost_per_gb = 0.1 # $/GB/hour
compute_cost_per_cpu = 0.05 # $/CPU/hour
# Standard approach
standard_memory_cost = n_values / 1e9 * memory_cost_per_gb
standard_compute_cost = np.ones_like(n_values) * compute_cost_per_cpu
standard_total = standard_memory_cost + standard_compute_cost
# √n approach
sqrt_memory_cost = np.sqrt(n_values) / 1e9 * memory_cost_per_gb
sqrt_compute_cost = np.ones_like(n_values) * compute_cost_per_cpu * 1.2
sqrt_total = sqrt_memory_cost + sqrt_compute_cost
ax.loglog(n_values, standard_total, label='Standard (O(n) memory)', linewidth=2)
ax.loglog(n_values, sqrt_total, label='√n optimized', linewidth=2)
# Savings region
ax.fill_between(n_values, sqrt_total, standard_total,
where=(standard_total > sqrt_total),
alpha=0.3, color='green', label='Cost savings')
ax.set_xlabel('Data Size (bytes)')
ax.set_ylabel('Cost ($/hour)')
ax.legend()
ax.grid(True, alpha=0.3)
# 4. Breakeven analysis
ax = axes[1, 1]
ax.set_title('When to Use √n Optimizations')
# Create a heatmap showing when √n is beneficial
data_sizes = np.logspace(3, 9, 20)
memory_costs = np.logspace(-2, 2, 20)
benefit_matrix = np.zeros((len(memory_costs), len(data_sizes)))
for i, mem_cost in enumerate(memory_costs):
for j, data_size in enumerate(data_sizes):
# Simple model: benefit if memory savings > compute overhead
memory_saved = (data_size - np.sqrt(data_size)) / 1e9
benefit = memory_saved * mem_cost - 0.1 # 0.1 = overhead cost
benefit_matrix[i, j] = benefit > 0
im = ax.imshow(benefit_matrix, aspect='auto', origin='lower',
extent=[3, 9, -2, 2], cmap='RdYlGn')
ax.set_xlabel('log₁₀(Data Size)')
ax.set_ylabel('log₁₀(Memory Cost Ratio)')
ax.set_title('Green = Use √n, Red = Use Standard')
# Add contour line
contour = ax.contour(np.log10(data_sizes), np.log10(memory_costs),
benefit_matrix, levels=[0.5], colors='black', linewidths=2)
ax.clabel(contour, inline=True, fmt='Breakeven')
plt.colorbar(im, ax=ax)
plt.tight_layout()
plt.show()
def create_educational_diagrams():
"""Create educational diagrams explaining concepts"""
print("\n" + "="*60)
print("Educational Diagrams")
print("="*60)
# Create figure with subplots
fig = plt.figure(figsize=(16, 12))
# 1. Williams' theorem visualization
ax1 = plt.subplot(2, 3, 1)
ax1.set_title("Williams' Space-Time Bound", fontsize=14, fontweight='bold')
t_values = np.logspace(1, 6, 100)
s_bound = np.sqrt(t_values * np.log(t_values))
ax1.fill_between(t_values, 0, s_bound, alpha=0.3, color='red',
label='Impossible region')
ax1.fill_between(t_values, s_bound, t_values*10, alpha=0.3, color='green',
label='Feasible region')
ax1.loglog(t_values, s_bound, 'k-', linewidth=3,
label='S = √(t log t) bound')
# Add example algorithms
ax1.scatter([1000], [1000], s=100, color='blue', marker='o',
label='Standard algorithm')
ax1.scatter([1000], [31.6], s=100, color='orange', marker='s',
label='√n algorithm')
ax1.set_xlabel('Time (t)')
ax1.set_ylabel('Space (s)')
ax1.legend()
ax1.grid(True, alpha=0.3)
# 2. Memory hierarchy
ax2 = plt.subplot(2, 3, 2)
ax2.set_title('Memory Hierarchy & Access Times', fontsize=14, fontweight='bold')
levels = ['CPU\nRegisters', 'L1\nCache', 'L2\nCache', 'L3\nCache', 'RAM', 'SSD', 'HDD']
sizes = [1e-3, 32, 256, 8192, 32768, 512000, 2000000] # KB
latencies = [0.3, 1, 3, 12, 100, 10000, 10000000] # ns
y_pos = np.arange(len(levels))
# Create bars
bars = ax2.barh(y_pos, np.log10(sizes), color=plt.cm.viridis(np.linspace(0, 1, len(levels))))
# Add latency annotations
for i, (bar, latency) in enumerate(zip(bars, latencies)):
width = bar.get_width()
if latency < 1000:
lat_str = f'{latency:.1f}ns'
elif latency < 1000000:
lat_str = f'{latency/1000:.0f}μs'
else:
lat_str = f'{latency/1000000:.0f}ms'
ax2.text(width + 0.1, bar.get_y() + bar.get_height()/2,
lat_str, va='center')
ax2.set_yticks(y_pos)
ax2.set_yticklabels(levels)
ax2.set_xlabel('log₁₀(Size in KB)')
ax2.set_title('Memory Hierarchy & Access Times', fontsize=14, fontweight='bold')
ax2.grid(True, alpha=0.3, axis='x')
# 3. Checkpoint visualization
ax3 = plt.subplot(2, 3, 3)
ax3.set_title('Checkpoint Strategies', fontsize=14, fontweight='bold')
n = 100
progress = np.arange(n)
# No checkpointing
ax3.fill_between(progress, 0, progress, alpha=0.3, color='red',
label='No checkpoint')
# √n checkpointing
checkpoint_interval = int(np.sqrt(n))
sqrt_memory = np.zeros(n)
for i in range(n):
sqrt_memory[i] = i % checkpoint_interval
ax3.fill_between(progress, 0, sqrt_memory, alpha=0.3, color='green',
label='√n checkpoint')
# Fixed interval
fixed_interval = 20
fixed_memory = np.zeros(n)
for i in range(n):
fixed_memory[i] = i % fixed_interval
ax3.plot(progress, fixed_memory, 'b-', linewidth=2,
label=f'Fixed interval ({fixed_interval})')
# Add checkpoint markers
for i in range(0, n, checkpoint_interval):
ax3.axvline(x=i, color='green', linestyle='--', alpha=0.5)
ax3.set_xlabel('Progress')
ax3.set_ylabel('Memory Usage')
ax3.legend()
ax3.set_xlim(0, n)
ax3.grid(True, alpha=0.3)
# 4. Cache line utilization
ax4 = plt.subplot(2, 3, 4)
ax4.set_title('Cache Line Utilization', fontsize=14, fontweight='bold')
cache_line_size = 64 # bytes
# Poor alignment
poor_sizes = [7, 13, 17, 23] # bytes per element
poor_util = [cache_line_size // s * s / cache_line_size * 100 for s in poor_sizes]
# Good alignment
good_sizes = [8, 16, 32, 64] # bytes per element
good_util = [cache_line_size // s * s / cache_line_size * 100 for s in good_sizes]
x = np.arange(len(poor_sizes))
width = 0.35
bars1 = ax4.bar(x - width/2, poor_util, width, label='Poor alignment', color='red', alpha=0.7)
bars2 = ax4.bar(x + width/2, good_util, width, label='Good alignment', color='green', alpha=0.7)
# Add value labels
for bars in [bars1, bars2]:
for bar in bars:
height = bar.get_height()
ax4.text(bar.get_x() + bar.get_width()/2., height + 1,
f'{height:.0f}%', ha='center', va='bottom')
ax4.set_ylabel('Cache Line Utilization (%)')
ax4.set_xlabel('Element Size Configuration')
ax4.set_xticks(x)
ax4.set_xticklabels([f'{p}B vs {g}B' for p, g in zip(poor_sizes, good_sizes)])
ax4.legend()
ax4.set_ylim(0, 110)
ax4.grid(True, alpha=0.3, axis='y')
# 5. Algorithm selection guide
ax5 = plt.subplot(2, 3, 5)
ax5.set_title('Algorithm Selection Guide', fontsize=14, fontweight='bold')
# Create decision matrix
data_size_ranges = ['< 1KB', '1KB-1MB', '1MB-1GB', '> 1GB']
memory_constraints = ['Unlimited', 'Limited', 'Severe', 'Embedded']
recommendations = [
['Array', 'Array', 'Hash', 'B-tree'],
['Array', 'B-tree', 'B-tree', 'External'],
['Compressed', 'Compressed', '√n Cache', '√n External'],
['Minimal', 'Minimal', 'Streaming', 'Streaming']
]
# Create color map
colors = {'Array': 0, 'Hash': 1, 'B-tree': 2, 'External': 3,
'Compressed': 4, '√n Cache': 5, '√n External': 6,
'Minimal': 7, 'Streaming': 8}
matrix = np.zeros((len(memory_constraints), len(data_size_ranges)))
for i in range(len(memory_constraints)):
for j in range(len(data_size_ranges)):
matrix[i, j] = colors[recommendations[i][j]]
im = ax5.imshow(matrix, cmap='tab10', aspect='auto')
# Add text annotations
for i in range(len(memory_constraints)):
for j in range(len(data_size_ranges)):
ax5.text(j, i, recommendations[i][j],
ha='center', va='center', fontsize=10)
ax5.set_xticks(np.arange(len(data_size_ranges)))
ax5.set_yticks(np.arange(len(memory_constraints)))
ax5.set_xticklabels(data_size_ranges)
ax5.set_yticklabels(memory_constraints)
ax5.set_xlabel('Data Size')
ax5.set_ylabel('Memory Constraint')
# 6. Cost-benefit analysis
ax6 = plt.subplot(2, 3, 6)
ax6.set_title('Cost-Benefit Analysis', fontsize=14, fontweight='bold')
# Create spider chart
categories = ['Memory\nSavings', 'Speed', 'Complexity', 'Fault\nTolerance', 'Scalability']
# Different strategies
strategies = {
'Standard': [20, 100, 100, 30, 40],
'√n Optimized': [90, 70, 60, 80, 95],
'Extreme Memory': [98, 30, 20, 50, 80]
}
# Number of variables
num_vars = len(categories)
# Compute angle for each axis
angles = np.linspace(0, 2 * np.pi, num_vars, endpoint=False).tolist()
angles += angles[:1] # Complete the circle
ax6 = plt.subplot(2, 3, 6, projection='polar')
for name, values in strategies.items():
values += values[:1] # Complete the circle
ax6.plot(angles, values, 'o-', linewidth=2, label=name)
ax6.fill(angles, values, alpha=0.15)
ax6.set_xticks(angles[:-1])
ax6.set_xticklabels(categories)
ax6.set_ylim(0, 100)
ax6.set_title('Strategy Comparison', fontsize=14, fontweight='bold', pad=20)
ax6.legend(loc='upper right', bbox_to_anchor=(1.2, 1.1))
ax6.grid(True)
plt.tight_layout()
plt.show()
def main():
"""Run all example visualizations"""
print("SpaceTime Explorer - Example Visualizations")
print("="*60)
# Run each visualization
visualize_algorithm_comparison()
visualize_real_world_systems()
visualize_optimization_impact()
create_educational_diagrams()
print("\n" + "="*60)
print("Example visualizations complete!")
print("\nThese examples demonstrate:")
print("- Algorithm space-time tradeoffs")
print("- Real-world system optimizations")
print("- Impact of √n strategies")
print("- Educational diagrams for understanding concepts")
print("="*60)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,653 @@
#!/usr/bin/env python3
"""
Visual SpaceTime Explorer: Interactive visualization of space-time tradeoffs
Features:
- Interactive Plots: Pan, zoom, and explore tradeoff curves
- Live Updates: See impact of parameter changes in real-time
- Multiple Views: Memory hierarchy, checkpoint intervals, cache effects
- Export: Save visualizations and insights
- Educational: Understand theoretical bounds visually
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.widgets import Slider, Button, RadioButtons, TextBox
import matplotlib.patches as mpatches
from mpl_toolkits.mplot3d import Axes3D
import json
from datetime import datetime
from typing import Dict, List, Tuple, Optional, Any
import time
# Import core components
from core.spacetime_core import (
MemoryHierarchy,
SqrtNCalculator,
StrategyAnalyzer,
OptimizationStrategy
)
class SpaceTimeVisualizer:
"""Main visualization engine"""
def __init__(self):
self.sqrt_calc = SqrtNCalculator()
self.hierarchy = MemoryHierarchy.detect_system()
self.strategy_analyzer = StrategyAnalyzer(self.hierarchy)
# Plot settings
self.fig = None
self.axes = []
self.animations = []
# Data ranges
self.n_min = 100
self.n_max = 10**9
self.n_points = 100
# Current parameters
self.current_n = 10**6
self.current_strategy = 'sqrt_n'
self.current_view = 'tradeoff'
def create_main_window(self):
"""Create main visualization window"""
self.fig = plt.figure(figsize=(16, 10))
self.fig.suptitle('SpaceTime Explorer: Interactive Space-Time Tradeoff Visualization',
fontsize=16, fontweight='bold')
# Create subplots
gs = self.fig.add_gridspec(3, 3, hspace=0.3, wspace=0.3)
# Main tradeoff plot
self.ax_tradeoff = self.fig.add_subplot(gs[0:2, 0:2])
self.ax_tradeoff.set_title('Space-Time Tradeoff Curves')
# Memory hierarchy view
self.ax_hierarchy = self.fig.add_subplot(gs[0, 2])
self.ax_hierarchy.set_title('Memory Hierarchy')
# Checkpoint intervals
self.ax_checkpoint = self.fig.add_subplot(gs[1, 2])
self.ax_checkpoint.set_title('Checkpoint Intervals')
# Cost analysis
self.ax_cost = self.fig.add_subplot(gs[2, 0])
self.ax_cost.set_title('Cost Analysis')
# Performance metrics
self.ax_metrics = self.fig.add_subplot(gs[2, 1])
self.ax_metrics.set_title('Performance Metrics')
# 3D visualization
self.ax_3d = self.fig.add_subplot(gs[2, 2], projection='3d')
self.ax_3d.set_title('3D Space-Time-Cost')
# Add controls
self._add_controls()
# Initial plot
self.update_all_plots()
def _add_controls(self):
"""Add interactive controls"""
# Sliders
ax_n_slider = plt.axes([0.1, 0.02, 0.3, 0.02])
self.n_slider = Slider(ax_n_slider, 'Data Size (log10)',
np.log10(self.n_min), np.log10(self.n_max),
valinit=np.log10(self.current_n), valstep=0.1)
self.n_slider.on_changed(self._on_n_changed)
# Strategy selector
ax_strategy = plt.axes([0.5, 0.02, 0.15, 0.1])
self.strategy_radio = RadioButtons(ax_strategy,
['sqrt_n', 'linear', 'log_n', 'constant'],
active=0)
self.strategy_radio.on_clicked(self._on_strategy_changed)
# View selector
ax_view = plt.axes([0.7, 0.02, 0.15, 0.1])
self.view_radio = RadioButtons(ax_view,
['tradeoff', 'animated', 'comparison'],
active=0)
self.view_radio.on_clicked(self._on_view_changed)
# Export button
ax_export = plt.axes([0.88, 0.02, 0.1, 0.04])
self.export_btn = Button(ax_export, 'Export')
self.export_btn.on_clicked(self._export_data)
def update_all_plots(self):
"""Update all visualizations"""
self.plot_tradeoff_curves()
self.plot_memory_hierarchy()
self.plot_checkpoint_intervals()
self.plot_cost_analysis()
self.plot_performance_metrics()
self.plot_3d_visualization()
plt.draw()
def plot_tradeoff_curves(self):
"""Plot main space-time tradeoff curves"""
self.ax_tradeoff.clear()
# Generate data points
n_values = np.logspace(np.log10(self.n_min), np.log10(self.n_max), self.n_points)
# Theoretical bounds
time_linear = n_values
space_sqrt = np.sqrt(n_values * np.log(n_values))
# Practical implementations
strategies = {
'O(n) space': (n_values, time_linear),
'O(√n) space': (space_sqrt, time_linear * 1.5),
'O(log n) space': (np.log(n_values), time_linear * n_values / 100),
'O(1) space': (np.ones_like(n_values), time_linear ** 2)
}
# Plot curves
for name, (space, time) in strategies.items():
self.ax_tradeoff.loglog(space, time, label=name, linewidth=2)
# Highlight current point
current_space, current_time = self._get_current_point()
self.ax_tradeoff.scatter(current_space, current_time,
color='red', s=200, zorder=5,
edgecolors='black', linewidth=2)
# Theoretical bound (Williams)
self.ax_tradeoff.fill_between(space_sqrt, time_linear * 0.9, time_linear * 50,
alpha=0.2, color='gray',
label='Feasible region (Williams bound)')
self.ax_tradeoff.set_xlabel('Space Usage')
self.ax_tradeoff.set_ylabel('Time Complexity')
self.ax_tradeoff.legend(loc='upper left')
self.ax_tradeoff.grid(True, alpha=0.3)
# Add annotations
self.ax_tradeoff.annotate(f'Current: n={self.current_n:.0e}',
xy=(current_space, current_time),
xytext=(current_space*2, current_time*2),
arrowprops=dict(arrowstyle='->', color='red'))
def plot_memory_hierarchy(self):
"""Visualize memory hierarchy and data placement"""
self.ax_hierarchy.clear()
# Memory levels
levels = ['L1', 'L2', 'L3', 'RAM', 'SSD']
sizes = [
self.hierarchy.l1_size,
self.hierarchy.l2_size,
self.hierarchy.l3_size,
self.hierarchy.ram_size,
self.hierarchy.ssd_size
]
latencies = [
self.hierarchy.l1_latency_ns,
self.hierarchy.l2_latency_ns,
self.hierarchy.l3_latency_ns,
self.hierarchy.ram_latency_ns,
self.hierarchy.ssd_latency_ns
]
# Calculate data distribution
data_size = self.current_n * 8 # 8 bytes per element
distribution = self._calculate_data_distribution(data_size, sizes)
# Create stacked bar chart
y_pos = np.arange(len(levels))
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#DDA0DD']
bars = self.ax_hierarchy.barh(y_pos, distribution, color=colors)
# Add size labels
for i, (bar, size, dist) in enumerate(zip(bars, sizes, distribution)):
if dist > 0:
self.ax_hierarchy.text(bar.get_width()/2, bar.get_y() + bar.get_height()/2,
f'{dist/size*100:.1f}%',
ha='center', va='center', fontsize=8)
self.ax_hierarchy.set_yticks(y_pos)
self.ax_hierarchy.set_yticklabels(levels)
self.ax_hierarchy.set_xlabel('Data Distribution')
self.ax_hierarchy.set_xlim(0, max(distribution) * 1.2)
# Add latency annotations
for i, (level, latency) in enumerate(zip(levels, latencies)):
self.ax_hierarchy.text(max(distribution) * 1.1, i, f'{latency}ns',
ha='left', va='center', fontsize=8)
def plot_checkpoint_intervals(self):
"""Visualize checkpoint intervals for different strategies"""
self.ax_checkpoint.clear()
# Checkpoint strategies
n = self.current_n
strategies = {
'No checkpoint': [n],
'√n intervals': self._get_checkpoint_intervals(n, 'sqrt_n'),
'Fixed 1000': self._get_checkpoint_intervals(n, 'fixed', 1000),
'Exponential': self._get_checkpoint_intervals(n, 'exponential'),
}
# Plot timeline
y_offset = 0
colors = plt.cm.Set3(np.linspace(0, 1, len(strategies)))
for (name, intervals), color in zip(strategies.items(), colors):
# Draw checkpoint blocks
x_pos = 0
for interval in intervals[:20]: # Limit display
rect = mpatches.Rectangle((x_pos, y_offset), interval, 0.8,
facecolor=color, edgecolor='black', linewidth=0.5)
self.ax_checkpoint.add_patch(rect)
x_pos += interval
if x_pos > n:
break
# Label
self.ax_checkpoint.text(-n*0.1, y_offset + 0.4, name,
ha='right', va='center', fontsize=10)
y_offset += 1
self.ax_checkpoint.set_xlim(0, min(n, 10000))
self.ax_checkpoint.set_ylim(-0.5, len(strategies) - 0.5)
self.ax_checkpoint.set_xlabel('Progress')
self.ax_checkpoint.set_yticks([])
# Add checkpoint count
for i, (name, intervals) in enumerate(strategies.items()):
count = len(intervals)
self.ax_checkpoint.text(min(n, 10000) * 1.05, i + 0.4,
f'{count} checkpoints',
ha='left', va='center', fontsize=8)
def plot_cost_analysis(self):
"""Analyze costs of different strategies"""
self.ax_cost.clear()
# Cost components
strategies = ['O(n)', 'O(√n)', 'O(log n)', 'O(1)']
memory_costs = [100, 10, 1, 0.1]
time_costs = [1, 10, 100, 1000]
total_costs = [m + t for m, t in zip(memory_costs, time_costs)]
# Create grouped bar chart
x = np.arange(len(strategies))
width = 0.25
bars1 = self.ax_cost.bar(x - width, memory_costs, width, label='Memory Cost')
bars2 = self.ax_cost.bar(x, time_costs, width, label='Time Cost')
bars3 = self.ax_cost.bar(x + width, total_costs, width, label='Total Cost')
# Highlight current strategy
current_idx = strategies.index(f'O({self.current_strategy.replace("_", " ")})')
for bars in [bars1, bars2, bars3]:
bars[current_idx].set_edgecolor('red')
bars[current_idx].set_linewidth(3)
self.ax_cost.set_xticks(x)
self.ax_cost.set_xticklabels(strategies)
self.ax_cost.set_ylabel('Relative Cost')
self.ax_cost.legend()
self.ax_cost.set_yscale('log')
def plot_performance_metrics(self):
"""Show performance metrics for current configuration"""
self.ax_metrics.clear()
# Calculate metrics
n = self.current_n
metrics = self._calculate_performance_metrics(n, self.current_strategy)
# Create radar chart
categories = list(metrics.keys())
values = list(metrics.values())
angles = np.linspace(0, 2 * np.pi, len(categories), endpoint=False).tolist()
values += values[:1] # Complete the circle
angles += angles[:1]
self.ax_metrics.plot(angles, values, 'o-', linewidth=2, color='#4ECDC4')
self.ax_metrics.fill(angles, values, alpha=0.25, color='#4ECDC4')
self.ax_metrics.set_xticks(angles[:-1])
self.ax_metrics.set_xticklabels(categories, size=8)
self.ax_metrics.set_ylim(0, 100)
self.ax_metrics.grid(True)
# Add value labels
for angle, value, category in zip(angles[:-1], values[:-1], categories):
self.ax_metrics.text(angle, value + 5, f'{value:.0f}',
ha='center', va='center', size=8)
def plot_3d_visualization(self):
"""3D visualization of space-time-cost tradeoffs"""
self.ax_3d.clear()
# Generate 3D surface
n_range = np.logspace(2, 8, 20)
strategies = ['sqrt_n', 'linear', 'log_n']
for i, strategy in enumerate(strategies):
space = []
time = []
cost = []
for n in n_range:
s, t, c = self._get_strategy_metrics(n, strategy)
space.append(s)
time.append(t)
cost.append(c)
self.ax_3d.plot(np.log10(space), np.log10(time), np.log10(cost),
label=strategy, linewidth=2)
# Current point
s, t, c = self._get_strategy_metrics(self.current_n, self.current_strategy)
self.ax_3d.scatter([np.log10(s)], [np.log10(t)], [np.log10(c)],
color='red', s=100, edgecolors='black')
self.ax_3d.set_xlabel('log₁₀(Space)')
self.ax_3d.set_ylabel('log₁₀(Time)')
self.ax_3d.set_zlabel('log₁₀(Cost)')
self.ax_3d.legend()
def create_animated_view(self):
"""Create animated visualization of algorithm progress"""
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8))
# Initialize plots
n = 1000
x = np.arange(n)
y = np.random.rand(n)
line1, = ax1.plot([], [], 'b-', label='Processing')
checkpoint_lines = []
ax1.set_xlim(0, n)
ax1.set_ylim(0, 1)
ax1.set_title('Algorithm Progress with Checkpoints')
ax1.set_xlabel('Elements Processed')
ax1.legend()
# Memory usage over time
line2, = ax2.plot([], [], 'r-', label='Memory Usage')
ax2.set_xlim(0, n)
ax2.set_ylim(0, n * 8 / 1024) # KB
ax2.set_title('Memory Usage Over Time')
ax2.set_xlabel('Elements Processed')
ax2.set_ylabel('Memory (KB)')
ax2.legend()
# Animation function
checkpoint_interval = int(np.sqrt(n))
memory_usage = []
def animate(frame):
# Update processing line
line1.set_data(x[:frame], y[:frame])
# Add checkpoint markers
if frame % checkpoint_interval == 0 and frame > 0:
checkpoint_line = ax1.axvline(x=frame, color='red',
linestyle='--', alpha=0.5)
checkpoint_lines.append(checkpoint_line)
# Update memory usage
if self.current_strategy == 'sqrt_n':
mem = min(frame, checkpoint_interval) * 8 / 1024
else:
mem = frame * 8 / 1024
memory_usage.append(mem)
line2.set_data(range(len(memory_usage)), memory_usage)
return line1, line2
anim = animation.FuncAnimation(fig, animate, frames=n,
interval=10, blit=True)
plt.show()
return anim
def create_comparison_view(self):
"""Compare multiple strategies side by side"""
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
axes = axes.flatten()
strategies = ['sqrt_n', 'linear', 'log_n', 'constant']
n_range = np.logspace(2, 9, 100)
for ax, strategy in zip(axes, strategies):
# Calculate metrics
space = []
time = []
for n in n_range:
s, t, _ = self._get_strategy_metrics(n, strategy)
space.append(s)
time.append(t)
# Plot
ax.loglog(n_range, space, label='Space', linewidth=2)
ax.loglog(n_range, time, label='Time', linewidth=2)
ax.set_title(f'{strategy.replace("_", " ").title()} Strategy')
ax.set_xlabel('Data Size (n)')
ax.set_ylabel('Resource Usage')
ax.legend()
ax.grid(True, alpha=0.3)
# Add efficiency zone
if strategy == 'sqrt_n':
ax.axvspan(10**4, 10**7, alpha=0.2, color='green',
label='Optimal range')
plt.tight_layout()
plt.show()
# Helper methods
def _get_current_point(self) -> Tuple[float, float]:
"""Get current space-time point"""
n = self.current_n
if self.current_strategy == 'sqrt_n':
space = np.sqrt(n * np.log(n))
time = n * 1.5
elif self.current_strategy == 'linear':
space = n
time = n
elif self.current_strategy == 'log_n':
space = np.log(n)
time = n * n / 100
else: # constant
space = 1
time = n * n
return space, time
def _calculate_data_distribution(self, data_size: int,
memory_sizes: List[int]) -> List[float]:
"""Calculate how data is distributed across memory hierarchy"""
distribution = []
remaining = data_size
for size in memory_sizes:
if remaining <= 0:
distribution.append(0)
elif remaining <= size:
distribution.append(remaining)
remaining = 0
else:
distribution.append(size)
remaining -= size
return distribution
def _get_checkpoint_intervals(self, n: int, strategy: str,
param: Optional[int] = None) -> List[int]:
"""Get checkpoint intervals for different strategies"""
if strategy == 'sqrt_n':
interval = int(np.sqrt(n))
return [interval] * (n // interval)
elif strategy == 'fixed':
interval = param or 1000
return [interval] * (n // interval)
elif strategy == 'exponential':
intervals = []
pos = 0
exp = 1
while pos < n:
interval = min(2**exp, n - pos)
intervals.append(interval)
pos += interval
exp += 1
return intervals
else:
return [n]
def _calculate_performance_metrics(self, n: int,
strategy: str) -> Dict[str, float]:
"""Calculate performance metrics"""
# Base metrics
if strategy == 'sqrt_n':
memory_eff = 90
speed = 70
fault_tol = 85
scalability = 95
cost_eff = 80
elif strategy == 'linear':
memory_eff = 20
speed = 100
fault_tol = 50
scalability = 40
cost_eff = 60
elif strategy == 'log_n':
memory_eff = 95
speed = 30
fault_tol = 70
scalability = 80
cost_eff = 70
else: # constant
memory_eff = 100
speed = 10
fault_tol = 60
scalability = 90
cost_eff = 50
return {
'Memory\nEfficiency': memory_eff,
'Speed': speed,
'Fault\nTolerance': fault_tol,
'Scalability': scalability,
'Cost\nEfficiency': cost_eff
}
def _get_strategy_metrics(self, n: int,
strategy: str) -> Tuple[float, float, float]:
"""Get space, time, and cost for a strategy"""
if strategy == 'sqrt_n':
space = np.sqrt(n * np.log(n))
time = n * 1.5
cost = space * 0.1 + time * 0.01
elif strategy == 'linear':
space = n
time = n
cost = space * 0.1 + time * 0.01
elif strategy == 'log_n':
space = np.log(n)
time = n * n / 100
cost = space * 0.1 + time * 0.01
else: # constant
space = 1
time = n * n
cost = space * 0.1 + time * 0.01
return space, time, cost
# Event handlers
def _on_n_changed(self, val):
"""Handle data size slider change"""
self.current_n = 10**val
self.update_all_plots()
def _on_strategy_changed(self, label):
"""Handle strategy selection change"""
self.current_strategy = label
self.update_all_plots()
def _on_view_changed(self, label):
"""Handle view selection change"""
self.current_view = label
if label == 'animated':
self.create_animated_view()
elif label == 'comparison':
self.create_comparison_view()
else:
self.update_all_plots()
def _export_data(self, event):
"""Export visualization data"""
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
filename = f'spacetime_analysis_{timestamp}.json'
data = {
'timestamp': timestamp,
'parameters': {
'data_size': self.current_n,
'strategy': self.current_strategy,
'view': self.current_view
},
'metrics': self._calculate_performance_metrics(self.current_n,
self.current_strategy),
'space_time_point': self._get_current_point(),
'system_info': {
'l1_cache': self.hierarchy.l1_size,
'l2_cache': self.hierarchy.l2_size,
'l3_cache': self.hierarchy.l3_size,
'ram_size': self.hierarchy.ram_size
}
}
with open(filename, 'w') as f:
json.dump(data, f, indent=2)
print(f"Exported analysis to {filename}")
# Also save current figure
self.fig.savefig(f'spacetime_plot_{timestamp}.png', dpi=300, bbox_inches='tight')
print(f"Saved plot to spacetime_plot_{timestamp}.png")
def main():
"""Run the SpaceTime Explorer"""
print("SpaceTime Explorer - Interactive Visualization")
print("="*60)
visualizer = SpaceTimeVisualizer()
visualizer.create_main_window()
print("\nControls:")
print("- Slider: Adjust data size (n)")
print("- Radio buttons: Select strategy and view")
print("- Export: Save analysis and plots")
print("- Mouse: Pan and zoom on plots")
plt.show()
if __name__ == "__main__":
main()