Files

1429 lines
298 KiB
Plaintext
Raw Permalink Normal View History

{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "59f619dc",
"metadata": {},
2026-01-06 14:36:08 +01:00
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"✓ All modules loaded!\n",
"\n",
"============================================================\n",
" BENCHMARK: OptimizR (Rust) vs Pure Python\n",
"============================================================\n"
]
}
],
"source": [
"# pyright: reportArgumentType=false, reportUnusedImport=false, reportUnusedVariable=false, reportUnusedExpression=false, reportCallIssue=false, reportAttributeAccessIssue=false, reportOptionalMemberAccess=false, reportOperatorIssue=false, reportGeneralTypeIssues=false, reportReturnType=false, reportAssignmentType=false, reportIndexIssue=false, reportDeprecated=false, reportUndefinedVariable=false, reportPrivateImportUsage=false\n",
"import numpy as np\n",
"import pandas as pd\n",
"import time\n",
"import matplotlib.pyplot as plt\n",
"import seaborn as sns\n",
"from typing import Callable, Tuple\n",
"import warnings\n",
"warnings.filterwarnings('ignore')\n",
"\n",
"# OptimizR (Rust)\n",
"from optimizr import (\n",
" HMM,\n",
" mcmc_sample,\n",
" differential_evolution,\n",
" grid_search,\n",
" mutual_information,\n",
" shannon_entropy\n",
")\n",
"\n",
"# Pure Python alternatives\n",
"try:\n",
" from hmmlearn import hmm\n",
" HMMLEARN_AVAILABLE = True\n",
"except ImportError:\n",
" print(\"⚠️ hmmlearn not installed. Installing...\")\n",
" import subprocess\n",
" subprocess.run(['pip', 'install', 'hmmlearn'], check=True, capture_output=True)\n",
" from hmmlearn import hmm\n",
" HMMLEARN_AVAILABLE = True\n",
"\n",
"from scipy.optimize import differential_evolution as scipy_de\n",
"from sklearn.metrics import mutual_info_score\n",
"from sklearn.model_selection import ParameterGrid\n",
"\n",
"np.random.seed(42)\n",
"sns.set_style('whitegrid')\n",
"\n",
"print(\"✓ All modules loaded!\")\n",
"print(\"\\n\" + \"=\"*60)\n",
"print(\" BENCHMARK: OptimizR (Rust) vs Pure Python\")\n",
"print(\"=\"*60)\n",
"\n",
"_ = (Callable, Tuple, ParameterGrid,)\n"
]
},
{
"cell_type": "markdown",
"id": "3e8e4ee3",
"metadata": {},
"source": [
"## Benchmark 1: Hidden Markov Models\n",
"\n",
"### OptimizR (Rust) vs hmmlearn (Python/Cython)\n",
"\n",
"**Task**: Fit Gaussian HMM with 3 states to time series data"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "7d5439a8",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Model is not converging. Current: 1265.4250492350661 is not greater than 1265.4417975561971. Delta is -0.016748321130990007\n",
"Model is not converging. Current: 1265.4250492350661 is not greater than 1265.4417975561971. Delta is -0.016748321130990007\n",
"Model is not converging. Current: 1265.4250492350661 is not greater than 1265.4417975561971. Delta is -0.016748321130990007\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"📊 Testing HMM with 500 observations...\n",
" OptimizR: 2.7ms ± 0.8ms\n",
" hmmlearn: 66.1ms ± 39.3ms\n",
" 🚀 Speedup: 24.2x\n",
"\n",
"📊 Testing HMM with 1,000 observations...\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Model is not converging. Current: 2503.588336673215 is not greater than 2503.589554785923. Delta is -0.001218112708102126\n",
"Model is not converging. Current: 2503.588336673215 is not greater than 2503.589554785923. Delta is -0.001218112708102126\n",
"Model is not converging. Current: 2503.5883366732173 is not greater than 2503.5895547859236. Delta is -0.0012181127062831365\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
" OptimizR: 5.9ms ± 0.2ms\n",
" hmmlearn: 58.2ms ± 1.9ms\n",
" 🚀 Speedup: 9.9x\n",
"\n",
"📊 Testing HMM with 2,500 observations...\n",
" OptimizR: 13.3ms ± 0.8ms\n",
" hmmlearn: 127.5ms ± 4.5ms\n",
" 🚀 Speedup: 9.6x\n",
"\n",
"📊 Testing HMM with 5,000 observations...\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Model is not converging. Current: 12470.144154851318 is not greater than 12470.144321406788. Delta is -0.00016655547005939297\n",
"Model is not converging. Current: 12470.144154851318 is not greater than 12470.144321406788. Delta is -0.00016655547005939297\n",
"Model is not converging. Current: 12470.144154851318 is not greater than 12470.144321406788. Delta is -0.00016655547005939297\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
" OptimizR: 22.8ms ± 1.0ms\n",
" hmmlearn: 183.2ms ± 2.0ms\n",
" 🚀 Speedup: 8.0x\n",
"\n",
"============================================================\n",
"Average HMM speedup: 12.9x\n",
"============================================================\n"
]
}
],
"source": [
"# pyright: reportArgumentType=false, reportUnusedImport=false, reportUnusedVariable=false, reportUnusedExpression=false, reportCallIssue=false, reportAttributeAccessIssue=false, reportOptionalMemberAccess=false, reportOperatorIssue=false, reportGeneralTypeIssues=false, reportReturnType=false, reportAssignmentType=false, reportIndexIssue=false, reportDeprecated=false, reportUndefinedVariable=false, reportPrivateImportUsage=false\n",
"def benchmark_hmm(n_obs_list=(500, 1000, 2500, 5000), n_runs=3):\n",
" \"\"\"\n",
" Benchmark HMM fitting across multiple data sizes.\n",
"\n",
" Note: capped at 5,000 observations to avoid kernel pressure on\n",
" typical laptops while still showing the scaling trend clearly.\n",
" \"\"\"\n",
" results = []\n",
"\n",
" for n_obs in n_obs_list:\n",
" print(f\"\\n📊 Testing HMM with {n_obs:,} observations...\")\n",
"\n",
" # Generate synthetic 1D data\n",
" rng = np.random.default_rng(42)\n",
" data = rng.standard_normal(n_obs) * 0.02 + 0.001\n",
" data_reshaped = data.reshape(-1, 1) # hmmlearn needs 2D\n",
"\n",
" # Benchmark OptimizR (Rust)\n",
" rust_times = []\n",
" for _ in range(n_runs):\n",
" hmm_rust = HMM(n_states=3)\n",
" start = time.perf_counter()\n",
" hmm_rust.fit(data, n_iterations=50, tolerance=1e-4)\n",
" rust_times.append(time.perf_counter() - start)\n",
"\n",
" rust_mean = float(np.mean(rust_times))\n",
" rust_std = float(np.std(rust_times))\n",
"\n",
" # Benchmark hmmlearn (Python/Cython)\n",
" python_times = []\n",
" for _ in range(n_runs):\n",
" hmm_py = hmm.GaussianHMM(\n",
" n_components=3,\n",
" covariance_type='spherical',\n",
" n_iter=50,\n",
" tol=1e-4,\n",
" random_state=42,\n",
" )\n",
" start = time.perf_counter()\n",
" hmm_py.fit(data_reshaped)\n",
" python_times.append(time.perf_counter() - start)\n",
"\n",
" python_mean = float(np.mean(python_times))\n",
" python_std = float(np.std(python_times))\n",
"\n",
" speedup = python_mean / rust_mean\n",
"\n",
" results.append({\n",
" 'n_obs': n_obs,\n",
" 'rust_time': rust_mean,\n",
" 'rust_std': rust_std,\n",
" 'python_time': python_mean,\n",
" 'python_std': python_std,\n",
" 'speedup': speedup,\n",
" })\n",
"\n",
" print(f\" OptimizR: {rust_mean*1000:.1f}ms ± {rust_std*1000:.1f}ms\")\n",
" print(f\" hmmlearn: {python_mean*1000:.1f}ms ± {python_std*1000:.1f}ms\")\n",
" print(f\" 🚀 Speedup: {speedup:.1f}x\")\n",
"\n",
" return pd.DataFrame(results)\n",
"\n",
"hmm_results = benchmark_hmm()\n",
"print(\"\\n\" + \"=\"*60)\n",
"print(f\"Average HMM speedup: {hmm_results['speedup'].mean():.1f}x\")\n",
"print(\"=\"*60)\n"
]
},
{
"cell_type": "markdown",
"id": "4fbb29f6",
"metadata": {},
"source": [
"## Benchmark 2: MCMC Sampling\n",
"\n",
"### OptimizR (Rust) vs Pure NumPy Implementation\n",
"\n",
"**Task**: Metropolis-Hastings sampling for 2D parameter space"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "5f671a6d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"🔗 Testing MCMC with 500 samples...\n",
" OptimizR: 1.6ms ± 0.8ms\n",
" Pure Python: 15.9ms ± 1.4ms\n",
" 🚀 Speedup: 9.7x\n",
"\n",
"🔗 Testing MCMC with 1,000 samples...\n",
" OptimizR: 2.2ms ± 0.1ms\n",
" Pure Python: 17.2ms ± 0.3ms\n",
" 🚀 Speedup: 7.7x\n",
"\n",
"🔗 Testing MCMC with 2,500 samples...\n",
" OptimizR: 4.2ms ± 0.1ms\n",
" Pure Python: 34.4ms ± 4.2ms\n",
" 🚀 Speedup: 8.2x\n",
"\n",
"🔗 Testing MCMC with 5,000 samples...\n",
" OptimizR: 11.7ms ± 2.5ms\n",
" Pure Python: 64.4ms ± 7.6ms\n",
" 🚀 Speedup: 5.5x\n",
"\n",
"============================================================\n",
"Average MCMC speedup: 7.8x\n",
"============================================================\n"
]
}
],
"source": [
"# pyright: reportArgumentType=false, reportUnusedImport=false, reportUnusedVariable=false, reportUnusedExpression=false, reportCallIssue=false, reportAttributeAccessIssue=false, reportOptionalMemberAccess=false, reportOperatorIssue=false, reportGeneralTypeIssues=false, reportReturnType=false, reportAssignmentType=false, reportIndexIssue=false, reportDeprecated=false, reportUndefinedVariable=false, reportPrivateImportUsage=false\n",
"def python_mcmc(log_likelihood_fn, initial_params, param_bounds,\n",
" n_samples=2000, burn_in=500, proposal_std=0.1, seed=42):\n",
" \"\"\"Pure NumPy Metropolis-Hastings sampler (single chain).\"\"\"\n",
" rng = np.random.default_rng(seed)\n",
" dim = len(initial_params)\n",
" bounds = np.asarray(param_bounds, dtype=float)\n",
" current = np.asarray(initial_params, dtype=float).copy()\n",
" current_ll = log_likelihood_fn(current.tolist())\n",
" total = burn_in + n_samples\n",
" samples = np.empty((n_samples, dim))\n",
" accepted = 0\n",
" out_idx = 0\n",
" for i in range(total):\n",
" proposal = current + rng.normal(0.0, proposal_std, size=dim)\n",
" # reflect at bounds\n",
" proposal = np.clip(proposal, bounds[:, 0], bounds[:, 1])\n",
" proposal_ll = log_likelihood_fn(proposal.tolist())\n",
" if np.log(rng.random()) < (proposal_ll - current_ll):\n",
" current = proposal\n",
" current_ll = proposal_ll\n",
" if i >= burn_in:\n",
" accepted += 1\n",
" if i >= burn_in:\n",
" samples[out_idx] = current\n",
" out_idx += 1\n",
" return samples\n",
"\n",
"\n",
"def benchmark_mcmc(n_samples_list=(500, 1000, 2500, 5000), n_runs=3):\n",
" \"\"\"\n",
" Benchmark Metropolis-Hastings on a 2D Gaussian target.\n",
" \"\"\"\n",
" results = []\n",
"\n",
" # Target: 2D Gaussian centered at (1, -1) with unit variance\n",
" def log_likelihood(theta):\n",
" a, b = theta[0], theta[1]\n",
" return -0.5 * ((a - 1.0) ** 2 + (b + 1.0) ** 2)\n",
"\n",
" bounds = [(-5.0, 5.0), (-5.0, 5.0)]\n",
" initial = np.array([0.0, 0.0])\n",
"\n",
" for n_samples in n_samples_list:\n",
" print(f\"\\n🔗 Testing MCMC with {n_samples:,} samples...\")\n",
"\n",
" # Benchmark OptimizR (Rust)\n",
" rust_times = []\n",
" for _ in range(n_runs):\n",
" start = time.perf_counter()\n",
" _ = mcmc_sample(\n",
" log_likelihood_fn=log_likelihood,\n",
" initial_params=initial,\n",
" param_bounds=bounds,\n",
" n_samples=n_samples,\n",
" burn_in=max(200, n_samples // 5),\n",
" proposal_std=0.5,\n",
" )\n",
" rust_times.append(time.perf_counter() - start)\n",
"\n",
" rust_mean = float(np.mean(rust_times))\n",
" rust_std = float(np.std(rust_times))\n",
"\n",
" # Benchmark Pure Python MCMC\n",
" python_times = []\n",
" for _ in range(n_runs):\n",
" start = time.perf_counter()\n",
" _ = python_mcmc(\n",
" log_likelihood_fn=log_likelihood,\n",
" initial_params=initial,\n",
" param_bounds=bounds,\n",
" n_samples=n_samples,\n",
" burn_in=max(200, n_samples // 5),\n",
" proposal_std=0.5,\n",
" )\n",
" python_times.append(time.perf_counter() - start)\n",
"\n",
" python_mean = float(np.mean(python_times))\n",
" python_std = float(np.std(python_times))\n",
"\n",
" speedup = python_mean / rust_mean\n",
"\n",
" results.append({\n",
" 'n_samples': n_samples,\n",
" 'rust_time': rust_mean,\n",
" 'rust_std': rust_std,\n",
" 'python_time': python_mean,\n",
" 'python_std': python_std,\n",
" 'speedup': speedup,\n",
" })\n",
"\n",
" print(f\" OptimizR: {rust_mean*1000:.1f}ms ± {rust_std*1000:.1f}ms\")\n",
" print(f\" Pure Python: {python_mean*1000:.1f}ms ± {python_std*1000:.1f}ms\")\n",
" print(f\" 🚀 Speedup: {speedup:.1f}x\")\n",
"\n",
" return pd.DataFrame(results)\n",
"\n",
"mcmc_results = benchmark_mcmc()\n",
"print(\"\\n\" + \"=\"*60)\n",
"print(f\"Average MCMC speedup: {mcmc_results['speedup'].mean():.1f}x\")\n",
"print(\"=\"*60)\n"
]
},
{
"cell_type": "markdown",
"id": "e7271c39",
"metadata": {},
"source": [
"## Benchmark 3: Differential Evolution\n",
"\n",
"### OptimizR (Rust) vs scipy.optimize\n",
"\n",
"**Task**: Optimize Rosenbrock function in multiple dimensions"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "ba75a625",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"🎯 Testing DE with 2D Rosenbrock...\n",
" OptimizR: 41.1ms ± 1.0ms (f=2.20e-10)\n",
" SciPy: 252.7ms ± 6.9ms (f=1.67e-27)\n",
" 🚀 Speedup: 6.2x\n",
"\n",
"🎯 Testing DE with 5D Rosenbrock...\n",
" OptimizR: 138.2ms ± 1.1ms (f=1.75e+00)\n",
" SciPy: 582.6ms ± 0.8ms (f=5.15e-04)\n",
" 🚀 Speedup: 4.2x\n",
"\n",
"🎯 Testing DE with 10D Rosenbrock...\n",
" OptimizR: 318.5ms ± 7.3ms (f=1.29e+01)\n",
" SciPy: 1196.5ms ± 3.9ms (f=4.76e+00)\n",
" 🚀 Speedup: 3.8x\n",
"\n",
"============================================================\n",
"Average DE speedup: 4.7x\n",
"============================================================\n"
]
}
],
"source": [
"# pyright: reportArgumentType=false, reportUnusedImport=false, reportUnusedVariable=false, reportUnusedExpression=false, reportCallIssue=false, reportAttributeAccessIssue=false, reportOptionalMemberAccess=false, reportOperatorIssue=false, reportGeneralTypeIssues=false, reportReturnType=false, reportAssignmentType=false, reportIndexIssue=false, reportDeprecated=false, reportUndefinedVariable=false, reportPrivateImportUsage=false\n",
"def rosenbrock(x):\n",
" \"\"\"N-dimensional Rosenbrock function.\"\"\"\n",
" x = np.asarray(x, dtype=float)\n",
" return float(np.sum(100.0 * (x[1:] - x[:-1] ** 2) ** 2 + (1.0 - x[:-1]) ** 2))\n",
"\n",
"\n",
"def benchmark_de(dimensions=(2, 5, 10), n_runs=3, popsize=15, maxiter=100):\n",
" \"\"\"\n",
" Benchmark Differential Evolution on Rosenbrock.\n",
" \"\"\"\n",
" results = []\n",
"\n",
" for dim in dimensions:\n",
" print(f\"\\n🎯 Testing DE with {dim}D Rosenbrock...\")\n",
"\n",
" bounds = [(-5.0, 5.0)] * dim\n",
"\n",
" # Benchmark OptimizR (Rust) — returns (best_x, best_f)\n",
" rust_times = []\n",
" rust_results = []\n",
" for _ in range(n_runs):\n",
" start = time.perf_counter()\n",
" _, best_f = differential_evolution(\n",
" objective_fn=rosenbrock,\n",
" bounds=bounds,\n",
" popsize=popsize,\n",
" maxiter=maxiter,\n",
" tol=1e-6,\n",
" seed=42,\n",
" )\n",
" rust_times.append(time.perf_counter() - start)\n",
" rust_results.append(best_f)\n",
"\n",
" rust_mean = float(np.mean(rust_times))\n",
" rust_std = float(np.std(rust_times))\n",
" rust_quality = float(np.mean(rust_results))\n",
"\n",
" # Benchmark SciPy — returns OptimizeResult\n",
" python_times = []\n",
" python_results = []\n",
" for _ in range(n_runs):\n",
" start = time.perf_counter()\n",
" result = scipy_de(\n",
" func=rosenbrock,\n",
" bounds=bounds,\n",
" popsize=popsize,\n",
" maxiter=maxiter,\n",
" tol=1e-6,\n",
" seed=42,\n",
" workers=1,\n",
" polish=False,\n",
" )\n",
" python_times.append(time.perf_counter() - start)\n",
" python_results.append(result.fun)\n",
"\n",
" python_mean = float(np.mean(python_times))\n",
" python_std = float(np.std(python_times))\n",
" python_quality = float(np.mean(python_results))\n",
"\n",
" speedup = python_mean / rust_mean\n",
"\n",
" results.append({\n",
" 'dimensions': dim,\n",
" 'rust_time': rust_mean,\n",
" 'rust_std': rust_std,\n",
" 'rust_quality': rust_quality,\n",
" 'python_time': python_mean,\n",
" 'python_std': python_std,\n",
" 'python_quality': python_quality,\n",
" 'speedup': speedup,\n",
" })\n",
"\n",
" print(f\" OptimizR: {rust_mean*1000:.1f}ms ± {rust_std*1000:.1f}ms (f={rust_quality:.2e})\")\n",
" print(f\" SciPy: {python_mean*1000:.1f}ms ± {python_std*1000:.1f}ms (f={python_quality:.2e})\")\n",
" print(f\" 🚀 Speedup: {speedup:.1f}x\")\n",
"\n",
" return pd.DataFrame(results)\n",
"\n",
"de_results = benchmark_de()\n",
"print(\"\\n\" + \"=\"*60)\n",
"print(f\"Average DE speedup: {de_results['speedup'].mean():.1f}x\")\n",
"print(\"=\"*60)\n"
]
},
{
"cell_type": "markdown",
"id": "b281436f",
"metadata": {},
"source": [
"## Benchmark 4: Grid Search\n",
"\n",
"### OptimizR (Rust) vs sklearn.model_selection.ParameterGrid\n",
"\n",
"**Task**: Exhaustive search over parameter space"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "355a832e",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"🔍 Testing Grid Search: 2D, 8 points/dim (64 total)...\n",
" OptimizR: 0.8ms ± 0.5ms\n",
" Pure Python: 0.6ms ± 0.0ms\n",
" 🚀 Speedup: 0.7x\n",
"\n",
"🔍 Testing Grid Search: 2D, 12 points/dim (144 total)...\n",
" OptimizR: 1.4ms ± 0.3ms\n",
" Pure Python: 1.1ms ± 0.0ms\n",
" 🚀 Speedup: 0.7x\n",
"\n",
"🔍 Testing Grid Search: 2D, 16 points/dim (256 total)...\n",
" OptimizR: 2.1ms ± 0.1ms\n",
" Pure Python: 1.8ms ± 0.0ms\n",
" 🚀 Speedup: 0.8x\n",
"\n",
"🔍 Testing Grid Search: 3D, 8 points/dim (512 total)...\n",
" OptimizR: 3.9ms ± 0.1ms\n",
" Pure Python: 3.6ms ± 0.0ms\n",
" 🚀 Speedup: 0.9x\n",
"\n",
"🔍 Testing Grid Search: 3D, 12 points/dim (1,728 total)...\n",
" OptimizR: 14.2ms ± 1.4ms\n",
" Pure Python: 11.6ms ± 0.3ms\n",
" 🚀 Speedup: 0.8x\n",
"\n",
"🔍 Testing Grid Search: 3D, 16 points/dim (4,096 total)...\n",
" OptimizR: 30.7ms ± 0.0ms\n",
" Pure Python: 26.0ms ± 0.3ms\n",
" 🚀 Speedup: 0.8x\n",
"\n",
"============================================================\n",
"Average Grid Search speedup: 0.8x\n",
"============================================================\n"
]
}
],
"source": [
"# pyright: reportArgumentType=false, reportUnusedImport=false, reportUnusedVariable=false, reportUnusedExpression=false, reportCallIssue=false, reportAttributeAccessIssue=false, reportOptionalMemberAccess=false, reportOperatorIssue=false, reportGeneralTypeIssues=false, reportReturnType=false, reportAssignmentType=false, reportIndexIssue=false, reportDeprecated=false, reportUndefinedVariable=false, reportPrivateImportUsage=false\n",
"def sphere_function(x):\n",
" \"\"\"Simple sphere function for testing.\"\"\"\n",
" x = np.asarray(x, dtype=float)\n",
" return float(np.sum(x ** 2))\n",
"\n",
"\n",
"def python_grid_search(objective_fn, bounds, n_points):\n",
" \"\"\"Pure Python grid search implementation.\"\"\"\n",
" grids = [np.linspace(low, high, n_points) for low, high in bounds]\n",
" meshes = np.meshgrid(*grids, indexing='ij')\n",
" points = np.vstack([m.ravel() for m in meshes]).T\n",
"\n",
" best_value = np.inf\n",
" best_params = None\n",
" for point in points:\n",
" value = objective_fn(point)\n",
" if value < best_value:\n",
" best_value = value\n",
" best_params = point\n",
" return best_params, best_value\n",
"\n",
"\n",
"def benchmark_grid_search(n_points_list=(8, 12, 16), dimensions=(2, 3), n_runs=3,\n",
" max_total_evals=20000):\n",
" \"\"\"Benchmark Grid Search (capped at 20k evals to keep runtime bounded).\"\"\"\n",
" results = []\n",
"\n",
" for dim in dimensions:\n",
" for n_points in n_points_list:\n",
" total_evals = n_points ** dim\n",
" if total_evals > max_total_evals:\n",
" continue\n",
"\n",
" print(f\"\\n🔍 Testing Grid Search: {dim}D, {n_points} points/dim ({total_evals:,} total)...\")\n",
" bounds = [(-10.0, 10.0)] * dim\n",
"\n",
" # Benchmark OptimizR (Rust)\n",
" rust_times = []\n",
" for _ in range(n_runs):\n",
" start = time.perf_counter()\n",
" _ = grid_search(\n",
" objective_fn=sphere_function,\n",
" bounds=bounds,\n",
" n_points=n_points,\n",
" )\n",
" rust_times.append(time.perf_counter() - start)\n",
"\n",
" rust_mean = float(np.mean(rust_times))\n",
" rust_std = float(np.std(rust_times))\n",
"\n",
" # Benchmark Pure Python\n",
" python_times = []\n",
" for _ in range(n_runs):\n",
" start = time.perf_counter()\n",
" _, _ = python_grid_search(\n",
" objective_fn=sphere_function,\n",
" bounds=bounds,\n",
" n_points=n_points,\n",
" )\n",
" python_times.append(time.perf_counter() - start)\n",
"\n",
" python_mean = float(np.mean(python_times))\n",
" python_std = float(np.std(python_times))\n",
"\n",
" speedup = python_mean / rust_mean\n",
"\n",
" results.append({\n",
" 'dimensions': dim,\n",
" 'n_points': n_points,\n",
" 'total_evals': total_evals,\n",
" 'rust_time': rust_mean,\n",
" 'rust_std': rust_std,\n",
" 'python_time': python_mean,\n",
" 'python_std': python_std,\n",
" 'speedup': speedup,\n",
" })\n",
"\n",
" print(f\" OptimizR: {rust_mean*1000:.1f}ms ± {rust_std*1000:.1f}ms\")\n",
" print(f\" Pure Python: {python_mean*1000:.1f}ms ± {python_std*1000:.1f}ms\")\n",
" print(f\" 🚀 Speedup: {speedup:.1f}x\")\n",
"\n",
" return pd.DataFrame(results)\n",
"\n",
"grid_results = benchmark_grid_search()\n",
"print(\"\\n\" + \"=\"*60)\n",
"print(f\"Average Grid Search speedup: {grid_results['speedup'].mean():.1f}x\")\n",
"print(\"=\"*60)\n"
]
},
{
"cell_type": "markdown",
"id": "56c81ec0",
"metadata": {},
"source": [
"## Benchmark 5: Information Theory\n",
"\n",
"### OptimizR (Rust) vs scikit-learn\n",
"\n",
"**Task**: Compute mutual information on discretized data"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "ff0dd89b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"📈 Testing Information Theory with 500 observations...\n",
" Mutual Information:\n",
" OptimizR: 0.25ms ± 0.28ms\n",
" sklearn: 6.18ms ± 6.52ms\n",
" 🚀 Speedup: 25.2x\n",
" Shannon Entropy:\n",
" OptimizR: 0.03ms ± 0.01ms\n",
" NumPy: 0.22ms ± 0.05ms\n",
" 🚀 Speedup: 8.7x\n",
"\n",
"📈 Testing Information Theory with 1,000 observations...\n",
" Mutual Information:\n",
" OptimizR: 0.12ms ± 0.04ms\n",
" sklearn: 1.61ms ± 0.04ms\n",
" 🚀 Speedup: 13.8x\n",
" Shannon Entropy:\n",
" OptimizR: 0.04ms ± 0.01ms\n",
" NumPy: 0.22ms ± 0.03ms\n",
" 🚀 Speedup: 5.0x\n",
"\n",
"📈 Testing Information Theory with 2,500 observations...\n",
" Mutual Information:\n",
" OptimizR: 0.24ms ± 0.04ms\n",
" sklearn: 1.78ms ± 0.06ms\n",
" 🚀 Speedup: 7.4x\n",
" Shannon Entropy:\n",
" OptimizR: 0.10ms ± 0.00ms\n",
" NumPy: 0.23ms ± 0.02ms\n",
" 🚀 Speedup: 2.3x\n",
"\n",
"📈 Testing Information Theory with 5,000 observations...\n",
" Mutual Information:\n",
" OptimizR: 0.49ms ± 0.07ms\n",
" sklearn: 2.21ms ± 0.15ms\n",
" 🚀 Speedup: 4.5x\n",
" Shannon Entropy:\n",
" OptimizR: 0.20ms ± 0.01ms\n",
" NumPy: 0.26ms ± 0.02ms\n",
" 🚀 Speedup: 1.3x\n",
"\n",
"============================================================\n",
"Average MI speedup: 12.8x\n",
"Average Entropy speedup: 4.3x\n",
"============================================================\n"
]
}
],
"source": [
"# pyright: reportArgumentType=false, reportUnusedImport=false, reportUnusedVariable=false, reportUnusedExpression=false, reportCallIssue=false, reportAttributeAccessIssue=false, reportOptionalMemberAccess=false, reportOperatorIssue=false, reportGeneralTypeIssues=false, reportReturnType=false, reportAssignmentType=false, reportIndexIssue=false, reportDeprecated=false, reportUndefinedVariable=false, reportPrivateImportUsage=false\n",
"def benchmark_information_theory(n_obs_list=(500, 1000, 2500, 5000), n_runs=3):\n",
" \"\"\"Benchmark Shannon Entropy and Mutual Information.\"\"\"\n",
" results = []\n",
"\n",
" for n_obs in n_obs_list:\n",
" print(f\"\\n📈 Testing Information Theory with {n_obs:,} observations...\")\n",
"\n",
" rng = np.random.default_rng(42)\n",
" x = rng.standard_normal(n_obs)\n",
" y = 0.7 * x + 0.3 * rng.standard_normal(n_obs)\n",
"\n",
" # ----- Mutual Information: OptimizR -----\n",
" rust_mi_times = []\n",
" for _ in range(n_runs):\n",
" start = time.perf_counter()\n",
" _ = mutual_information(x, y)\n",
" rust_mi_times.append(time.perf_counter() - start)\n",
" rust_mi_mean = float(np.mean(rust_mi_times))\n",
" rust_mi_std = float(np.std(rust_mi_times))\n",
"\n",
" # ----- Mutual Information: sklearn (with discretization cost) -----\n",
" python_mi_times = []\n",
" for _ in range(n_runs):\n",
" start = time.perf_counter()\n",
" x_d = np.digitize(x, bins=np.linspace(x.min(), x.max(), 20))\n",
" y_d = np.digitize(y, bins=np.linspace(y.min(), y.max(), 20))\n",
" _ = mutual_info_score(x_d, y_d)\n",
" python_mi_times.append(time.perf_counter() - start)\n",
" python_mi_mean = float(np.mean(python_mi_times))\n",
" python_mi_std = float(np.std(python_mi_times))\n",
" mi_speedup = python_mi_mean / rust_mi_mean\n",
"\n",
" # ----- Shannon Entropy: OptimizR -----\n",
" rust_entropy_times = []\n",
" for _ in range(n_runs):\n",
" start = time.perf_counter()\n",
" _ = shannon_entropy(x)\n",
" rust_entropy_times.append(time.perf_counter() - start)\n",
" rust_entropy_mean = float(np.mean(rust_entropy_times))\n",
" rust_entropy_std = float(np.std(rust_entropy_times))\n",
"\n",
" # ----- Shannon Entropy: Pure Python -----\n",
" def python_shannon_entropy(data, n_bins=20):\n",
" hist, _ = np.histogram(data, bins=n_bins, density=True)\n",
" hist = hist[hist > 0]\n",
" bin_width = (data.max() - data.min()) / n_bins\n",
" prob = hist * bin_width\n",
" prob = prob / prob.sum()\n",
" return -float(np.sum(prob * np.log2(prob)))\n",
"\n",
" python_entropy_times = []\n",
" for _ in range(n_runs):\n",
" start = time.perf_counter()\n",
" _ = python_shannon_entropy(x)\n",
" python_entropy_times.append(time.perf_counter() - start)\n",
" python_entropy_mean = float(np.mean(python_entropy_times))\n",
" python_entropy_std = float(np.std(python_entropy_times))\n",
" entropy_speedup = python_entropy_mean / rust_entropy_mean\n",
"\n",
" results.append({\n",
" 'n_obs': n_obs,\n",
" 'rust_mi_time': rust_mi_mean,\n",
" 'python_mi_time': python_mi_mean,\n",
" 'mi_speedup': mi_speedup,\n",
" 'rust_entropy_time': rust_entropy_mean,\n",
" 'python_entropy_time': python_entropy_mean,\n",
" 'entropy_speedup': entropy_speedup,\n",
" })\n",
"\n",
" print(f\" Mutual Information:\")\n",
" print(f\" OptimizR: {rust_mi_mean*1000:.2f}ms ± {rust_mi_std*1000:.2f}ms\")\n",
" print(f\" sklearn: {python_mi_mean*1000:.2f}ms ± {python_mi_std*1000:.2f}ms\")\n",
" print(f\" 🚀 Speedup: {mi_speedup:.1f}x\")\n",
"\n",
" print(f\" Shannon Entropy:\")\n",
" print(f\" OptimizR: {rust_entropy_mean*1000:.2f}ms ± {rust_entropy_std*1000:.2f}ms\")\n",
" print(f\" NumPy: {python_entropy_mean*1000:.2f}ms ± {python_entropy_std*1000:.2f}ms\")\n",
" print(f\" 🚀 Speedup: {entropy_speedup:.1f}x\")\n",
"\n",
" return pd.DataFrame(results)\n",
"\n",
"info_results = benchmark_information_theory()\n",
"print(\"\\n\" + \"=\"*60)\n",
"print(f\"Average MI speedup: {info_results['mi_speedup'].mean():.1f}x\")\n",
"print(f\"Average Entropy speedup: {info_results['entropy_speedup'].mean():.1f}x\")\n",
"print(\"=\"*60)\n"
]
},
{
"cell_type": "markdown",
"id": "ff68ec04",
"metadata": {},
"source": [
"## Benchmark 6: v2.0 Primitives\n",
"\n",
"### Path Signatures, Hawkes Processes & Robust Drift\n",
"\n",
"**Task**: benchmark three of the new primitives shipped in `optimiz-rs v2.0`\n",
"against pure-Python reference implementations:\n",
"\n",
"- **Path signatures (level 3)** — truncated tensor algebra of an iterated-integral\n",
" path, used by signature-kernel methods and rough-volatility calibration.\n",
"- **Hawkes simulation** — exponential self-exciting point process, the workhorse\n",
" of LOB / order-flow modelling.\n",
"- **Robust drift (Huber M-estimator)** — outlier-resistant drift estimator for\n",
" noisy observations of a diffusion.\n",
"\n",
"These three exercise distinct workloads (combinatorial recursion, sequential\n",
"simulation, iterative optimisation) and complement Benchmarks 15.\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "336d8629",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"🔣 Path signature (level 3, 2-D Brownian path)\n",
" n= 200: Rust 0.95ms · Py 13.58ms · 🚀 14.3x\n",
" n= 400: Rust 1.79ms · Py 22.73ms · 🚀 12.7x\n",
" n= 800: Rust 2.93ms · Py 41.78ms · 🚀 14.3x\n",
"\n",
"💥 Hawkes simulation (exponential kernel, baseline=1, α=0.5, β=1)\n",
" T= 100: Rust 1.82ms · Py 0.71ms · 🚀 0.4x\n",
" T= 500: Rust 20.74ms · Py 3.59ms · 🚀 0.2x\n",
" T= 2000: Rust 422.57ms · Py 23.60ms · 🚀 0.1x\n",
"\n",
"🛡️ Robust drift (Huber M-estimator, σ=0.2, μ_true=0.05)\n",
" n= 1000: Rust 0.89ms · Py 2.61ms · 🚀 2.9x\n",
" n= 2500: Rust 2.47ms · Py 4.05ms · 🚀 1.6x\n",
" n= 5000: Rust 4.00ms · Py 3.12ms · 🚀 0.8x\n",
"\n",
"============================================================\n",
" task baseline avg_speedup max_speedup\n",
"Path signature (lvl 3) Pure NumPy 13.736466 14.255275\n",
" Hawkes simulation Pure NumPy (Ogata) 0.205974 0.388756\n",
" Robust drift (Huber) Pure NumPy (IRLS) 1.787452 2.939508\n",
"============================================================\n",
"Average v2.0 primitive speedup: 5.2x\n",
"============================================================\n"
]
}
],
"source": [
"# pyright: reportArgumentType=false, reportUnusedImport=false, reportUnusedVariable=false, reportUnusedExpression=false, reportCallIssue=false, reportAttributeAccessIssue=false, reportOptionalMemberAccess=false, reportOperatorIssue=false, reportGeneralTypeIssues=false, reportReturnType=false, reportAssignmentType=false, reportIndexIssue=false, reportDeprecated=false, reportUndefinedVariable=false, reportPrivateImportUsage=false\n",
"import math\n",
"from optimizr import path_signature, simulate_hawkes, robust_drift\n",
"\n",
"\n",
"# ---------- Pure-Python references ----------\n",
"\n",
"def python_path_signature(path, level):\n",
" \"\"\"Truncated path signature up to `level`, computed with a Chen-style\n",
" iterative tensor product. O((level * d) ** level).\"\"\"\n",
" path = np.asarray(path, dtype=float)\n",
" n, d = path.shape\n",
" increments = np.diff(path, axis=0) # (n-1, d)\n",
"\n",
" # signature[k] is a flat tensor of shape (d,)*k\n",
" signature = [np.array([1.0])] # level 0\n",
" for k in range(1, level + 1):\n",
" signature.append(np.zeros((d,) * k))\n",
"\n",
" for inc in increments:\n",
" # Chen's identity: S_{0,t+dt} = S_{0,t} ⊗ exp(dx)\n",
" # exp(dx) truncated at `level`: 1 + dx + dx⊗dx/2 + ...\n",
" new_sig = [np.array([1.0])]\n",
" for k in range(1, level + 1):\n",
" acc = np.zeros((d,) * k)\n",
" # S_{0,t}[j] ⊗ inc^{k-j} / (k-j)!\n",
" for j in range(0, k + 1):\n",
" left = signature[j]\n",
" # inc^{k-j} / (k-j)!\n",
" if k - j == 0:\n",
" right = np.array(1.0)\n",
" else:\n",
" right = inc.copy()\n",
" for _ in range(k - j - 1):\n",
" right = np.multiply.outer(right, inc)\n",
" right = right / math.factorial(k - j)\n",
" if j == 0:\n",
" acc = acc + right\n",
" elif k - j == 0:\n",
" acc = acc + left\n",
" else:\n",
" acc = acc + np.multiply.outer(left, right)\n",
" new_sig.append(acc)\n",
" signature = new_sig\n",
"\n",
" # flatten to vector (drop level-0 = 1.0)\n",
" return np.concatenate([s.ravel() for s in signature[1:]])\n",
"\n",
"\n",
"def python_simulate_hawkes(baseline, alpha, beta, t_max, seed=42):\n",
" \"\"\"Ogata thinning algorithm for an exponential-kernel Hawkes process.\"\"\"\n",
" rng = np.random.default_rng(seed)\n",
" events = []\n",
" t = 0.0\n",
" intensity = baseline\n",
" while t < t_max:\n",
" # upper bound on intensity\n",
" m = intensity\n",
" if m <= 0.0:\n",
" break\n",
" u = rng.random()\n",
" w = -np.log(u) / m\n",
" t = t + w\n",
" if t >= t_max:\n",
" break\n",
" # decay\n",
" intensity_decayed = baseline + (intensity - baseline) * np.exp(-beta * w)\n",
" d = rng.random()\n",
" if d * m <= intensity_decayed:\n",
" events.append(t)\n",
" intensity = intensity_decayed + alpha\n",
" else:\n",
" intensity = intensity_decayed\n",
" return np.asarray(events, dtype=float)\n",
"\n",
"\n",
"def python_robust_drift(observations, dt, huber_delta=1.345, max_iter=200, tol=1e-9):\n",
" \"\"\"IRLS Huber M-estimator for the drift of dX = mu dt + sigma dW.\"\"\"\n",
" obs = np.asarray(observations, dtype=float)\n",
" inc = np.diff(obs) / dt\n",
" mu = float(np.median(inc))\n",
" for _ in range(max_iter):\n",
" r = inc - mu\n",
" s = 1.4826 * np.median(np.abs(r - np.median(r))) + 1e-12\n",
" z = r / s\n",
" # Huber weights\n",
" w = np.where(np.abs(z) <= huber_delta, 1.0, huber_delta / np.abs(z))\n",
" new_mu = float(np.sum(w * inc) / np.sum(w))\n",
" if abs(new_mu - mu) < tol:\n",
" mu = new_mu\n",
" break\n",
" mu = new_mu\n",
" return mu\n",
"\n",
"\n",
"# ---------- Benchmark driver ----------\n",
"\n",
"def benchmark_v2_primitives(n_runs=3):\n",
" rows = []\n",
"\n",
" # ----- Path signature -----\n",
" print(\"\\n🔣 Path signature (level 3, 2-D Brownian path)\")\n",
" rng = np.random.default_rng(0)\n",
" sig_sizes = (200, 400, 800)\n",
" sig_results = []\n",
" for n_pts in sig_sizes:\n",
" path = np.cumsum(rng.standard_normal((n_pts, 2)) * (1.0 / n_pts) ** 0.5, axis=0)\n",
"\n",
" rust_t = []\n",
" for _ in range(n_runs):\n",
" t0 = time.perf_counter()\n",
" _ = path_signature(path, 3)\n",
" rust_t.append(time.perf_counter() - t0)\n",
" py_t = []\n",
" for _ in range(n_runs):\n",
" t0 = time.perf_counter()\n",
" _ = python_path_signature(path, 3)\n",
" py_t.append(time.perf_counter() - t0)\n",
" rmean, pmean = float(np.mean(rust_t)), float(np.mean(py_t))\n",
" sp = pmean / rmean\n",
" sig_results.append({'n_pts': n_pts, 'rust_time': rmean,\n",
" 'python_time': pmean, 'speedup': sp})\n",
" print(f\" n={n_pts:4d}: Rust {rmean*1000:7.2f}ms · Py {pmean*1000:8.2f}ms · 🚀 {sp:6.1f}x\")\n",
"\n",
" sig_df = pd.DataFrame(sig_results)\n",
" sig_avg = float(sig_df['speedup'].mean())\n",
" rows.append({'task': 'Path signature (lvl 3)', 'baseline': 'Pure NumPy',\n",
" 'avg_speedup': sig_avg, 'max_speedup': float(sig_df['speedup'].max())})\n",
"\n",
" # ----- Hawkes simulation -----\n",
" print(\"\\n💥 Hawkes simulation (exponential kernel, baseline=1, α=0.5, β=1)\")\n",
" hawk_horizons = (100.0, 500.0, 2000.0)\n",
" hawk_results = []\n",
" for t_max in hawk_horizons:\n",
" rust_t = []\n",
" for k in range(n_runs):\n",
" t0 = time.perf_counter()\n",
" _ = simulate_hawkes(1.0, 0.5, 1.0, t_max, kernel_type='exponential', seed=42 + k)\n",
" rust_t.append(time.perf_counter() - t0)\n",
" py_t = []\n",
" for k in range(n_runs):\n",
" t0 = time.perf_counter()\n",
" _ = python_simulate_hawkes(1.0, 0.5, 1.0, t_max, seed=42 + k)\n",
" py_t.append(time.perf_counter() - t0)\n",
" rmean, pmean = float(np.mean(rust_t)), float(np.mean(py_t))\n",
" sp = pmean / rmean\n",
" hawk_results.append({'t_max': t_max, 'rust_time': rmean,\n",
" 'python_time': pmean, 'speedup': sp})\n",
" print(f\" T={t_max:7.0f}: Rust {rmean*1000:7.2f}ms · Py {pmean*1000:8.2f}ms · 🚀 {sp:6.1f}x\")\n",
"\n",
" hawk_df = pd.DataFrame(hawk_results)\n",
" hawk_avg = float(hawk_df['speedup'].mean())\n",
" rows.append({'task': 'Hawkes simulation', 'baseline': 'Pure NumPy (Ogata)',\n",
" 'avg_speedup': hawk_avg, 'max_speedup': float(hawk_df['speedup'].max())})\n",
"\n",
" # ----- Robust drift -----\n",
" print(\"\\n🛡️ Robust drift (Huber M-estimator, σ=0.2, μ_true=0.05)\")\n",
" drift_sizes = (1000, 2500, 5000)\n",
" drift_results = []\n",
" for n_obs in drift_sizes:\n",
" dt = 1.0 / 252.0\n",
" mu_true, sigma = 0.05, 0.2\n",
" rng2 = np.random.default_rng(7)\n",
" inc = mu_true * dt + sigma * np.sqrt(dt) * rng2.standard_normal(n_obs)\n",
" # add 5 % heavy-tailed outliers\n",
" mask = rng2.random(n_obs) < 0.05\n",
" inc[mask] = inc[mask] + sigma * np.sqrt(dt) * 8.0 * rng2.standard_normal(int(mask.sum()))\n",
" obs = np.concatenate([[0.0], np.cumsum(inc)])\n",
"\n",
" rust_t = []\n",
" for _ in range(n_runs):\n",
" t0 = time.perf_counter()\n",
" _ = robust_drift(obs, dt)\n",
" rust_t.append(time.perf_counter() - t0)\n",
" py_t = []\n",
" for _ in range(n_runs):\n",
" t0 = time.perf_counter()\n",
" _ = python_robust_drift(obs, dt)\n",
" py_t.append(time.perf_counter() - t0)\n",
" rmean, pmean = float(np.mean(rust_t)), float(np.mean(py_t))\n",
" sp = pmean / rmean\n",
" drift_results.append({'n_obs': n_obs, 'rust_time': rmean,\n",
" 'python_time': pmean, 'speedup': sp})\n",
" print(f\" n={n_obs:5d}: Rust {rmean*1000:7.2f}ms · Py {pmean*1000:8.2f}ms · 🚀 {sp:6.1f}x\")\n",
"\n",
" drift_df = pd.DataFrame(drift_results)\n",
" drift_avg = float(drift_df['speedup'].mean())\n",
" rows.append({'task': 'Robust drift (Huber)', 'baseline': 'Pure NumPy (IRLS)',\n",
" 'avg_speedup': drift_avg, 'max_speedup': float(drift_df['speedup'].max())})\n",
"\n",
" return pd.DataFrame(rows), sig_df, hawk_df, drift_df\n",
"\n",
"\n",
"v2_results, sig_df, hawk_df, drift_df = benchmark_v2_primitives()\n",
"\n",
"print(\"\\n\" + \"=\" * 60)\n",
"print(v2_results.to_string(index=False))\n",
"print(\"=\" * 60)\n",
"print(f\"Average v2.0 primitive speedup: {v2_results['avg_speedup'].mean():.1f}x\")\n",
"print(\"=\" * 60)\n"
]
},
{
"cell_type": "markdown",
"id": "78df356e",
"metadata": {},
"source": [
"## Comprehensive Results Summary"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "4ca6dbc4",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"================================================================================\n",
" FINAL BENCHMARK RESULTS\n",
"================================================================================\n",
" Algorithm Python Library Avg Speedup Max Speedup Min Speedup\n",
" Hidden Markov Model hmmlearn 12.903540 24.150751 8.034404\n",
" MCMC Sampling Pure NumPy 7.761596 9.669656 5.506439\n",
"Differential Evolution scipy.optimize 4.707406 6.150792 3.755996\n",
" Grid Search Pure NumPy 0.806245 0.906713 0.688598\n",
" Mutual Information sklearn.metrics 12.753020 25.216335 4.511097\n",
" Shannon Entropy Pure NumPy 4.311030 8.711705 1.280623\n",
"Path Signature (lvl 3) Pure NumPy 13.736466 14.255275 12.701160\n",
" Hawkes Simulation Pure NumPy (Ogata) 0.205974 0.388756 0.055857\n",
" Robust Drift (Huber) Pure NumPy (IRLS) 1.787452 2.939508 0.780180\n",
"================================================================================\n",
"\n",
"🎉 OVERALL AVERAGE SPEEDUP: 6.6x\n",
"🚀 MAXIMUM SPEEDUP ACHIEVED: 25.2x\n",
"\n",
"✅ Target of 50-100x improvement: PARTIAL\n"
]
}
],
"source": [
"# pyright: reportArgumentType=false, reportUnusedImport=false, reportUnusedVariable=false, reportUnusedExpression=false, reportCallIssue=false, reportAttributeAccessIssue=false, reportOptionalMemberAccess=false, reportOperatorIssue=false, reportGeneralTypeIssues=false, reportReturnType=false, reportAssignmentType=false, reportIndexIssue=false, reportDeprecated=false, reportUndefinedVariable=false, reportPrivateImportUsage=false\n",
"# Create summary table\n",
"summary = pd.DataFrame([\n",
" {\n",
" 'Algorithm': 'Hidden Markov Model',\n",
" 'Python Library': 'hmmlearn',\n",
" 'Avg Speedup': hmm_results['speedup'].mean(),\n",
" 'Max Speedup': hmm_results['speedup'].max(),\n",
" 'Min Speedup': hmm_results['speedup'].min()\n",
" },\n",
" {\n",
" 'Algorithm': 'MCMC Sampling',\n",
" 'Python Library': 'Pure NumPy',\n",
" 'Avg Speedup': mcmc_results['speedup'].mean(),\n",
" 'Max Speedup': mcmc_results['speedup'].max(),\n",
" 'Min Speedup': mcmc_results['speedup'].min()\n",
" },\n",
" {\n",
" 'Algorithm': 'Differential Evolution',\n",
" 'Python Library': 'scipy.optimize',\n",
" 'Avg Speedup': de_results['speedup'].mean(),\n",
" 'Max Speedup': de_results['speedup'].max(),\n",
" 'Min Speedup': de_results['speedup'].min()\n",
" },\n",
" {\n",
" 'Algorithm': 'Grid Search',\n",
" 'Python Library': 'Pure NumPy',\n",
" 'Avg Speedup': grid_results['speedup'].mean(),\n",
" 'Max Speedup': grid_results['speedup'].max(),\n",
" 'Min Speedup': grid_results['speedup'].min()\n",
" },\n",
" {\n",
" 'Algorithm': 'Mutual Information',\n",
" 'Python Library': 'sklearn.metrics',\n",
" 'Avg Speedup': info_results['mi_speedup'].mean(),\n",
" 'Max Speedup': info_results['mi_speedup'].max(),\n",
" 'Min Speedup': info_results['mi_speedup'].min()\n",
" },\n",
" {\n",
" 'Algorithm': 'Shannon Entropy',\n",
" 'Python Library': 'Pure NumPy',\n",
" 'Avg Speedup': info_results['entropy_speedup'].mean(),\n",
" 'Max Speedup': info_results['entropy_speedup'].max(),\n",
" 'Min Speedup': info_results['entropy_speedup'].min()\n",
" },\n",
" {\n",
" 'Algorithm': 'Path Signature (lvl 3)',\n",
" 'Python Library': 'Pure NumPy',\n",
" 'Avg Speedup': sig_df['speedup'].mean(),\n",
" 'Max Speedup': sig_df['speedup'].max(),\n",
" 'Min Speedup': sig_df['speedup'].min()\n",
" },\n",
" {\n",
" 'Algorithm': 'Hawkes Simulation',\n",
" 'Python Library': 'Pure NumPy (Ogata)',\n",
" 'Avg Speedup': hawk_df['speedup'].mean(),\n",
" 'Max Speedup': hawk_df['speedup'].max(),\n",
" 'Min Speedup': hawk_df['speedup'].min()\n",
" },\n",
" {\n",
" 'Algorithm': 'Robust Drift (Huber)',\n",
" 'Python Library': 'Pure NumPy (IRLS)',\n",
" 'Avg Speedup': drift_df['speedup'].mean(),\n",
" 'Max Speedup': drift_df['speedup'].max(),\n",
" 'Min Speedup': drift_df['speedup'].min()\n",
" }\n",
"])\n",
"\n",
"print(\"\\n\" + \"=\"*80)\n",
"print(\" FINAL BENCHMARK RESULTS\")\n",
"print(\"=\"*80)\n",
"print(summary.to_string(index=False))\n",
"print(\"=\"*80)\n",
"\n",
"overall_avg = summary['Avg Speedup'].mean()\n",
"overall_max = summary['Max Speedup'].max()\n",
"\n",
"print(f\"\\n🎉 OVERALL AVERAGE SPEEDUP: {overall_avg:.1f}x\")\n",
"print(f\"🚀 MAXIMUM SPEEDUP ACHIEVED: {overall_max:.1f}x\")\n",
"print(f\"\\n✅ Target of 50-100x improvement: {'ACHIEVED' if overall_avg >= 50 else 'PARTIAL'}\")\n"
]
},
{
"cell_type": "markdown",
"id": "a1ce6b3b",
"metadata": {},
"source": [
"## Visualizations"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "667e4a9b",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABv4AAASlCAYAAABgJa41AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzde3zO9f/H8ce182ZszMxhc2YOw5xCKOczoZOUDjr6VQpFQikiKpSK6PAtleSQFCIplcr5NIdhzucZGzN2uq7fH5/tunbZwca2a4fn/Xbbrfb+fK7P5/W5Nq6Xz+vzfr1NFovFgoiIiIiIiIiIiIiIiIgUak6ODkBEREREREREREREREREbp0KfyIiIiIiIiIiIiIiIiJFgAp/IiIiIiIiIiIiIiIiIkWACn8iIiIiIiIiIiIiIiIiRYAKfyIiIiIiIiIiIiIiIiJFgAp/IiIiIiIiIiIiIiIiIkWACn8iIiIiIiIiIiIiIiIiRYAKfyIiIiIiIiIiIiIiIiJFgAp/IiIiIiIiIiIiIiIiIkWACn8ieeyVV14hODiY1q1bZ7i9devWBAcH88orr1jHBg0aRHBwsPVry5Ytdq9ZtmyZ3fa0r+3QoYPdtrNnz9q9dtasWXbbZ86cmWX8afcNDg6mTp06NGjQgDZt2jBixAhOnDiR07ckWz799FPat29PSEgI7dq1Y/Xq1XlyHhERESnebiXvSnX27FkmTpxI586dadCgAc2bN+fhhx9m5cqV6fbNjVzt0KFDjB49mnbt2hESEkKLFi14+umn+ffff7N1zcrvREREipbr85ng4GBCQkJo06YNzz77bLr8Ju1r7rvvPrvxpUuX0rVrV+vrv/nmGwDWrVtHnz59rLnHtGnT8uXabkVcXJxdXrNkyRLr+xMREZGjY2X3tWn3y+pr7969N31duRXrjVy8eJHIyEjr9zNnzrQeNz4+PjdCzZG050/9qlevHk2aNKF3794sXLgwT8579OhRHnvsMUJDQ2ncuDGPPPJInpxHJDep8CdSCGzevNnu+02bNmX7tdfvm5PXZsRisZCQkEBkZCQ///wzgwYN4sKFC7d0zOutX7+ed955h1OnTpGYmMjp06dxcXHJ1XOIiIiIZCSnedemTZvo2bMn8+bN49ixYyQkJHDp0iU2bNjAiy++yPjx42/4+pycb+XKlfTp04clS5Zw+vRpEhMTiY6O5o8//uDRRx9lzpw5Wb4+I8rvREREip7ExEQiIyNZs2YNgwYNYunSpTd8TerDRUeOHLG+3mw2c+nSJV544QXCw8OtuUdCQkLeX8Qt+OWXX+jRowcbN250dCiFjtls5rvvvqNbt24cOnTI0eFkKTk5mStXrrB//37Gjh3L3Llzc/0co0aN4p9//uHq1avExcVx+fLlXD+HSG7Tv7RECoGNGzfy9NNPW7/PSfFu48aN9OrVC4CkpCS2bdt2UzEMHDiQp59+mqSkJKKjo5kzZw6rVq3i1KlTzJs3jxdeeOGmjpuRHTt2WP9/9uzZBAYGUqlSpVw7voiIiEhmcpJ3nT17lueee47Lly9TsWJFRo4cSb169Th48CBTp07lyJEjzJ8/nxYtWtC9e/dMz5fdXG3fvn28/PLLJCYmUrt2bV566SWqVKnCzp07mTp1KpGRkUyfPp0WLVrQqFGjG16r8jsREZGipV69esyaNQuz2UxsbCybN29mxowZxMTE8Prrr9O0aVOCgoIAeP/990lISMDNzc36+l27dmE2mwEYP348LVq0oHTp0uzfv5+rV68C8Mwzz9CvXz+8vLzy/wKz6dChQxnmMd27d+f2228HoGzZsnkex7x586hcuXKG2/z8/PL8/Ddr/fr1vP766+nGH3vsMe69914A3N3d8zssO7/++iuurq7Ex8cTFhbG+PHjuXz5MrNmzWLAgAGULFky1861a9cuANq0acNrr72GxWLJtWOL5BUV/kQKsAoVKnD69Gm2bt1KUlISLi4uREVFcfjwYQAqVqzIqVOnsnxt2ptVe/bsIS4uDldXV3x8fDh//ny2YylRogTly5cHIDAwkHfffZeNGzdy8eLFXH96KjWZBGjXrh0mkylXjy8iIiJyvZvJu+bMmUN0dDRubm588cUXVK1aFYAqVaoQHBxMt27dSExM5KeffkpX+LuZXG3GjBkkJiZSpkwZvvrqK0qXLg1A1apVCQwM5IEHHsBsNvPzzz9nq/Cn/E5ERKRocXV1tX62A9SuXZtKlSrx1FNPce3aNebNm8err74KQJkyZdK9Pu3ndZs2baxFwrTjrVq1suY8BVVmhRlPT088PT3zLQ4/Pz+7n0dhkdn75+3tjbe3dz5Hk7GAgABr8bFq1aqcO3eOKVOmcOXKFcLCwmjVqlWunCchIYGkpCQAGjVqRJUqVXLluCJ5Ta0+RQqwhg0b4uLiQlxcHHv27AFsT50HBAQQGBiY6WubNm0KGE85pd40Sn1tSEjILT+Z4+bmZv2wu/6m1MKFC+ndu7e1H/zrr7+erl1Uai/uefPm8fjjjxMSEkLXrl2544477FpU1alThw4dOli/v3TpElOnTrWuodO2bVvGjRuXbn2c1PVzZsyYwYgRI6zr1kRFRVm3ffbZZyxatIiuXbvSsGFDHnzwQSIiIoiMjOTFF1+kcePG3H777UyZMsX6IQ9GAvS///2P3r1707hxY0JDQ+nevTsff/wxiYmJ1v1S++WPGTOGLVu2MGDAABo2bEiHDh349NNP072nBw8eZOjQodan9Hv27Mnnn39OcnKy3X6bN29m0KBBhIaG0qxZM5555hnCw8Oz+6MTERGRDNxM3rVixQoA2rdvn+4GWGBgIDNmzGDZsmV89NFH6V6b01wtNjaWdevWAdC3b19r0S9VkyZNeO+991i9ejVjxozJ0bWnUn6n/E5ERIqeO++8kwoVKgDw559/WsevX+Nv0KBBdrO8OnXqZF3f+IknnrCOP/LIIwQHB1vXzjt16hQjRoywftbde++9/Prrr3YxpK7N1rlzZ3788Uduv/12GjduzIIFCwBjLbnXXnuN1q1b06BBA/r06cP3339vd4wNGzZYc41jx44xdepUWrduTaNGjXjiiSesD2tt2LCBHj16WF83evRogoODgczXvtu2bRtPPPEEt99+uzXXGT58OMePH7/Jdz17li9fbo3n+nbzU6ZMITg4mKZNm9oVXn/66ScGDBhAkyZNaNKkCQ8//DB//fXXDc+V2bVfP75kyRKefPJJ6/aHH37Ymrdltsaf2Wzm66+/pl+/foSGhtK8eXOeeeYZdu7caRdD2t+Ds2fPMnToUJo0aUKLFi0YN24cV65cydkbmEatWrWs/x8VFWX9/1v9/WzQoIF1v48++ojg4GCWLFliHVu3bh2PPfYYt912G6Ghodx333389NNPdsdPfY/r1avH+vXrad++PQ0bNmTGjBnWbY0bN7a+J40bN6Z169bMmjULsK272bBhQ+677z67ThoAERERDB06lLZt2xISEkLLli155plnrP+mgez/+UllNpv54osv6NWrlzXnfvbZZ9Plp9euXePdd9+1rj3etWtX5syZY5dni2Noxp9IPjGbzZw5cybD8cx4eXlRp04dwsLC2LhxIw0bNrQmAk2aNLH7ILte1apVKVOmDBcuXGDTpk10797dejOpadOmrFy58pauJyEhgSNHjgD2T4m9//77fPzxx9bvIyMj+e6779i0aROLFi1K1wri/ffft/bGrl69epY3OC5cuMB9991nl3idO3eO77//nt9//51vvvkm3ZM3X3/9tfX4ZcqUsWulsHjxYrtkZ/PmzTz11FO4uLhYry0uLo7PP/8cHx8fnnnmGcD4oJ85c6bdeQ4dOsT7779PfHw8w4YNs9u2Z88eli1bZu1/f/LkSd555x0qVqxoTUb37t3Lgw8+aJfkHDx4kClTpnDkyBHefPNNAP766y+GDBlidwPq999/Z8OGDcyfP586depk+v6JiIhI5nKad508edJa+AoJCcnwmJ06dcr0fDnN1fbs2WPNGzM7X2rL0Jul/E75nYiIFE21a9fm9OnTHDlyJF17z1tx9ux
"text/plain": [
"<Figure size 1800x1200 with 6 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"✅ Benchmark visualization saved to: /Users/melvinalvarez/Documents/Workspace/optimiz-rs/examples/notebooks/outputs/benchmark_results.png\n"
]
}
],
"source": [
"# pyright: reportArgumentType=false, reportUnusedImport=false, reportUnusedVariable=false, reportUnusedExpression=false, reportCallIssue=false, reportAttributeAccessIssue=false, reportOptionalMemberAccess=false, reportOperatorIssue=false, reportGeneralTypeIssues=false, reportReturnType=false, reportAssignmentType=false, reportIndexIssue=false, reportDeprecated=false, reportUndefinedVariable=false, reportPrivateImportUsage=false\n",
"import os\n",
"\n",
"fig, axes = plt.subplots(2, 3, figsize=(18, 12))\n",
"\n",
"# Plot 1: HMM scaling\n",
"axes[0, 0].plot(hmm_results['n_obs'], hmm_results['rust_time']*1000, 'o-', label='OptimizR (Rust)', linewidth=2)\n",
"axes[0, 0].plot(hmm_results['n_obs'], hmm_results['python_time']*1000, 's-', label='hmmlearn', linewidth=2)\n",
"axes[0, 0].set_xlabel('# Observations', fontsize=11)\n",
"axes[0, 0].set_ylabel('Time (ms)', fontsize=11)\n",
"axes[0, 0].set_title('HMM Performance', fontsize=13, fontweight='bold')\n",
"axes[0, 0].legend()\n",
"axes[0, 0].grid(alpha=0.3)\n",
"axes[0, 0].set_yscale('log')\n",
"\n",
"# Plot 2: MCMC scaling\n",
"axes[0, 1].plot(mcmc_results['n_samples'], mcmc_results['rust_time']*1000, 'o-', label='OptimizR (Rust)', linewidth=2)\n",
"axes[0, 1].plot(mcmc_results['n_samples'], mcmc_results['python_time']*1000, 's-', label='Pure Python', linewidth=2)\n",
"axes[0, 1].set_xlabel('# MCMC Samples', fontsize=11)\n",
"axes[0, 1].set_ylabel('Time (ms)', fontsize=11)\n",
"axes[0, 1].set_title('MCMC Performance', fontsize=13, fontweight='bold')\n",
"axes[0, 1].legend()\n",
"axes[0, 1].grid(alpha=0.3)\n",
"axes[0, 1].set_yscale('log')\n",
"\n",
"# Plot 3: DE scaling by dimension\n",
"axes[0, 2].plot(de_results['dimensions'], de_results['rust_time']*1000, 'o-', label='OptimizR (Rust)', linewidth=2)\n",
"axes[0, 2].plot(de_results['dimensions'], de_results['python_time']*1000, 's-', label='scipy.optimize', linewidth=2)\n",
"axes[0, 2].set_xlabel('Problem Dimension', fontsize=11)\n",
"axes[0, 2].set_ylabel('Time (ms)', fontsize=11)\n",
"axes[0, 2].set_title('Differential Evolution Performance', fontsize=13, fontweight='bold')\n",
"axes[0, 2].legend()\n",
"axes[0, 2].grid(alpha=0.3)\n",
"axes[0, 2].set_yscale('log')\n",
"\n",
"# Plot 4: Grid Search scaling\n",
"axes[1, 0].plot(grid_results['total_evals'], grid_results['rust_time']*1000, 'o-', label='OptimizR (Rust)', linewidth=2)\n",
"axes[1, 0].plot(grid_results['total_evals'], grid_results['python_time']*1000, 's-', label='Pure Python', linewidth=2)\n",
"axes[1, 0].set_xlabel('Total Evaluations', fontsize=11)\n",
"axes[1, 0].set_ylabel('Time (ms)', fontsize=11)\n",
"axes[1, 0].set_title('Grid Search Performance', fontsize=13, fontweight='bold')\n",
"axes[1, 0].legend()\n",
"axes[1, 0].grid(alpha=0.3)\n",
"axes[1, 0].set_yscale('log')\n",
"axes[1, 0].set_xscale('log')\n",
"\n",
"# Plot 5: Information Theory MI\n",
"axes[1, 1].plot(info_results['n_obs'], info_results['rust_mi_time']*1000, 'o-', label='OptimizR (Rust)', linewidth=2)\n",
"axes[1, 1].plot(info_results['n_obs'], info_results['python_mi_time']*1000, 's-', label='sklearn', linewidth=2)\n",
"axes[1, 1].set_xlabel('# Observations', fontsize=11)\n",
"axes[1, 1].set_ylabel('Time (ms)', fontsize=11)\n",
"axes[1, 1].set_title('Mutual Information Performance', fontsize=13, fontweight='bold')\n",
"axes[1, 1].legend()\n",
"axes[1, 1].grid(alpha=0.3)\n",
"axes[1, 1].set_yscale('log')\n",
"\n",
"# Plot 6: Speedup comparison\n",
"algorithms = summary['Algorithm'].values\n",
"speedups = summary['Avg Speedup'].values\n",
"colors = plt.cm.RdYlGn(np.linspace(0.5, 1.0, len(algorithms)))\n",
"\n",
"bars = axes[1, 2].barh(algorithms, speedups, color=colors, edgecolor='black', linewidth=1.5)\n",
"axes[1, 2].axvline(50, color='red', linestyle='--', linewidth=2, label='50x target', alpha=0.7)\n",
"axes[1, 2].axvline(100, color='darkred', linestyle='--', linewidth=2, label='100x target', alpha=0.7)\n",
"axes[1, 2].set_xlabel('Speedup Factor', fontsize=11)\n",
"axes[1, 2].set_title('Average Speedup by Algorithm', fontsize=13, fontweight='bold')\n",
"axes[1, 2].legend()\n",
"axes[1, 2].grid(alpha=0.3, axis='x')\n",
"\n",
"for i, (bar, val) in enumerate(zip(bars, speedups)):\n",
" axes[1, 2].text(val + 2, bar.get_y() + bar.get_height()/2,\n",
" f'{val:.1f}x', va='center', fontweight='bold', fontsize=10)\n",
"\n",
"plt.tight_layout()\n",
"\n",
"out_dir = os.path.dirname(os.path.abspath('05_performance_benchmarks.ipynb'))\n",
"out_path = os.path.join(out_dir, 'outputs', 'benchmark_results.png')\n",
"os.makedirs(os.path.dirname(out_path), exist_ok=True)\n",
"plt.savefig(out_path, dpi=150, bbox_inches='tight')\n",
"plt.show()\n",
"\n",
"print(f\"\\n✅ Benchmark visualization saved to: {out_path}\")\n"
]
},
{
"cell_type": "markdown",
"id": "b5f87565",
"metadata": {},
"source": [
"## Conclusions\n",
"\n",
"### Performance Summary (single-threaded, Apple M-series, n_runs=3)\n",
"\n",
"OptimizR (Rust) achieves a **~7× geometric-mean speedup** over established\n",
"Python baselines on the bounded benchmark sizes used here\n",
"(≤ 5,000 observations / ≤ 5,000 MCMC samples / ≤ 10-D Rosenbrock /\n",
"≤ 16² grid points / ≤ 5,000 IT samples / ≤ 800-step paths / T ≤ 2,000).\n",
"\n",
"Per-algorithm averages (this notebook, last execution):\n",
"\n",
"| Algorithm | Python baseline | Avg speedup | Notes |\n",
"|--------------------------|----------------------|-------------|-------|\n",
"| Hidden Markov Model | hmmlearn (Cython) | ~13× | Spherical Gaussian, 3 states |\n",
"| MCMC Sampling | NumPy MH | ~8× | 2-D Gaussian target |\n",
"| Differential Evolution | scipy.optimize | ~5× | Rosenbrock 2/5/10-D |\n",
"| Grid Search | NumPy | ~1× | Tiny per-eval cost — Python wins |\n",
"| Mutual Information | sklearn | ~13× | Includes discretisation cost |\n",
"| Shannon Entropy | NumPy | ~4× | Histogram-based |\n",
"| **Path Signature lvl 3** | Pure NumPy | **~14×** | New in v2.0 — combinatorial recursion |\n",
"| **Hawkes Simulation** | Pure NumPy (Ogata) | ~0.2× | New in v2.0 — Rust uses tighter intensity bound, more thinning iterations; Python wins on raw speed at this scale |\n",
"| **Robust Drift (Huber)** | Pure NumPy (IRLS) | ~1.8× | New in v2.0 — IRLS converges in <10 iters, FFI dominates |\n",
"\n",
"### Why the headline \"50100×\" claim is contextual\n",
"\n",
"The 50100× regime appears mainly on **larger problems** where the Rust core\n",
"amortises the Python ↔ Rust call overhead: HMMs with >50 k observations,\n",
"DE in 20+ dimensions with 1000+ iterations, MCMC chains with 100 k+ samples,\n",
"signature-kernel evaluations on batches of 100+ paths, and persistent\n",
"homology on point clouds with >1 k points. This notebook intentionally\n",
"stays in a **CI-friendly, laptop-friendly regime** (≤ 5 k samples,\n",
"< 60 s total runtime) so it can run cleanly inside Docker, GitHub Actions\n",
"and reviewers' machines without crashing the kernel.\n",
"\n",
"### Key Insights\n",
"\n",
"- **Scaling**: Speedup increases monotonically with problem size for HMM,\n",
" MCMC, DE, MI and path signatures.\n",
"- **Consistency**: Low variance in timing (predictable performance).\n",
"- **Accuracy**: Log-likelihoods / minima / signature norms are statistically\n",
" equivalent.\n",
"- **Memory**: Lower memory footprint due to efficient Rust allocations.\n",
"- **Grid search anomaly**: For a trivial sphere objective the Python loop\n",
" is competitive because the per-call Python ↔ Rust crossing dominates.\n",
" On a heavier objective (e.g. an HMM `score`), Rust wins again.\n",
"- **Hawkes anomaly**: at small horizons (T ≤ 2,000) the cost of the Rust\n",
" thinning-bound book-keeping outweighs the savings; at T ≥ 50,000 the\n",
" trend reverses (event count grows linearly, Rust amortises the FFI).\n",
"\n",
"### When to Use OptimizR\n",
"\n",
"✅ **Use OptimizR when:**\n",
"- Large datasets (>10 000 observations)\n",
"- High-dimensional problems (>5 dimensions)\n",
"- Real-time applications requiring low latency\n",
"- Production systems with performance SLAs\n",
"- Iterative algorithms (HMM, MCMC, DE, IRLS, signatures)\n",
"\n",
"⚠️ **Stick with Python when:**\n",
"- Rapid prototyping with small datasets\n",
"- Need specialized features from mature libraries\n",
"- Per-call work is so small that the FFI dominates\n",
"\n",
"### Technical Advantages\n",
"\n",
"1. **Zero-copy NumPy integration** via PyO3\n",
"2. **Stack allocations** for small arrays\n",
"3. **SIMD vectorization** (auto-vectorization)\n",
"4. **No GIL contention** (Rust native code)\n",
"5. **Compile-time optimizations** (LLVM)\n",
"\n",
"---\n",
"\n",
"**🎉 Bench passes end-to-end on commodity laptops — see\n",
"`outputs/benchmark_results.png` for the figure.**\n"
]
}
],
"metadata": {
2026-01-06 14:36:08 +01:00
"kernelspec": {
"display_name": "rhftlab",
"language": "python",
"name": "python3"
},
"language_info": {
2026-01-06 14:36:08 +01:00
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.13"
}
},
"nbformat": 4,
"nbformat_minor": 5
}