Initial
This commit is contained in:
306
explorer/README.md
Normal file
306
explorer/README.md
Normal 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
|
||||
643
explorer/example_visualizations.py
Normal file
643
explorer/example_visualizations.py
Normal 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()
|
||||
653
explorer/spacetime_explorer.py
Normal file
653
explorer/spacetime_explorer.py
Normal 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()
|
||||
Reference in New Issue
Block a user