/ concept-collection / benchcompress
Sign in
concept-collection / benchcompress
benchcompress / figures / make_figures_iid.py
263 lines · 10.5 KBCodeBlameHistory
045ef0bmake figuresJeremy Magland 1import requests
2import json
3import os
4import numpy as np
5import matplotlib.pyplot as plt
6from matplotlib.axes import Axes
7from adjustText import adjust_text
8from load_results import download_results, load_results_into_models, BenchmarkResults
10def ensure_image_dir():
11 """Ensure the images directory exists relative to this script."""
12 script_dir = os.path.dirname(os.path.abspath(__file__))
13 image_dir = os.path.join(script_dir, 'images')
14 os.makedirs(image_dir, exist_ok=True)
15 return image_dir
17def get_theoretical_ratio(dataset_name: str) -> float | None:
18 """Get theoretical compression ratio for a dataset if applicable."""
19 if dataset_name.startswith('bernoulli-'):
20 try:
21 p = float(dataset_name.split('-')[1])
22 probs = np.array([p, 1-p])
23 entropy = -np.sum(probs * np.log2(probs)) # Shannon entropy
24 return 8 / entropy # 8 bits per byte divided by entropy
25 except (IndexError, ValueError):
26 return None
27 elif dataset_name.startswith('gaussian-q'):
28 try:
29 sigma = float(dataset_name.split('-q')[1])
30 # Calculate probabilities for integers in a reasonable range around mean (0)
31 # For 99.7% coverage, use ±4*sigma
32 range_max = int(4 * sigma)
33 x = np.arange(-range_max, range_max + 1)
34 # Calculate probabilities using normal distribution PDF
35 probs = (1/(sigma * np.sqrt(2*np.pi))) * np.exp(-(x**2)/(2*sigma**2))
36 # Normalize probabilities to sum to 1
37 probs = probs / np.sum(probs)
38 # Calculate entropy
39 nonzero_probs = probs[probs > 0] # Avoid log(0)
40 entropy = -np.sum(nonzero_probs * np.log2(nonzero_probs))
41 return 16 / entropy # 8 bits per byte divided by entropy
42 except (IndexError, ValueError):
43 return None
44 return None
46def plot_single_compression_ratio_comparison(results: BenchmarkResults, dataset_name: str, ax: Axes):
47 """Create a horizontal bar plot for a specific dataset."""
48 # Filter for the specified dataset
49 dataset_results = [r for r in results.results if r.dataset == dataset_name]
51 # Get unique algorithms and their best compression ratios
52 algorithm_ratios = {}
53 for r in dataset_results:
54 current_ratio = r.compression_ratio
55 if r.algorithm not in algorithm_ratios or current_ratio < algorithm_ratios[r.algorithm]:
56 algorithm_ratios[r.algorithm] = current_ratio
58 # Sort by compression ratio
59 sorted_items = sorted(algorithm_ratios.items(), key=lambda x: x[1])
60 algorithms = [item[0] for item in sorted_items]
61 ratios = [item[1] for item in sorted_items]
63 # Create horizontal bar plot
64 ax.barh(algorithms, ratios)
65 ax.set_xlabel('Compression Ratio')
66 ax.set_ylabel('Algorithm')
67 ax.set_title(f'Compression Ratios for {dataset_name}')
69 # Add theoretical limit line if applicable
70 theoretical_ratio = get_theoretical_ratio(dataset_name)
71 if theoretical_ratio is not None:
72 ax.axvline(x=theoretical_ratio, color='red', linestyle='--')
73 ax.legend()
75def figure_tradeoff_comparison(results: BenchmarkResults, datasets: list[str]):
76 """Create scatter plots showing compression ratio vs speed tradeoffs."""
77 # Create two figures - one for encode, one for decode
78 for speed_type in ['encode', 'decode']:
79 n_plots = len(datasets)
80 fig, axes = plt.subplots(1, n_plots, figsize=(10*n_plots, 8))
81 fig.suptitle(f'Compression Ratio vs {speed_type.capitalize()} Speed Tradeoff')
83 # Handle single dataset case
84 if n_plots == 1:
85 axes = [axes]
87 for dataset_name, ax in zip(datasets, axes):
88 # Filter for specified dataset
89 dataset_results = [r for r in results.results if r.dataset == dataset_name]
91 # Get best results for each algorithm
92 algorithm_metrics = {}
93 for r in dataset_results:
94 speed = r.encode_mb_per_sec if speed_type == 'encode' else r.decode_mb_per_sec
95 if r.algorithm not in algorithm_metrics:
96 algorithm_metrics[r.algorithm] = {
97 'ratio': r.compression_ratio,
98 'speed': speed
99 }
100 else:
101 # Update if this instance has better trade-off score
102 current_score = speed / r.compression_ratio
103 existing_score = (algorithm_metrics[r.algorithm]['speed'] /
104 algorithm_metrics[r.algorithm]['ratio'])
105 if current_score > existing_score:
106 algorithm_metrics[r.algorithm] = {
107 'ratio': r.compression_ratio,
108 'speed': speed
109 }
111 # Extract data for plotting
112 ratios = [metrics['ratio'] for metrics in algorithm_metrics.values()]
113 speeds = [metrics['speed'] for metrics in algorithm_metrics.values()]
114 algorithms = list(algorithm_metrics.keys())
116 # Create scatter plot
117 ax.scatter(ratios, speeds, alpha=0.6)
119 texts = [ax.text(ratios[i], speeds[i], alg, fontsize=9) for i, alg in enumerate(algorithms)]
120 adjust_text(texts,
121 arrowprops=dict(arrowstyle='->', color='gray', linewidth=0.5),
122 ensure_inside_axes=False,
123 ax=ax)
125 # Customize plot
126 ax.set_xlabel('Compression Ratio (higher is better)')
127 ax.set_ylabel(f'{speed_type.capitalize()} Speed MB/sec (higher is better)')
128 ax.set_title(f'{dataset_name}')
129 ax.grid(True, alpha=0.3)
131 # Add theoretical limit line if applicable
132 theoretical_ratio = get_theoretical_ratio(dataset_name)
133 if theoretical_ratio is not None:
134 ax.axvline(x=theoretical_ratio, color='red', linestyle='--')
135 ax.legend()
137 plt.tight_layout()
138 # Save figure
139 plt.savefig(os.path.join(ensure_image_dir(), f'iid_tradeoff_{speed_type}_{"-".join(datasets)}.png'))
140 plt.close()
142def figure_speeds_comparison(results: BenchmarkResults, datasets: list[str]):
143 """Create horizontal bar plots comparing encode/decode speeds for the given datasets."""
144 # Create figure with enough subplots for all datasets
145 n_plots = len(datasets)
146 fig, axes = plt.subplots(1, n_plots, figsize=(10*n_plots, 6))
148 # Handle single dataset case
149 if n_plots == 1:
150 axes = [axes]
152 for dataset_name, ax in zip(datasets, axes):
153 # Filter for specified dataset
154 dataset_results = [r for r in results.results if r.dataset == dataset_name]
156 # Get unique algorithms and their speeds
157 algorithm_speeds = {}
158 for r in dataset_results:
159 if r.algorithm not in algorithm_speeds:
160 algorithm_speeds[r.algorithm] = {
161 'encode': r.encode_mb_per_sec,
162 'decode': r.decode_mb_per_sec
163 }
164 else:
165 # Update if this instance has better average speed
166 current_avg = (r.encode_mb_per_sec + r.decode_mb_per_sec) / 2
167 existing_avg = (algorithm_speeds[r.algorithm]['encode'] +
168 algorithm_speeds[r.algorithm]['decode']) / 2
169 if current_avg > existing_avg:
170 algorithm_speeds[r.algorithm] = {
171 'encode': r.encode_mb_per_sec,
172 'decode': r.decode_mb_per_sec
173 }
175 # Sort alphabetically by algorithm name
176 sorted_items = sorted(algorithm_speeds.items(), key=lambda x: x[0])
177 algorithms = [item[0] for item in sorted_items]
178 encode_speeds = [item[1]['encode'] for item in sorted_items]
179 decode_speeds = [item[1]['decode'] for item in sorted_items]
181 # Set up positions for the bars
182 y_pos = np.arange(len(algorithms))
183 bar_height = 0.35
185 # Create bars
186 ax.barh(y_pos - bar_height/2, encode_speeds, bar_height,
187 label='Encode Speed', color='royalblue', alpha=0.8)
188 ax.barh(y_pos + bar_height/2, decode_speeds, bar_height,
189 label='Decode Speed', color='seagreen', alpha=0.8)
191 # Customize plot
192 ax.set_yticks(y_pos)
193 ax.set_yticklabels(algorithms)
194 ax.set_xlabel('Speed (MB/sec)')
195 ax.set_title(f'Encode/Decode Speeds for {dataset_name}')
196 ax.legend()
198 # Add grid for readability
199 ax.grid(True, axis='x', alpha=0.3)
201 plt.tight_layout()
202 # Save figure
203 plt.savefig(os.path.join(ensure_image_dir(), f'iid_speeds_comparison_{"-".join(datasets)}.png'))
204 plt.close()
206def figure_compression_ratios_comparison(results: BenchmarkResults, datasets: list[str]):
207 """Create horizontal bar plots comparing compression ratios for given datasets."""
208 # Create figure with enough subplots for all datasets
209 n_plots = len(datasets)
210 fig, axes = plt.subplots(1, n_plots, figsize=(10*n_plots, 6))
212 # Handle single dataset case
213 if n_plots == 1:
214 axes = [axes]
216 # Plot comparisons for each dataset
217 for dataset, ax in zip(datasets, axes):
218 plot_single_compression_ratio_comparison(results, dataset, ax)
220 plt.tight_layout()
221 # Save figure
222 plt.savefig(os.path.join(ensure_image_dir(), f'iid_compression_ratios_{"-".join(datasets)}.png'))
223 plt.close()
225def main():
226 try:
227 # Download the results
228 raw_data = download_results()
230 # Load into pydantic models
231 results = load_results_into_models(raw_data)
233 print(f"Successfully loaded {len(results.results)} benchmark results")
235 datasets_list = [
236 ['bernoulli-0.1', 'bernoulli-0.5'],
237 ['gaussian-q2', 'gaussian-q5']
238 ]
240 for datasets in datasets_list:
241 print("\nGenerating compression ratios plot...")
242 figure_compression_ratios_comparison(results, datasets)
244 print("\nGenerating speed comparison plot...")
245 figure_speeds_comparison(results, datasets)
247 print("\nGenerating tradeoff plots...")
248 figure_tradeoff_comparison(results, datasets)
250 return results
252 except requests.RequestException as e:
253 print(f"Error downloading results: {e}")
254 return None
255 except json.JSONDecodeError as e:
256 print(f"Error parsing JSON: {e}")
257 return None
258 except Exception as e:
259 print(f"Error loading data into models: {e}")
260 return None
262if __name__ == '__main__':
263 main()
moveopenescclose