code formatting
24 changed files+612−453
web-ui/package-lock.jsonmodified+16−0View file
@@ -28,6 +28,7 @@
2828 "eslint-plugin-react-refresh": "^0.4.16",
2929 "globals": "^15.14.0",
3030 "postcss": "^8.5.1",
31+ "prettier": "^3.4.2",
3132 "tailwindcss": "^4.0.0",
3233 "typescript": "~5.6.2",
3334 "typescript-eslint": "^8.18.2",
@@ -5214,6 +5215,21 @@
52145215 "node": ">= 0.8.0"
52155216 }
52165217 },
5218+ "node_modules/prettier": {
5219+ "version": "3.4.2",
5220+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz",
5221+ "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==",
5222+ "dev": true,
5223+ "bin": {
5224+ "prettier": "bin/prettier.cjs"
5225+ },
5226+ "engines": {
5227+ "node": ">=14"
5228+ },
5229+ "funding": {
5230+ "url": "https://github.com/prettier/prettier?sponsor=1"
5231+ }
5232+ },
52175233 "node_modules/probe-image-size": {
52185234 "version": "7.2.3",
52195235 "resolved": "https://registry.npmjs.org/probe-image-size/-/probe-image-size-7.2.3.tgz",
web-ui/package.jsonmodified+3−1View file
@@ -7,7 +7,8 @@
77 "dev": "vite",
88 "build": "tsc -b && vite build",
99 "lint": "eslint .",
10- "preview": "vite preview"
10+ "preview": "vite preview",
11+ "format": "prettier --write \"src/**/*.{ts,tsx,js,jsx}\""
1112 },
1213 "dependencies": {
1314 "@tanstack/react-table": "^8.20.6",
@@ -30,6 +31,7 @@
3031 "eslint-plugin-react-refresh": "^0.4.16",
3132 "globals": "^15.14.0",
3233 "postcss": "^8.5.1",
34+ "prettier": "^3.4.2",
3335 "tailwindcss": "^4.0.0",
3436 "typescript": "~5.6.2",
3537 "typescript-eslint": "^8.18.2",
web-ui/src/App.tsxmodified+18−13View file
@@ -1,21 +1,26 @@
1-import { BenchmarkTable } from './components/BenchmarkTable';
1+import { BenchmarkTable } from "./components/BenchmarkTable";
22
33 function App() {
44 return (
5- <div style={{ padding: '2rem' }}>
6- <header style={{ marginBottom: '2rem' }}>
7- <h1 style={{
8- fontSize: '2rem',
9- fontWeight: 'bold',
10- color: '#333'
11- }}>
5+ <div style={{ padding: "2rem" }}>
6+ <header style={{ marginBottom: "2rem" }}>
7+ <h1
8+ style={{
9+ fontSize: "2rem",
10+ fontWeight: "bold",
11+ color: "#333",
12+ }}
13+ >
1214 ZIA Integer Compression Benchmark
1315 </h1>
14- <p style={{
15- color: '#666',
16- marginTop: '0.5rem'
17- }}>
18- Comparing different integer array compression algorithms and their performance
16+ <p
17+ style={{
18+ color: "#666",
19+ marginTop: "0.5rem",
20+ }}
21+ >
22+ Comparing different integer array compression algorithms and their
23+ performance
1924 </p>
2025 </header>
2126 <main>
web-ui/src/components/BenchmarkTable.tsxmodified+1−1View file
@@ -1 +1 @@
1-export { BenchmarkTable } from './benchmark/table/BenchmarkTable';
1+export { BenchmarkTable } from "./benchmark/table/BenchmarkTable";
web-ui/src/components/benchmark/charts/BenchmarkCharts.tsxmodified+68−62View file
@@ -1,5 +1,5 @@
1-import Plot from 'react-plotly.js';
2-import { useState } from 'react';
1+import Plot from "react-plotly.js";
2+import { useState } from "react";
33
44 interface ChartData {
55 algorithm: string;
@@ -23,8 +23,8 @@ export function BenchmarkCharts({ chartData }: BenchmarkChartsProps) {
2323
2424 return (
2525 <div>
26- <div style={{ marginBottom: '10px' }}>
27- <label style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
26+ <div style={{ marginBottom: "10px" }}>
27+ <label style={{ display: "flex", alignItems: "center", gap: "8px" }}>
2828 <input
2929 type="checkbox"
3030 checked={sortByRatio}
@@ -33,66 +33,72 @@ export function BenchmarkCharts({ chartData }: BenchmarkChartsProps) {
3333 Sort by compression ratio
3434 </label>
3535 </div>
36- <div style={{ marginBottom: '30px' }}>
37- <div style={{ marginBottom: '20px' }}>
38- <h3 style={{ marginBottom: '10px' }}>Compression Ratio</h3>
39- <Plot
40- data={[{
41- type: 'bar',
42- orientation: 'h',
43- y: sortedData.map(d => d.algorithm),
44- x: sortedData.map(d => d.compression_ratio),
45- marker: { color: '#8884d8' }
46- }]}
47- layout={{
48- width: 800,
49- height: 400,
50- margin: { t: 5, r: 30, l: 120, b: 30 },
51- xaxis: { title: 'Ratio' }
52- }}
53- config={{ displayModeBar: false }}
54- />
55- </div>
36+ <div style={{ marginBottom: "30px" }}>
37+ <div style={{ marginBottom: "20px" }}>
38+ <h3 style={{ marginBottom: "10px" }}>Compression Ratio</h3>
39+ <Plot
40+ data={[
41+ {
42+ type: "bar",
43+ orientation: "h",
44+ y: sortedData.map((d) => d.algorithm),
45+ x: sortedData.map((d) => d.compression_ratio),
46+ marker: { color: "#8884d8" },
47+ },
48+ ]}
49+ layout={{
50+ width: 800,
51+ height: 400,
52+ margin: { t: 5, r: 30, l: 120, b: 30 },
53+ xaxis: { title: "Ratio" },
54+ }}
55+ config={{ displayModeBar: false }}
56+ />
57+ </div>
5658
57- <div style={{ marginBottom: '20px' }}>
58- <h3 style={{ marginBottom: '10px' }}>Encode Speed (MB/s)</h3>
59- <Plot
60- data={[{
61- type: 'bar',
62- orientation: 'h',
63- y: sortedData.map(d => d.algorithm),
64- x: sortedData.map(d => d.encode_speed),
65- marker: { color: '#82ca9d' }
66- }]}
67- layout={{
68- width: 800,
69- height: 400,
70- margin: { t: 5, r: 30, l: 120, b: 30 },
71- xaxis: { title: 'MB/s' }
72- }}
73- config={{ displayModeBar: false }}
74- />
75- </div>
59+ <div style={{ marginBottom: "20px" }}>
60+ <h3 style={{ marginBottom: "10px" }}>Encode Speed (MB/s)</h3>
61+ <Plot
62+ data={[
63+ {
64+ type: "bar",
65+ orientation: "h",
66+ y: sortedData.map((d) => d.algorithm),
67+ x: sortedData.map((d) => d.encode_speed),
68+ marker: { color: "#82ca9d" },
69+ },
70+ ]}
71+ layout={{
72+ width: 800,
73+ height: 400,
74+ margin: { t: 5, r: 30, l: 120, b: 30 },
75+ xaxis: { title: "MB/s" },
76+ }}
77+ config={{ displayModeBar: false }}
78+ />
79+ </div>
7680
77- <div style={{ marginBottom: '20px' }}>
78- <h3 style={{ marginBottom: '10px' }}>Decode Speed (MB/s)</h3>
79- <Plot
80- data={[{
81- type: 'bar',
82- orientation: 'h',
83- y: sortedData.map(d => d.algorithm),
84- x: sortedData.map(d => d.decode_speed),
85- marker: { color: '#ff7300' }
86- }]}
87- layout={{
88- width: 800,
89- height: 400,
90- margin: { t: 5, r: 30, l: 120, b: 30 },
91- xaxis: { title: 'MB/s' }
92- }}
93- config={{ displayModeBar: false }}
94- />
95- </div>
81+ <div style={{ marginBottom: "20px" }}>
82+ <h3 style={{ marginBottom: "10px" }}>Decode Speed (MB/s)</h3>
83+ <Plot
84+ data={[
85+ {
86+ type: "bar",
87+ orientation: "h",
88+ y: sortedData.map((d) => d.algorithm),
89+ x: sortedData.map((d) => d.decode_speed),
90+ marker: { color: "#ff7300" },
91+ },
92+ ]}
93+ layout={{
94+ width: 800,
95+ height: 400,
96+ margin: { t: 5, r: 30, l: 120, b: 30 },
97+ xaxis: { title: "MB/s" },
98+ }}
99+ config={{ displayModeBar: false }}
100+ />
101+ </div>
96102 </div>
97103 </div>
98104 );
web-ui/src/components/benchmark/export/csvExport.tsmodified+37−24View file
@@ -1,34 +1,47 @@
1-import { BenchmarkResult } from '../../../types';
2-import { formatNumber, formatSize } from '../utils/formatters';
3-import { columns } from '../table/columns';
1+import { BenchmarkResult } from "../../../types";
2+import { formatNumber, formatSize } from "../utils/formatters";
3+import { columns } from "../table/columns";
44
5-export const exportToCsv = (data: BenchmarkResult[], selectedDataset: string) => {
5+export const exportToCsv = (
6+ data: BenchmarkResult[],
7+ selectedDataset: string,
8+) => {
69 // Convert data to CSV
7- const headers = columns.map(col => col.header).join(',');
8- const rows = data.map(row =>
9- columns.map(col => {
10- const value = row[col.accessorKey as keyof BenchmarkResult];
11- // Format numbers according to their display format
12- if (col.accessorKey === 'compression_ratio') {
13- return `${formatNumber(value as number)}x`;
14- } else if (col.accessorKey === 'encode_time' || col.accessorKey === 'decode_time') {
15- return formatNumber(value as number, 4);
16- } else if (col.accessorKey === 'original_size' || col.accessorKey === 'compressed_size') {
17- return formatSize(value as number);
18- } else if (typeof value === 'number') {
19- return formatNumber(value);
20- }
21- return value;
22- }).join(',')
23- ).join('\n');
10+ const headers = columns.map((col) => col.header).join(",");
11+ const rows = data
12+ .map((row) =>
13+ columns
14+ .map((col) => {
15+ const value = row[col.accessorKey as keyof BenchmarkResult];
16+ // Format numbers according to their display format
17+ if (col.accessorKey === "compression_ratio") {
18+ return `${formatNumber(value as number)}x`;
19+ } else if (
20+ col.accessorKey === "encode_time" ||
21+ col.accessorKey === "decode_time"
22+ ) {
23+ return formatNumber(value as number, 4);
24+ } else if (
25+ col.accessorKey === "original_size" ||
26+ col.accessorKey === "compressed_size"
27+ ) {
28+ return formatSize(value as number);
29+ } else if (typeof value === "number") {
30+ return formatNumber(value);
31+ }
32+ return value;
33+ })
34+ .join(","),
35+ )
36+ .join("\n");
2437 const csv = `${headers}\n${rows}`;
2538
2639 // Create and trigger download
27- const blob = new Blob([csv], { type: 'text/csv' });
40+ const blob = new Blob([csv], { type: "text/csv" });
2841 const url = window.URL.createObjectURL(blob);
29- const a = document.createElement('a');
42+ const a = document.createElement("a");
3043 a.href = url;
31- a.download = `benchmark-results${selectedDataset ? `-${selectedDataset}` : ''}.csv`;
44+ a.download = `benchmark-results${selectedDataset ? `-${selectedDataset}` : ""}.csv`;
3245 document.body.appendChild(a);
3346 a.click();
3447 document.body.removeChild(a);
web-ui/src/components/benchmark/table/BenchmarkTable.tsxmodified+61−44View file
@@ -1,19 +1,19 @@
1-import { useEffect, useState, useMemo } from 'react';
2-import axios from 'axios';
1+import { useEffect, useState, useMemo } from "react";
2+import axios from "axios";
33 import {
44 flexRender,
55 getCoreRowModel,
66 useReactTable,
77 getSortedRowModel,
8-} from '@tanstack/react-table';
9-import { BenchmarkResult } from '../../../types';
10-import { columns } from './columns';
11-import { BenchmarkCharts } from '../charts/BenchmarkCharts';
12-import { exportToCsv } from '../export/csvExport';
8+} from "@tanstack/react-table";
9+import { BenchmarkResult } from "../../../types";
10+import { columns } from "./columns";
11+import { BenchmarkCharts } from "../charts/BenchmarkCharts";
12+import { exportToCsv } from "../export/csvExport";
1313
1414 export function BenchmarkTable() {
1515 const [data, setData] = useState<BenchmarkResult[]>([]);
16- const [selectedDataset, setSelectedDataset] = useState<string>('');
16+ const [selectedDataset, setSelectedDataset] = useState<string>("");
1717 const [availableDatasets, setAvailableDatasets] = useState<string[]>([]);
1818 const [isLoading, setIsLoading] = useState(true);
1919 const [error, setError] = useState<string | null>(null);
@@ -24,17 +24,20 @@ export function BenchmarkTable() {
2424 setIsLoading(true);
2525 setError(null);
2626 const response = await axios.get(
27- 'https://raw.githubusercontent.com/magland/zia/benchmark-results/benchmark_results/results.json'
27+ "https://raw.githubusercontent.com/magland/zia/benchmark-results/benchmark_results/results.json",
2828 );
2929 const results = response.data.results;
3030 setData(results);
3131 // Extract unique dataset names with proper typing
32- const datasets = Array.from(new Set(results.map((result: BenchmarkResult) => result.dataset))).sort() as string[];
32+ const datasets = Array.from(
33+ new Set(results.map((result: BenchmarkResult) => result.dataset)),
34+ ).sort() as string[];
3335 setAvailableDatasets(datasets);
3436 } catch (error) {
35- const message = error instanceof Error ? error.message : 'Failed to fetch data';
37+ const message =
38+ error instanceof Error ? error.message : "Failed to fetch data";
3639 setError(message);
37- console.error('Error fetching benchmark data:', error);
40+ console.error("Error fetching benchmark data:", error);
3841 } finally {
3942 setIsLoading(false);
4043 }
@@ -46,7 +49,7 @@ export function BenchmarkTable() {
4649 // Memoize filtered data to prevent unnecessary recalculations
4750 const filteredData = useMemo(() => {
4851 if (!selectedDataset) return data;
49- return data.filter(row => row.dataset === selectedDataset);
52+ return data.filter((row) => row.dataset === selectedDataset);
5053 }, [data, selectedDataset]);
5154
5255 const table = useReactTable({
@@ -60,12 +63,12 @@ export function BenchmarkTable() {
6063 const chartData = useMemo(() => {
6164 if (!selectedDataset) return [];
6265 return data
63- .filter(row => row.dataset === selectedDataset)
64- .map(row => ({
66+ .filter((row) => row.dataset === selectedDataset)
67+ .map((row) => ({
6568 algorithm: row.algorithm,
6669 compression_ratio: row.compression_ratio,
6770 encode_speed: row.encode_mb_per_sec,
68- decode_speed: row.decode_mb_per_sec
71+ decode_speed: row.decode_mb_per_sec,
6972 }));
7073 }, [data, selectedDataset]);
7174
@@ -79,23 +82,31 @@ export function BenchmarkTable() {
7982
8083 return (
8184 <div className="table-container">
82- <div style={{ marginBottom: '20px', display: 'flex', alignItems: 'center', gap: '10px', justifyContent: 'space-between' }}>
83- <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
85+ <div
86+ style={{
87+ marginBottom: "20px",
88+ display: "flex",
89+ alignItems: "center",
90+ gap: "10px",
91+ justifyContent: "space-between",
92+ }}
93+ >
94+ <div style={{ display: "flex", alignItems: "center", gap: "10px" }}>
8495 <label htmlFor="dataset-select">Dataset:</label>
8596 <select
8697 id="dataset-select"
8798 value={selectedDataset}
8899 onChange={(e) => setSelectedDataset(e.target.value)}
89100 style={{
90- padding: '8px',
91- borderRadius: '4px',
92- border: '1px solid #ccc',
93- minWidth: '200px',
94- backgroundColor: '#fff'
101+ padding: "8px",
102+ borderRadius: "4px",
103+ border: "1px solid #ccc",
104+ minWidth: "200px",
105+ backgroundColor: "#fff",
95106 }}
96107 >
97108 <option value="">All Datasets</option>
98- {availableDatasets.map(dataset => (
109+ {availableDatasets.map((dataset) => (
99110 <option key={dataset} value={dataset}>
100111 {dataset}
101112 </option>
@@ -105,20 +116,26 @@ export function BenchmarkTable() {
105116 <button
106117 onClick={() => exportToCsv(filteredData, selectedDataset)}
107118 style={{
108- padding: '8px 16px',
109- backgroundColor: '#4CAF50',
110- color: 'white',
111- border: 'none',
112- borderRadius: '4px',
113- cursor: 'pointer',
114- display: 'flex',
115- alignItems: 'center',
116- gap: '8px'
119+ padding: "8px 16px",
120+ backgroundColor: "#4CAF50",
121+ color: "white",
122+ border: "none",
123+ borderRadius: "4px",
124+ cursor: "pointer",
125+ display: "flex",
126+ alignItems: "center",
127+ gap: "8px",
117128 }}
118129 >
119- <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
120- <path d="M8 12L3 7H6V1H10V7H13L8 12Z" fill="currentColor"/>
121- <path d="M2 14V15H14V14H2Z" fill="currentColor"/>
130+ <svg
131+ width="16"
132+ height="16"
133+ viewBox="0 0 16 16"
134+ fill="none"
135+ xmlns="http://www.w3.org/2000/svg"
136+ >
137+ <path d="M8 12L3 7H6V1H10V7H13L8 12Z" fill="currentColor" />
138+ <path d="M2 14V15H14V14H2Z" fill="currentColor" />
122139 </svg>
123140 Download CSV
124141 </button>
@@ -130,21 +147,21 @@ export function BenchmarkTable() {
130147
131148 <table>
132149 <thead>
133- {table.getHeaderGroups().map(headerGroup => (
150+ {table.getHeaderGroups().map((headerGroup) => (
134151 <tr key={headerGroup.id}>
135- {headerGroup.headers.map(header => (
152+ {headerGroup.headers.map((header) => (
136153 <th
137154 key={header.id}
138155 onClick={header.column.getToggleSortingHandler()}
139- style={{ cursor: 'pointer' }}
156+ style={{ cursor: "pointer" }}
140157 >
141158 {flexRender(
142159 header.column.columnDef.header,
143- header.getContext()
160+ header.getContext(),
144161 )}
145162 {header.column.getIsSorted() && (
146- <span style={{ marginLeft: '4px' }}>
147- {header.column.getIsSorted() === 'asc' ? '↑' : '↓'}
163+ <span style={{ marginLeft: "4px" }}>
164+ {header.column.getIsSorted() === "asc" ? "↑" : "↓"}
148165 </span>
149166 )}
150167 </th>
@@ -153,9 +170,9 @@ export function BenchmarkTable() {
153170 ))}
154171 </thead>
155172 <tbody>
156- {table.getRowModel().rows.map(row => (
173+ {table.getRowModel().rows.map((row) => (
157174 <tr key={row.id}>
158- {row.getVisibleCells().map(cell => (
175+ {row.getVisibleCells().map((cell) => (
159176 <td key={cell.id}>
160177 {flexRender(cell.column.columnDef.cell, cell.getContext())}
161178 </td>
web-ui/src/components/benchmark/table/columns.tsxmodified+30−30View file
@@ -1,75 +1,75 @@
1-import { createColumnHelper } from '@tanstack/react-table';
2-import { BenchmarkResult } from '../../../types';
3-import { formatNumber, formatSize } from '../utils/formatters';
1+import { createColumnHelper } from "@tanstack/react-table";
2+import { BenchmarkResult } from "../../../types";
3+import { formatNumber, formatSize } from "../utils/formatters";
44
55 const columnHelper = createColumnHelper<BenchmarkResult>();
66
77 export const columns = [
8- columnHelper.accessor('dataset', {
9- header: 'Dataset',
10- cell: info => info.getValue(),
8+ columnHelper.accessor("dataset", {
9+ header: "Dataset",
10+ cell: (info) => info.getValue(),
1111 }),
12- columnHelper.accessor('algorithm', {
13- header: 'Algorithm',
14- cell: info => info.getValue(),
12+ columnHelper.accessor("algorithm", {
13+ header: "Algorithm",
14+ cell: (info) => info.getValue(),
1515 }),
16- columnHelper.accessor('compression_ratio', {
17- header: 'Compression Ratio',
18- cell: info => `${formatNumber(info.getValue())}x`,
16+ columnHelper.accessor("compression_ratio", {
17+ header: "Compression Ratio",
18+ cell: (info) => `${formatNumber(info.getValue())}x`,
1919 sortingFn: (rowA, rowB) => {
2020 const a = rowA.original.compression_ratio;
2121 const b = rowB.original.compression_ratio;
2222 return a - b;
2323 },
2424 }),
25- columnHelper.accessor('encode_time', {
26- header: 'Encode Time (s)',
27- cell: info => formatNumber(info.getValue(), 4),
25+ columnHelper.accessor("encode_time", {
26+ header: "Encode Time (s)",
27+ cell: (info) => formatNumber(info.getValue(), 4),
2828 sortingFn: (rowA, rowB) => {
2929 const a = rowA.original.encode_time;
3030 const b = rowB.original.encode_time;
3131 return a - b;
3232 },
3333 }),
34- columnHelper.accessor('decode_time', {
35- header: 'Decode Time (s)',
36- cell: info => formatNumber(info.getValue(), 4),
34+ columnHelper.accessor("decode_time", {
35+ header: "Decode Time (s)",
36+ cell: (info) => formatNumber(info.getValue(), 4),
3737 sortingFn: (rowA, rowB) => {
3838 const a = rowA.original.decode_time;
3939 const b = rowB.original.decode_time;
4040 return a - b;
4141 },
4242 }),
43- columnHelper.accessor('encode_mb_per_sec', {
44- header: 'Encode Speed (MB/s)',
45- cell: info => formatNumber(info.getValue()),
43+ columnHelper.accessor("encode_mb_per_sec", {
44+ header: "Encode Speed (MB/s)",
45+ cell: (info) => formatNumber(info.getValue()),
4646 sortingFn: (rowA, rowB) => {
4747 const a = rowA.original.encode_mb_per_sec;
4848 const b = rowB.original.encode_mb_per_sec;
4949 return a - b;
5050 },
5151 }),
52- columnHelper.accessor('decode_mb_per_sec', {
53- header: 'Decode Speed (MB/s)',
54- cell: info => formatNumber(info.getValue()),
52+ columnHelper.accessor("decode_mb_per_sec", {
53+ header: "Decode Speed (MB/s)",
54+ cell: (info) => formatNumber(info.getValue()),
5555 sortingFn: (rowA, rowB) => {
5656 const a = rowA.original.decode_mb_per_sec;
5757 const b = rowB.original.decode_mb_per_sec;
5858 return a - b;
5959 },
6060 }),
61- columnHelper.accessor('original_size', {
62- header: 'Original Size',
63- cell: info => formatSize(info.getValue()),
61+ columnHelper.accessor("original_size", {
62+ header: "Original Size",
63+ cell: (info) => formatSize(info.getValue()),
6464 sortingFn: (rowA, rowB) => {
6565 const a = rowA.original.original_size;
6666 const b = rowB.original.original_size;
6767 return a - b;
6868 },
6969 }),
70- columnHelper.accessor('compressed_size', {
71- header: 'Compressed Size',
72- cell: info => formatSize(info.getValue()),
70+ columnHelper.accessor("compressed_size", {
71+ header: "Compressed Size",
72+ cell: (info) => formatSize(info.getValue()),
7373 sortingFn: (rowA, rowB) => {
7474 const a = rowA.original.compressed_size;
7575 const b = rowB.original.compressed_size;
web-ui/src/components/benchmark/utils/formatters.tsmodified+1−1View file
@@ -1,5 +1,5 @@
11 export const formatNumber = (num: number, decimals = 2) => {
2- return new Intl.NumberFormat('en-US', {
2+ return new Intl.NumberFormat("en-US", {
33 minimumFractionDigits: decimals,
44 maximumFractionDigits: decimals,
55 }).format(num);
web-ui/src/main.tsxmodified+6−6View file
@@ -1,10 +1,10 @@
1-import { StrictMode } from 'react'
2-import { createRoot } from 'react-dom/client'
3-import './index.css'
4-import App from './App.tsx'
1+import { StrictMode } from "react";
2+import { createRoot } from "react-dom/client";
3+import "./index.css";
4+import App from "./App.tsx";
55
6-createRoot(document.getElementById('root')!).render(
6+createRoot(document.getElementById("root")!).render(
77 <StrictMode>
88 <App />
99 </StrictMode>,
10-)
10+);
zia_benchmark/src/zia_benchmark/__init__.pymodified+1−1View file
@@ -2,4 +2,4 @@ from .algorithms import algorithms
22 from .datasets import datasets
33 from .run_benchmarks import run_benchmarks
44
5-__all__ = ['algorithms', 'datasets', 'run_benchmarks']
5+__all__ = ["algorithms", "datasets", "run_benchmarks"]
zia_benchmark/src/zia_benchmark/_analysis.pymodified+5−1View file
@@ -38,7 +38,10 @@ def compute_entropy_per_sample(array: np.ndarray) -> float:
3838
3939 from typing import Callable
4040
41-def linear_fit(x: np.ndarray, y: np.ndarray) -> tuple[np.ndarray, Callable[[np.ndarray], np.ndarray]]:
41+
42+def linear_fit(
43+ x: np.ndarray, y: np.ndarray
44+) -> tuple[np.ndarray, Callable[[np.ndarray], np.ndarray]]:
4245 """Perform linear fit with constant term.
4346
4447 Args:
@@ -51,6 +54,7 @@ def linear_fit(x: np.ndarray, y: np.ndarray) -> tuple[np.ndarray, Callable[[np.n
5154 - prediction function that takes x_new and returns predictions
5255 """
5356 from numpy.linalg import lstsq
57+
5458 X = np.column_stack([x, np.ones(len(x))])
5559 coeffs = lstsq(X, y, rcond=None)[0]
5660
zia_benchmark/src/zia_benchmark/_compress_ints_lossless.pymodified+9−1View file
@@ -14,17 +14,25 @@ def compress_ints_lossless(x, *, method: str = "zstd") -> bytes:
1414 """
1515 if method == "zstd":
1616 import zstandard as zstd
17+
1718 cctx = zstd.ZstdCompressor(level=22)
1819 return cctx.compress(x.tobytes())
1920 elif method == "zlib":
2021 import zlib
22+
2123 return zlib.compress(x.tobytes(), level=9)
2224 elif method == "lzma":
2325 import lzma
26+
2427 return lzma.compress(x.tobytes(), preset=9)
2528 elif method == "simple_ans":
2629 from simple_ans import ans_encode
30+
2731 encoding = ans_encode(x)
28- return encoding.bitstream + encoding.symbol_counts.tobytes() + encoding.symbol_values.tobytes()
32+ return (
33+ encoding.bitstream
34+ + encoding.symbol_counts.tobytes()
35+ + encoding.symbol_values.tobytes()
36+ )
2937 else:
3038 raise ValueError(f"Unknown method: {method}")
zia_benchmark/src/zia_benchmark/_data_loaders.pymodified+17−11View file
@@ -6,7 +6,9 @@ from typing import cast
66 import warnings
77
88
9-def load_real_000876(*, num_samples: int, num_channels: int, start_channel: int) -> np.ndarray:
9+def load_real_000876(
10+ *, num_samples: int, num_channels: int, start_channel: int
11+) -> np.ndarray:
1012 """Load data from DANDI dataset 000876.
1113
1214 Args:
@@ -20,17 +22,19 @@ def load_real_000876(*, num_samples: int, num_channels: int, start_channel: int)
2022 warnings.warn(
2123 "This function is deprecated. Use datasets['real-000876-ch45']['create']() instead.",
2224 DeprecationWarning,
23- stacklevel=2
25+ stacklevel=2,
2426 )
2527 nwb_url = "https://api.dandiarchive.org/api/assets/7e1de06d-d478-40e2-9b64-9dd04eafaa4c/download/"
2628 h5f = lindi.LindiH5pyFile.from_hdf5_file(nwb_url)
2729 ds = h5f["/acquisition/ElectricalSeriesAP/data"]
2830 assert isinstance(ds, lindi.LindiH5pyDataset)
29- ret = ds[:num_samples, start_channel:start_channel + num_channels]
31+ ret = ds[:num_samples, start_channel : start_channel + num_channels]
3032 return cast(np.ndarray, ret)
3133
3234
33-def load_real_000409(*, num_samples: int, num_channels: int, start_channel: int) -> np.ndarray:
35+def load_real_000409(
36+ *, num_samples: int, num_channels: int, start_channel: int
37+) -> np.ndarray:
3438 """Load data from DANDI dataset 000409.
3539
3640 Args:
@@ -44,17 +48,19 @@ def load_real_000409(*, num_samples: int, num_channels: int, start_channel: int)
4448 warnings.warn(
4549 "This function is deprecated. Use datasets['real-000409-ch101']['create']() instead.",
4650 DeprecationWarning,
47- stacklevel=2
51+ stacklevel=2,
4852 )
4953 nwb_url = "https://api.dandiarchive.org/api/assets/c04f6b30-82bf-40e1-9210-34f0bcd8be24/download/"
5054 h5f = lindi.LindiH5pyFile.from_hdf5_file(nwb_url)
51- ds = h5f['/acquisition/ElectricalSeriesAp/data']
55+ ds = h5f["/acquisition/ElectricalSeriesAp/data"]
5256 assert isinstance(ds, lindi.LindiH5pyDataset)
53- ret = ds[:num_samples, start_channel:start_channel + num_channels]
57+ ret = ds[:num_samples, start_channel : start_channel + num_channels]
5458 return cast(np.ndarray, ret)
5559
5660
57-def load_real_001290(*, num_samples: int, num_channels: int, start_channel: int) -> np.ndarray:
61+def load_real_001290(
62+ *, num_samples: int, num_channels: int, start_channel: int
63+) -> np.ndarray:
5864 """Load data from DANDI dataset 001290.
5965
6066 Args:
@@ -68,11 +74,11 @@ def load_real_001290(*, num_samples: int, num_channels: int, start_channel: int)
6874 warnings.warn(
6975 "This function is deprecated. Use datasets['real-001290-ch0']['create']() instead.",
7076 DeprecationWarning,
71- stacklevel=2
77+ stacklevel=2,
7278 )
7379 nwb_url = "https://api.dandiarchive.org/api/assets/78c99d23-da88-4ecd-9086-c488a126eac5/download/"
7480 h5f = lindi.LindiH5pyFile.from_hdf5_file(nwb_url)
75- ds = h5f['/acquisition/ElectricalSeriesAPImec/data']
81+ ds = h5f["/acquisition/ElectricalSeriesAPImec/data"]
7682 assert isinstance(ds, lindi.LindiH5pyDataset)
77- ret = ds[:num_samples, start_channel:start_channel + num_channels]
83+ ret = ds[:num_samples, start_channel : start_channel + num_channels]
7884 return cast(np.ndarray, ret)
zia_benchmark/src/zia_benchmark/_filters.pymodified+9−3View file
@@ -3,7 +3,9 @@ import numpy as np
33 from scipy.signal import butter, lfilter
44
55
6-def bandpass_filter(array: np.ndarray, *, sampling_frequency: float, lowcut: float, highcut: float) -> np.ndarray:
6+def bandpass_filter(
7+ array: np.ndarray, *, sampling_frequency: float, lowcut: float, highcut: float
8+) -> np.ndarray:
79 """Apply a bandpass filter to the input array.
810
911 Args:
@@ -22,7 +24,9 @@ def bandpass_filter(array: np.ndarray, *, sampling_frequency: float, lowcut: flo
2224 return cast(np.ndarray, lfilter(b, a, array, axis=0))
2325
2426
25-def lowpass_filter(array: np.ndarray, *, sampling_frequency: float, highcut: float) -> np.ndarray:
27+def lowpass_filter(
28+ array: np.ndarray, *, sampling_frequency: float, highcut: float
29+) -> np.ndarray:
2630 """Apply a lowpass filter to the input array.
2731
2832 Args:
@@ -39,7 +43,9 @@ def lowpass_filter(array: np.ndarray, *, sampling_frequency: float, highcut: flo
3943 return cast(np.ndarray, lfilter(b, a, array, axis=0))
4044
4145
42-def highpass_filter(array: np.ndarray, *, sampling_frequency: float, lowcut: float) -> np.ndarray:
46+def highpass_filter(
47+ array: np.ndarray, *, sampling_frequency: float, lowcut: float
48+) -> np.ndarray:
4349 """Apply a highpass filter to the input array.
4450
4551 Args:
zia_benchmark/src/zia_benchmark/_memobin.pymodified+23−12View file
@@ -2,7 +2,10 @@ import json
22 import requests
33 from typing import Optional
44
5-def create_signed_upload_url(url: str, size: int, user_id: str, memobin_api_key: str) -> str:
5+
6+def create_signed_upload_url(
7+ url: str, size: int, user_id: str, memobin_api_key: str
8+) -> str:
69 """Create a signed upload URL for memobin.
710
811 Args:
@@ -22,21 +25,21 @@ def create_signed_upload_url(url: str, size: int, user_id: str, memobin_api_key:
2225 if not url.startswith(prefix):
2326 raise ValueError("Invalid url. Does not have proper prefix")
2427
25- file_path = url[len(prefix):]
28+ file_path = url[len(prefix) :]
2629 tempory_api_url = "https://hub.tempory.net/api/uploadFile"
2730
2831 response = requests.post(
2932 tempory_api_url,
3033 headers={
3134 "Content-Type": "application/json",
32- "Authorization": f"Bearer {memobin_api_key}"
35+ "Authorization": f"Bearer {memobin_api_key}",
3336 },
3437 json={
3538 "appName": "memobin",
3639 "filePath": file_path,
3740 "size": size,
38- "userId": user_id
39- }
41+ "userId": user_id,
42+ },
4043 )
4144
4245 if not response.ok:
@@ -51,8 +54,14 @@ def create_signed_upload_url(url: str, size: int, user_id: str, memobin_api_key:
5154
5255 return upload_url
5356
54-def construct_memobin_url(alg_name: str, dataset_name: str, alg_version: str,
55- dataset_version: str, system_version: str) -> str:
57+
58+def construct_memobin_url(
59+ alg_name: str,
60+ dataset_name: str,
61+ alg_version: str,
62+ dataset_version: str,
63+ system_version: str,
64+) -> str:
5665 """Construct the memobin URL for a specific benchmark result.
5766
5867 Args:
@@ -68,7 +77,10 @@ def construct_memobin_url(alg_name: str, dataset_name: str, alg_version: str,
6877 path = f"{alg_name}/{dataset_name}/{alg_version}/{dataset_version}/{system_version}/metadata.json"
6978 return f"https://tempory.net/f/memobin/{path}"
7079
71-def upload_to_memobin(metadata: dict, url: str, user_id: str, memobin_api_key: str) -> None:
80+
81+def upload_to_memobin(
82+ metadata: dict, url: str, user_id: str, memobin_api_key: str
83+) -> None:
7284 """Upload metadata to memobin.
7385
7486 Args:
@@ -80,20 +92,19 @@ def upload_to_memobin(metadata: dict, url: str, user_id: str, memobin_api_key: s
8092 Raises:
8193 requests.RequestException: If the upload fails
8294 """
83- metadata_bytes = json.dumps(metadata).encode('utf-8')
95+ metadata_bytes = json.dumps(metadata).encode("utf-8")
8496 size = len(metadata_bytes)
8597
8698 upload_url = create_signed_upload_url(url, size, user_id, memobin_api_key)
8799
88100 response = requests.put(
89- upload_url,
90- data=metadata_bytes,
91- headers={"Content-Type": "application/json"}
101+ upload_url, data=metadata_bytes, headers={"Content-Type": "application/json"}
92102 )
93103
94104 if not response.ok:
95105 raise requests.RequestException("Failed to upload metadata to memobin")
96106
107+
97108 def download_from_memobin(url: str) -> Optional[dict]:
98109 """Download metadata from memobin.
99110
zia_benchmark/src/zia_benchmark/algorithms/lzma/__init__.pymodified+17−10View file
@@ -3,6 +3,7 @@ import numpy as np
33
44 def lzma_delta_encode(x: np.ndarray, preset: int) -> bytes:
55 import lzma
6+
67 assert x.ndim == 1
78 y = np.diff(x)
89 y = np.insert(y, 0, x[0])
@@ -10,8 +11,10 @@ def lzma_delta_encode(x: np.ndarray, preset: int) -> bytes:
1011 compressed = lzma.compress(buf, preset=preset)
1112 return compressed
1213
14+
1315 def lzma_delta_decode(x: bytes, dtype: str) -> np.ndarray:
1416 import lzma
17+
1518 buf = lzma.decompress(x)
1619 y = np.frombuffer(buf, dtype=dtype)
1720 return np.cumsum(y)
@@ -19,29 +22,33 @@ def lzma_delta_decode(x: bytes, dtype: str) -> np.ndarray:
1922
2023 def lzma_encode(x: np.ndarray, preset: int) -> bytes:
2124 import lzma
25+
2226 assert x.ndim == 1
2327 buf = x.tobytes()
2428 compressed = lzma.compress(buf, preset=preset)
2529 return compressed
2630
31+
2732 def lzma_decode(x: bytes, dtype: str) -> np.ndarray:
2833 import lzma
34+
2935 buf = lzma.decompress(x)
3036 y = np.frombuffer(buf, dtype=dtype)
3137 return y
3238
39+
3340 algorithms = [
3441 {
35- 'name': 'lzma-9',
36- 'version': '1',
37- 'encode': lambda x: lzma_encode(x, preset=9),
38- 'decode': lambda x, dtype: lzma_decode(x, dtype)
42+ "name": "lzma-9",
43+ "version": "1",
44+ "encode": lambda x: lzma_encode(x, preset=9),
45+ "decode": lambda x, dtype: lzma_decode(x, dtype),
3946 },
4047 {
41- 'name': 'lzma-9-delta',
42- 'version': '1',
43- 'encode': lambda x: lzma_delta_encode(x, preset=9),
44- 'decode': lambda x, dtype: lzma_delta_decode(x, dtype),
45- 'tags': ['delta_encoding']
46- }
48+ "name": "lzma-9-delta",
49+ "version": "1",
50+ "encode": lambda x: lzma_delta_encode(x, preset=9),
51+ "decode": lambda x, dtype: lzma_delta_decode(x, dtype),
52+ "tags": ["delta_encoding"],
53+ },
4754 ]
zia_benchmark/src/zia_benchmark/algorithms/simple_ans/__init__.pymodified+62−46View file
@@ -3,6 +3,7 @@ import numpy as np
33
44 def simple_ans_delta_encode(x: np.ndarray) -> bytes:
55 from simple_ans import ans_encode
6+
67 assert x.ndim == 1
78 # Calculate differences without inserting x[0]
89 y = np.diff(x)
@@ -21,36 +22,44 @@ def simple_ans_delta_encode(x: np.ndarray) -> bytes:
2122 else:
2223 raise ValueError(f"Unsupported dtype: {x.dtype}")
2324 # Include x[0] in the header
24- header = [
25- dtype_code,
26- encoded.num_bits,
27- encoded.signal_length,
28- encoded.state,
29- len(encoded.symbol_counts),
30- x[0] # Store first value in header
31- ] + [c for c in encoded.symbol_counts] + [v for v in encoded.symbol_values]
25+ header = (
26+ [
27+ dtype_code,
28+ encoded.num_bits,
29+ encoded.signal_length,
30+ encoded.state,
31+ len(encoded.symbol_counts),
32+ x[0], # Store first value in header
33+ ]
34+ + [c for c in encoded.symbol_counts]
35+ + [v for v in encoded.symbol_values]
36+ )
3237 header_bytes = np.array(header, dtype=np.int64).tobytes()
3338 header_size = np.uint32(len(header_bytes))
3439 return header_size.tobytes() + header_bytes + encoded.bitstream
3540
41+
3642 def simple_ans_delta_decode(x: bytes, dtype: str) -> np.ndarray:
3743 from simple_ans import ans_decode, EncodedSignal
44+
3845 header_size = np.frombuffer(x[:4], dtype=np.uint32)[0]
39- header = np.frombuffer(x[4:4 + header_size], dtype=np.int64)
40- dtype_code, num_bits, signal_length, state, num_symbols, x0 = header[:6] # Extract x0 from header
41- symbol_counts = header[6:6 + num_symbols]
42- symbol_values = header[6 + num_symbols:]
43- bitstream = x[4 + header_size:]
46+ header = np.frombuffer(x[4 : 4 + header_size], dtype=np.int64)
47+ dtype_code, num_bits, signal_length, state, num_symbols, x0 = header[
48+ :6
49+ ] # Extract x0 from header
50+ symbol_counts = header[6 : 6 + num_symbols]
51+ symbol_values = header[6 + num_symbols :]
52+ bitstream = x[4 + header_size :]
4453 if dtype_code == 0:
45- assert dtype == 'uint8'
54+ assert dtype == "uint8"
4655 elif dtype_code == 1:
47- assert dtype == 'uint16'
56+ assert dtype == "uint16"
4857 elif dtype_code == 2:
49- assert dtype == 'uint32'
58+ assert dtype == "uint32"
5059 elif dtype_code == 3:
51- assert dtype == 'int16'
60+ assert dtype == "int16"
5261 elif dtype_code == 4:
53- assert dtype == 'int32'
62+ assert dtype == "int32"
5463 else:
5564 raise ValueError(f"Unsupported dtype code: {dtype_code}")
5665
@@ -60,7 +69,7 @@ def simple_ans_delta_decode(x: bytes, dtype: str) -> np.ndarray:
6069 state=int(state),
6170 symbol_counts=symbol_counts.astype(np.uint32),
6271 symbol_values=symbol_values.astype(dtype),
63- bitstream=bitstream
72+ bitstream=bitstream,
6473 )
6574 # Decode the differences
6675 diffs = ans_decode(encoded)
@@ -74,6 +83,7 @@ def simple_ans_delta_decode(x: bytes, dtype: str) -> np.ndarray:
7483
7584 def simple_ans_encode(x: np.ndarray) -> bytes:
7685 from simple_ans import ans_encode
86+
7787 assert x.ndim == 1
7888 encoded = ans_encode(x)
7989 if x.dtype == np.uint8:
@@ -88,13 +98,17 @@ def simple_ans_encode(x: np.ndarray) -> bytes:
8898 dtype_code = 4
8999 else:
90100 raise ValueError(f"Unsupported dtype: {x.dtype}")
91- header = [
92- dtype_code,
93- encoded.num_bits,
94- encoded.signal_length,
95- encoded.state,
96- len(encoded.symbol_counts)
97- ] + [c for c in encoded.symbol_counts] + [v for v in encoded.symbol_values]
101+ header = (
102+ [
103+ dtype_code,
104+ encoded.num_bits,
105+ encoded.signal_length,
106+ encoded.state,
107+ len(encoded.symbol_counts),
108+ ]
109+ + [c for c in encoded.symbol_counts]
110+ + [v for v in encoded.symbol_values]
111+ )
98112 header_bytes = np.array(header, dtype=np.int64).tobytes()
99113 header_size = np.uint32(len(header_bytes))
100114 return header_size.tobytes() + header_bytes + encoded.bitstream
@@ -102,22 +116,23 @@ def simple_ans_encode(x: np.ndarray) -> bytes:
102116
103117 def simple_ans_decode(x: bytes, dtype: str) -> np.ndarray:
104118 from simple_ans import ans_decode, EncodedSignal
119+
105120 header_size = np.frombuffer(x[:4], dtype=np.uint32)[0]
106- header = np.frombuffer(x[4:4 + header_size], dtype=np.int64)
121+ header = np.frombuffer(x[4 : 4 + header_size], dtype=np.int64)
107122 dtype_code, num_bits, signal_length, state, num_symbols = header[:5]
108- symbol_counts = header[5:5 + num_symbols]
109- symbol_values = header[5 + num_symbols:]
110- bitstream = x[4 + header_size:]
123+ symbol_counts = header[5 : 5 + num_symbols]
124+ symbol_values = header[5 + num_symbols :]
125+ bitstream = x[4 + header_size :]
111126 if dtype_code == 0:
112- assert dtype == 'uint8'
127+ assert dtype == "uint8"
113128 elif dtype_code == 1:
114- assert dtype == 'uint16'
129+ assert dtype == "uint16"
115130 elif dtype_code == 2:
116- assert dtype == 'uint32'
131+ assert dtype == "uint32"
117132 elif dtype_code == 3:
118- assert dtype == 'int16'
133+ assert dtype == "int16"
119134 elif dtype_code == 4:
120- assert dtype == 'int32'
135+ assert dtype == "int32"
121136 else:
122137 raise ValueError(f"Unsupported dtype code: {dtype_code}")
123138
@@ -127,22 +142,23 @@ def simple_ans_decode(x: bytes, dtype: str) -> np.ndarray:
127142 state=int(state),
128143 symbol_counts=symbol_counts.astype(np.uint32),
129144 symbol_values=symbol_values.astype(dtype),
130- bitstream=bitstream
145+ bitstream=bitstream,
131146 )
132147 return ans_decode(encoded)
133148
149+
134150 algorithms = [
135151 {
136- 'name': 'simple-ans',
137- 'version': '1',
138- 'encode': lambda x: simple_ans_encode(x),
139- 'decode': lambda x, dtype: simple_ans_decode(x, dtype)
152+ "name": "simple-ans",
153+ "version": "1",
154+ "encode": lambda x: simple_ans_encode(x),
155+ "decode": lambda x, dtype: simple_ans_decode(x, dtype),
140156 },
141157 {
142- 'name': 'simple-ans-delta',
143- 'version': '1',
144- 'encode': lambda x: simple_ans_delta_encode(x),
145- 'decode': lambda x, dtype: simple_ans_delta_decode(x, dtype),
146- 'tags': ['delta_encoding']
147- }
158+ "name": "simple-ans-delta",
159+ "version": "1",
160+ "encode": lambda x: simple_ans_delta_encode(x),
161+ "decode": lambda x, dtype: simple_ans_delta_decode(x, dtype),
162+ "tags": ["delta_encoding"],
163+ },
148164 ]
zia_benchmark/src/zia_benchmark/algorithms/zlib/__init__.pymodified+39−31View file
@@ -3,19 +3,24 @@ import numpy as np
33
44 def zlib_encode(x: np.ndarray, level: int) -> bytes:
55 import zlib
6+
67 assert x.ndim == 1
78 buf = x.tobytes()
89 compressed = zlib.compress(buf, level=level)
910 return compressed
1011
12+
1113 def zlib_decode(x: bytes, dtype: str) -> np.ndarray:
1214 import zlib
15+
1316 buf = zlib.decompress(x)
1417 y = np.frombuffer(buf, dtype=dtype)
1518 return y
1619
20+
1721 def zlib_delta_encode(x: np.ndarray, level: int) -> bytes:
1822 import zlib
23+
1924 assert x.ndim == 1
2025 y = np.diff(x)
2126 y = np.insert(y, 0, x[0])
@@ -23,53 +28,56 @@ def zlib_delta_encode(x: np.ndarray, level: int) -> bytes:
2328 compressed = zlib.compress(buf, level=level)
2429 return compressed
2530
31+
2632 def zlib_delta_decode(x: bytes, dtype: str) -> np.ndarray:
2733 import zlib
34+
2835 buf = zlib.decompress(x)
2936 y = np.frombuffer(buf, dtype=dtype)
3037 return np.cumsum(y)
3138
39+
3240 algorithms = [
3341 {
34- 'name': 'zlib-1',
35- 'version': '1',
36- 'encode': lambda x: zlib_encode(x, level=1),
37- 'decode': lambda x, dtype: zlib_decode(x, dtype),
38- 'tags': []
42+ "name": "zlib-1",
43+ "version": "1",
44+ "encode": lambda x: zlib_encode(x, level=1),
45+ "decode": lambda x, dtype: zlib_decode(x, dtype),
46+ "tags": [],
3947 },
4048 {
41- 'name': 'zlib-3',
42- 'version': '1',
43- 'encode': lambda x: zlib_encode(x, level=3),
44- 'decode': lambda x, dtype: zlib_decode(x, dtype),
45- 'tags': []
49+ "name": "zlib-3",
50+ "version": "1",
51+ "encode": lambda x: zlib_encode(x, level=3),
52+ "decode": lambda x, dtype: zlib_decode(x, dtype),
53+ "tags": [],
4654 },
4755 {
48- 'name': 'zlib-5',
49- 'version': '1',
50- 'encode': lambda x: zlib_encode(x, level=5),
51- 'decode': lambda x, dtype: zlib_decode(x, dtype),
52- 'tags': []
56+ "name": "zlib-5",
57+ "version": "1",
58+ "encode": lambda x: zlib_encode(x, level=5),
59+ "decode": lambda x, dtype: zlib_decode(x, dtype),
60+ "tags": [],
5361 },
5462 {
55- 'name': 'zlib-7',
56- 'version': '1',
57- 'encode': lambda x: zlib_encode(x, level=7),
58- 'decode': lambda x, dtype: zlib_decode(x, dtype),
59- 'tags': []
63+ "name": "zlib-7",
64+ "version": "1",
65+ "encode": lambda x: zlib_encode(x, level=7),
66+ "decode": lambda x, dtype: zlib_decode(x, dtype),
67+ "tags": [],
6068 },
6169 {
62- 'name': 'zlib-9',
63- 'version': '1',
64- 'encode': lambda x: zlib_encode(x, level=9),
65- 'decode': lambda x, dtype: zlib_decode(x, dtype),
66- 'tags': []
70+ "name": "zlib-9",
71+ "version": "1",
72+ "encode": lambda x: zlib_encode(x, level=9),
73+ "decode": lambda x, dtype: zlib_decode(x, dtype),
74+ "tags": [],
6775 },
6876 {
69- 'name': 'zlib-9-delta',
70- 'version': '1',
71- 'encode': lambda x: zlib_delta_encode(x, level=9),
72- 'decode': lambda x, dtype: zlib_delta_decode(x, dtype),
73- 'tags': ['delta_encoding']
74- }
77+ "name": "zlib-9-delta",
78+ "version": "1",
79+ "encode": lambda x: zlib_delta_encode(x, level=9),
80+ "decode": lambda x, dtype: zlib_delta_decode(x, dtype),
81+ "tags": ["delta_encoding"],
82+ },
7583 ]
zia_benchmark/src/zia_benchmark/algorithms/zstd/__init__.pymodified+41−34View file
@@ -3,6 +3,7 @@ import numpy as np
33
44 def zstd_delta_encode(x: np.ndarray, level: int) -> bytes:
55 import zstandard as zstd
6+
67 assert x.ndim == 1
78 y = np.diff(x)
89 y = np.insert(y, 0, x[0])
@@ -11,8 +12,10 @@ def zstd_delta_encode(x: np.ndarray, level: int) -> bytes:
1112 compressed = compressor.compress(buf)
1213 return compressed
1314
15+
1416 def zstd_delta_decode(x: bytes, dtype: str) -> np.ndarray:
1517 import zstandard as zstd
18+
1619 decompressor = zstd.ZstdDecompressor()
1720 buf = decompressor.decompress(x)
1821 y = np.frombuffer(buf, dtype=dtype)
@@ -21,67 +24,71 @@ def zstd_delta_decode(x: bytes, dtype: str) -> np.ndarray:
2124
2225 def zstd_encode(x: np.ndarray, level: int) -> bytes:
2326 import zstandard as zstd
27+
2428 assert x.ndim == 1
2529 buf = x.tobytes()
2630 compressor = zstd.ZstdCompressor(level=level)
2731 compressed = compressor.compress(buf)
2832 return compressed
2933
34+
3035 def zstd_decode(x: bytes, dtype: str) -> np.ndarray:
3136 import zstandard as zstd
37+
3238 decompressor = zstd.ZstdDecompressor()
3339 buf = decompressor.decompress(x)
3440 y = np.frombuffer(buf, dtype=dtype)
3541 return y
3642
43+
3744 algorithms = [
3845 {
39- 'name': 'zstd-4',
40- 'version': '1',
41- 'encode': lambda x: zstd_encode(x, level=4),
42- 'decode': lambda x, dtype: zstd_decode(x, dtype)
46+ "name": "zstd-4",
47+ "version": "1",
48+ "encode": lambda x: zstd_encode(x, level=4),
49+ "decode": lambda x, dtype: zstd_decode(x, dtype),
4350 },
4451 {
45- 'name': 'zstd-7',
46- 'version': '1',
47- 'encode': lambda x: zstd_encode(x, level=7),
48- 'decode': lambda x, dtype: zstd_decode(x, dtype)
52+ "name": "zstd-7",
53+ "version": "1",
54+ "encode": lambda x: zstd_encode(x, level=7),
55+ "decode": lambda x, dtype: zstd_decode(x, dtype),
4956 },
5057 {
51- 'name': 'zstd-10',
52- 'version': '1',
53- 'encode': lambda x: zstd_encode(x, level=10),
54- 'decode': lambda x, dtype: zstd_decode(x, dtype)
58+ "name": "zstd-10",
59+ "version": "1",
60+ "encode": lambda x: zstd_encode(x, level=10),
61+ "decode": lambda x, dtype: zstd_decode(x, dtype),
5562 },
5663 {
57- 'name': 'zstd-13',
58- 'version': '1',
59- 'encode': lambda x: zstd_encode(x, level=13),
60- 'decode': lambda x, dtype: zstd_decode(x, dtype)
64+ "name": "zstd-13",
65+ "version": "1",
66+ "encode": lambda x: zstd_encode(x, level=13),
67+ "decode": lambda x, dtype: zstd_decode(x, dtype),
6168 },
6269 {
63- 'name': 'zstd-16',
64- 'version': '1',
65- 'encode': lambda x: zstd_encode(x, level=16),
66- 'decode': lambda x, dtype: zstd_decode(x, dtype)
70+ "name": "zstd-16",
71+ "version": "1",
72+ "encode": lambda x: zstd_encode(x, level=16),
73+ "decode": lambda x, dtype: zstd_decode(x, dtype),
6774 },
6875 {
69- 'name': 'zstd-19',
70- 'version': '1',
71- 'encode': lambda x: zstd_encode(x, level=19),
72- 'decode': lambda x, dtype: zstd_decode(x, dtype)
76+ "name": "zstd-19",
77+ "version": "1",
78+ "encode": lambda x: zstd_encode(x, level=19),
79+ "decode": lambda x, dtype: zstd_decode(x, dtype),
7380 },
7481 {
75- 'name': 'zstd-22',
76- 'version': '1',
77- 'encode': lambda x: zstd_encode(x, level=22),
78- 'decode': lambda x, dtype: zstd_decode(x, dtype)
82+ "name": "zstd-22",
83+ "version": "1",
84+ "encode": lambda x: zstd_encode(x, level=22),
85+ "decode": lambda x, dtype: zstd_decode(x, dtype),
7986 },
8087 {
81- 'name': 'zstd-22-delta',
82- 'version': '1',
83- 'encode': lambda x: zstd_delta_encode(x, level=22),
84- 'decode': lambda x, dtype: zstd_delta_decode(x, dtype),
85- 'tags': ['delta_encoding']
86- }
88+ "name": "zstd-22-delta",
89+ "version": "1",
90+ "encode": lambda x: zstd_delta_encode(x, level=22),
91+ "decode": lambda x, dtype: zstd_delta_decode(x, dtype),
92+ "tags": ["delta_encoding"],
93+ },
8794 ]
zia_benchmark/src/zia_benchmark/datasets/bernoulli/__init__.pymodified+22−21View file
@@ -6,35 +6,36 @@ def create_bernoulli(*, n_samples: int, p: float, seed: int) -> np.ndarray:
66 x = rng.binomial(1, p, n_samples).astype(np.uint8)
77 return x
88
9+
910 datasets = [
1011 {
11- 'name': 'bernoulli-0.1',
12- 'version': '1',
13- 'create': lambda: create_bernoulli(n_samples=1_000_000, p=0.1, seed=0),
14- 'tags': ['binary']
12+ "name": "bernoulli-0.1",
13+ "version": "1",
14+ "create": lambda: create_bernoulli(n_samples=1_000_000, p=0.1, seed=0),
15+ "tags": ["binary"],
1516 },
1617 {
17- 'name': 'bernoulli-0.2',
18- 'version': '1',
19- 'create': lambda: create_bernoulli(n_samples=1_000_000, p=0.2, seed=0),
20- 'tags': ['binary']
18+ "name": "bernoulli-0.2",
19+ "version": "1",
20+ "create": lambda: create_bernoulli(n_samples=1_000_000, p=0.2, seed=0),
21+ "tags": ["binary"],
2122 },
2223 {
23- 'name': 'bernoulli-0.3',
24- 'version': '1',
25- 'create': lambda: create_bernoulli(n_samples=1_000_000, p=0.3, seed=0),
26- 'tags': ['binary']
24+ "name": "bernoulli-0.3",
25+ "version": "1",
26+ "create": lambda: create_bernoulli(n_samples=1_000_000, p=0.3, seed=0),
27+ "tags": ["binary"],
2728 },
2829 {
29- 'name': 'bernoulli-0.4',
30- 'version': '1',
31- 'create': lambda: create_bernoulli(n_samples=1_000_000, p=0.4, seed=0),
32- 'tags': ['binary']
30+ "name": "bernoulli-0.4",
31+ "version": "1",
32+ "create": lambda: create_bernoulli(n_samples=1_000_000, p=0.4, seed=0),
33+ "tags": ["binary"],
3334 },
3435 {
35- 'name': 'bernoulli-0.5',
36- 'version': '1',
37- 'create': lambda: create_bernoulli(n_samples=1_000_000, p=0.5, seed=0),
38- 'tags': ['binary']
39- }
36+ "name": "bernoulli-0.5",
37+ "version": "1",
38+ "create": lambda: create_bernoulli(n_samples=1_000_000, p=0.5, seed=0),
39+ "tags": ["binary"],
40+ },
4041 ]
zia_benchmark/src/zia_benchmark/datasets/gaussian/__init__.pymodified+22−21View file
@@ -6,35 +6,36 @@ def create_gaussian(*, n_samples: int, stddev: float, seed: int) -> np.ndarray:
66 x = np.round(rng.normal(0, stddev, n_samples)).astype(np.int16)
77 return x
88
9+
910 datasets = [
1011 {
11- 'name': 'gaussian-1',
12- 'version': '1',
13- 'create': lambda: create_gaussian(n_samples=1_000_000, stddev=1, seed=0),
14- 'tags': []
12+ "name": "gaussian-1",
13+ "version": "1",
14+ "create": lambda: create_gaussian(n_samples=1_000_000, stddev=1, seed=0),
15+ "tags": [],
1516 },
1617 {
17- 'name': 'gaussian-2',
18- 'version': '1',
19- 'create': lambda: create_gaussian(n_samples=1_000_000, stddev=2, seed=0),
20- 'tags': []
18+ "name": "gaussian-2",
19+ "version": "1",
20+ "create": lambda: create_gaussian(n_samples=1_000_000, stddev=2, seed=0),
21+ "tags": [],
2122 },
2223 {
23- 'name': 'gaussian-3',
24- 'version': '1',
25- 'create': lambda: create_gaussian(n_samples=1_000_000, stddev=3, seed=0),
26- 'tags': []
24+ "name": "gaussian-3",
25+ "version": "1",
26+ "create": lambda: create_gaussian(n_samples=1_000_000, stddev=3, seed=0),
27+ "tags": [],
2728 },
2829 {
29- 'name': 'gaussian-5',
30- 'version': '1',
31- 'create': lambda: create_gaussian(n_samples=1_000_000, stddev=5, seed=0),
32- 'tags': []
30+ "name": "gaussian-5",
31+ "version": "1",
32+ "create": lambda: create_gaussian(n_samples=1_000_000, stddev=5, seed=0),
33+ "tags": [],
3334 },
3435 {
35- 'name': 'gaussian-8',
36- 'version': '1',
37- 'create': lambda: create_gaussian(n_samples=1_000_000, stddev=8, seed=0),
38- 'tags': []
39- }
36+ "name": "gaussian-8",
37+ "version": "1",
38+ "create": lambda: create_gaussian(n_samples=1_000_000, stddev=8, seed=0),
39+ "tags": [],
40+ },
4041 ]
zia_benchmark/src/zia_benchmark/datasets/real/__init__.pymodified+36−24View file
@@ -3,7 +3,9 @@ import lindi
33 from typing import cast
44
55
6-def _load_real_000876(*, num_samples: int, num_channels: int, start_channel: int) -> np.ndarray:
6+def _load_real_000876(
7+ *, num_samples: int, num_channels: int, start_channel: int
8+) -> np.ndarray:
79 """Load data from DANDI dataset 000876.
810
911 Args:
@@ -18,11 +20,13 @@ def _load_real_000876(*, num_samples: int, num_channels: int, start_channel: int
1820 h5f = lindi.LindiH5pyFile.from_hdf5_file(nwb_url)
1921 ds = h5f["/acquisition/ElectricalSeriesAP/data"]
2022 assert isinstance(ds, lindi.LindiH5pyDataset)
21- ret = ds[:num_samples, start_channel:start_channel + num_channels]
23+ ret = ds[:num_samples, start_channel : start_channel + num_channels]
2224 return cast(np.ndarray, ret)
2325
2426
25-def _load_real_000409(*, num_samples: int, num_channels: int, start_channel: int) -> np.ndarray:
27+def _load_real_000409(
28+ *, num_samples: int, num_channels: int, start_channel: int
29+) -> np.ndarray:
2630 """Load data from DANDI dataset 000409.
2731
2832 Args:
@@ -35,13 +39,15 @@ def _load_real_000409(*, num_samples: int, num_channels: int, start_channel: int
3539 """
3640 nwb_url = "https://api.dandiarchive.org/api/assets/c04f6b30-82bf-40e1-9210-34f0bcd8be24/download/"
3741 h5f = lindi.LindiH5pyFile.from_hdf5_file(nwb_url)
38- ds = h5f['/acquisition/ElectricalSeriesAp/data']
42+ ds = h5f["/acquisition/ElectricalSeriesAp/data"]
3943 assert isinstance(ds, lindi.LindiH5pyDataset)
40- ret = ds[:num_samples, start_channel:start_channel + num_channels]
44+ ret = ds[:num_samples, start_channel : start_channel + num_channels]
4145 return cast(np.ndarray, ret)
4246
4347
44-def _load_real_001290(*, num_samples: int, num_channels: int, start_channel: int) -> np.ndarray:
48+def _load_real_001290(
49+ *, num_samples: int, num_channels: int, start_channel: int
50+) -> np.ndarray:
4551 """Load data from DANDI dataset 001290.
4652
4753 Args:
@@ -54,32 +60,38 @@ def _load_real_001290(*, num_samples: int, num_channels: int, start_channel: int
5460 """
5561 nwb_url = "https://api.dandiarchive.org/api/assets/78c99d23-da88-4ecd-9086-c488a126eac5/download/"
5662 h5f = lindi.LindiH5pyFile.from_hdf5_file(nwb_url)
57- ds = h5f['/acquisition/ElectricalSeriesAPImec/data']
63+ ds = h5f["/acquisition/ElectricalSeriesAPImec/data"]
5864 assert isinstance(ds, lindi.LindiH5pyDataset)
59- ret = ds[:num_samples, start_channel:start_channel + num_channels]
65+ ret = ds[:num_samples, start_channel : start_channel + num_channels]
6066 return cast(np.ndarray, ret)
6167
6268
6369 datasets = [
6470 {
65- 'name': 'real-000876-ch45',
66- 'version': '1',
67- 'description': 'Real neurophysiology data from DANDI:000876, channel 45',
68- 'create': lambda: _load_real_000876(num_samples=500_000, num_channels=1, start_channel=45).flatten(),
69- 'tags': ['continuous', 'neurophysiology']
71+ "name": "real-000876-ch45",
72+ "version": "1",
73+ "description": "Real neurophysiology data from DANDI:000876, channel 45",
74+ "create": lambda: _load_real_000876(
75+ num_samples=500_000, num_channels=1, start_channel=45
76+ ).flatten(),
77+ "tags": ["continuous", "neurophysiology"],
7078 },
7179 {
72- 'name': 'real-000409-ch101',
73- 'version': '1',
74- 'description': 'Real neurophysiology data from DANDI:000409, channel 101',
75- 'create': lambda: _load_real_000409(num_samples=500_000, num_channels=1, start_channel=101).flatten(),
76- 'tags': ['continuous', 'neurophysiology']
80+ "name": "real-000409-ch101",
81+ "version": "1",
82+ "description": "Real neurophysiology data from DANDI:000409, channel 101",
83+ "create": lambda: _load_real_000409(
84+ num_samples=500_000, num_channels=1, start_channel=101
85+ ).flatten(),
86+ "tags": ["continuous", "neurophysiology"],
7787 },
7888 {
79- 'name': 'real-001290-ch0',
80- 'version': '1',
81- 'description': 'Real neurophysiology data from DANDI:001290, channel 0',
82- 'create': lambda: _load_real_001290(num_samples=500_000, num_channels=1, start_channel=0).flatten(),
83- 'tags': ['continuous', 'neurophysiology']
84- }
89+ "name": "real-001290-ch0",
90+ "version": "1",
91+ "description": "Real neurophysiology data from DANDI:001290, channel 0",
92+ "create": lambda: _load_real_001290(
93+ num_samples=500_000, num_channels=1, start_channel=0
94+ ).flatten(),
95+ "tags": ["continuous", "neurophysiology"],
96+ },
8597 ]
zia_benchmark/src/zia_benchmark/run_benchmarks.pymodified+68−55View file
@@ -9,7 +9,8 @@ from .datasets import datasets
99 from ._memobin import construct_memobin_url, upload_to_memobin, download_from_memobin
1010
1111
12-system_version = 'v4'
12+system_version = "v4"
13+
1314
1415 def is_compatible(algorithm_tags: List[str], dataset_tags: List[str]) -> bool:
1516 """Check if an algorithm is compatible with a dataset based on their tags.
@@ -22,11 +23,14 @@ def is_compatible(algorithm_tags: List[str], dataset_tags: List[str]) -> bool:
2223 True if the algorithm should be applied to the dataset
2324 """
2425 # If algorithm has delta_encoding tag, dataset must have continuous tag
25- if 'delta_encoding' in algorithm_tags and 'continuous' not in dataset_tags:
26+ if "delta_encoding" in algorithm_tags and "continuous" not in dataset_tags:
2627 return False
2728 return True
2829
29-def run_benchmarks(cache_dir: str = '.benchmark_cache', verbose: bool = True) -> Dict[str, Any]:
30+
31+def run_benchmarks(
32+ cache_dir: str = ".benchmark_cache", verbose: bool = True
33+) -> Dict[str, Any]:
3034 """Run all benchmarks, with caching based on algorithm and dataset versions.
3135
3236 Results are stored in separate directories for each dataset/algorithm combination:
@@ -52,51 +56,58 @@ def run_benchmarks(cache_dir: str = '.benchmark_cache', verbose: bool = True) ->
5256
5357 # Run benchmarks for each dataset and algorithm combination
5458 for dataset in datasets:
55- dataset_tags = dataset.get('tags', [])
59+ dataset_tags = dataset.get("tags", [])
5660 print(f"\n--- Dataset: {dataset['name']} (tags: {dataset_tags}) ---")
5761 # Create dataset once for all algorithms
58- data = dataset['create']()
62+ data = dataset["create"]()
5963 dtype = str(data.dtype)
6064 original_size = len(data.tobytes())
6165 print(f"Created dataset: shape={data.shape}, dtype={dtype}")
6266 print(f"Original size: {original_size:,} bytes")
6367
6468 for algorithm in algorithms:
65- alg_name = algorithm['name']
66- alg_tags = algorithm.get('tags', [])
69+ alg_name = algorithm["name"]
70+ alg_tags = algorithm.get("tags", [])
6771
6872 # Skip if algorithm and dataset are not compatible based on tags
6973 if not is_compatible(alg_tags, dataset_tags):
7074 if verbose:
71- print(f"\nSkipping algorithm {alg_name} (tags: {alg_tags}) - incompatible with dataset tags")
75+ print(
76+ f"\nSkipping algorithm {alg_name} (tags: {alg_tags}) - incompatible with dataset tags"
77+ )
7278 continue
7379
7480 print(f"\nTesting algorithm: {alg_name} (tags: {alg_tags})")
7581
7682 # Check if we can use cached result
77- test_dir = os.path.join(cache_dir, dataset['name'], alg_name)
78- metadata_file = os.path.join(test_dir, 'metadata.json')
79- compressed_file = os.path.join(test_dir, 'compressed.dat')
83+ test_dir = os.path.join(cache_dir, dataset["name"], alg_name)
84+ metadata_file = os.path.join(test_dir, "metadata.json")
85+ compressed_file = os.path.join(test_dir, "compressed.dat")
8086
8187 # First try local cache
8288 cached_data = None
8389 if os.path.exists(metadata_file):
84- with open(metadata_file, 'r') as f:
90+ with open(metadata_file, "r") as f:
8591 cached_data = json.load(f)
8692 # if versions do not match, then set to None
8793 if (
88- cached_data['result']['algorithm_version'] != algorithm['version'] or
89- cached_data['result']['dataset_version'] != dataset['version'] or
90- cached_data['result'].get('system_version', '') != system_version
94+ cached_data["result"]["algorithm_version"]
95+ != algorithm["version"]
96+ or cached_data["result"]["dataset_version"]
97+ != dataset["version"]
98+ or cached_data["result"].get("system_version", "")
99+ != system_version
91100 ):
92101 cached_data = None
93102
94103 # If not in local cache, try memobin
95104 if cached_data is None:
96105 memobin_url = construct_memobin_url(
97- alg_name, dataset['name'],
98- algorithm['version'], dataset['version'],
99- system_version
106+ alg_name,
107+ dataset["name"],
108+ algorithm["version"],
109+ dataset["version"],
110+ system_version,
100111 )
101112 if verbose:
102113 print(" Looking for cached result in memobin...")
@@ -106,16 +117,16 @@ def run_benchmarks(cache_dir: str = '.benchmark_cache', verbose: bool = True) ->
106117 print(" Found result in memobin, saving locally...")
107118 # Save to local cache
108119 os.makedirs(test_dir, exist_ok=True)
109- with open(metadata_file, 'w') as f:
120+ with open(metadata_file, "w") as f:
110121 json.dump(cached_data, f, indent=2)
111122
112123 if cached_data is not None and (
113- cached_data['result']['algorithm_version'] == algorithm['version'] and
114- cached_data['result']['dataset_version'] == dataset['version'] and
115- cached_data['result'].get('system_version', '') == system_version
124+ cached_data["result"]["algorithm_version"] == algorithm["version"]
125+ and cached_data["result"]["dataset_version"] == dataset["version"]
126+ and cached_data["result"].get("system_version", "") == system_version
116127 ):
117128 print(" Using cached result:")
118- results.append(cached_data['result'])
129+ results.append(cached_data["result"])
119130 continue
120131
121132 print(" Running new benchmark...")
@@ -139,8 +150,8 @@ def run_benchmarks(cache_dir: str = '.benchmark_cache', verbose: bool = True) ->
139150 return median_time, mb_per_sec
140151
141152 # Measure encoding with multiple trials
142- encode_time, encode_mb_per_sec = run_timed_trials(algorithm['encode'], data)
143- encoded = algorithm['encode'](data) # One final encode to get the result
153+ encode_time, encode_mb_per_sec = run_timed_trials(algorithm["encode"], data)
154+ encoded = algorithm["encode"](data) # One final encode to get the result
144155 compressed_size = len(encoded)
145156 compression_ratio = original_size / compressed_size
146157 print(" Compression complete:")
@@ -151,8 +162,10 @@ def run_benchmarks(cache_dir: str = '.benchmark_cache', verbose: bool = True) ->
151162
152163 print(" Verifying decompression...")
153164 # Measure decoding with multiple trials
154- decode_time, decode_mb_per_sec = run_timed_trials(algorithm['decode'], encoded, dtype)
155- decoded = algorithm['decode'](encoded, dtype) # One final decode to verify
165+ decode_time, decode_mb_per_sec = run_timed_trials(
166+ algorithm["decode"], encoded, dtype
167+ )
168+ decoded = algorithm["decode"](encoded, dtype) # One final decode to verify
156169 print(f" Decode time: {decode_time*1000:.2f}ms")
157170 print(f" Decode throughput: {decode_mb_per_sec:.2f} MB/s")
158171
@@ -165,52 +178,52 @@ def run_benchmarks(cache_dir: str = '.benchmark_cache', verbose: bool = True) ->
165178
166179 # Store result
167180 result = {
168- 'dataset': dataset['name'],
169- 'algorithm': alg_name,
170- 'algorithm_version': algorithm['version'],
171- 'dataset_version': dataset['version'],
172- 'system_version': system_version,
173- 'compression_ratio': compression_ratio,
174- 'encode_time': encode_time,
175- 'decode_time': decode_time,
176- 'encode_mb_per_sec': encode_mb_per_sec,
177- 'decode_mb_per_sec': decode_mb_per_sec,
178- 'original_size': original_size,
179- 'compressed_size': compressed_size,
180- 'array_shape': data.shape,
181- 'array_dtype': dtype,
182- 'timestamp': time.time()
181+ "dataset": dataset["name"],
182+ "algorithm": alg_name,
183+ "algorithm_version": algorithm["version"],
184+ "dataset_version": dataset["version"],
185+ "system_version": system_version,
186+ "compression_ratio": compression_ratio,
187+ "encode_time": encode_time,
188+ "decode_time": decode_time,
189+ "encode_mb_per_sec": encode_mb_per_sec,
190+ "decode_mb_per_sec": decode_mb_per_sec,
191+ "original_size": original_size,
192+ "compressed_size": compressed_size,
193+ "array_shape": data.shape,
194+ "array_dtype": dtype,
195+ "timestamp": time.time(),
183196 }
184197 results.append(result)
185198
186199 # Save result and compressed data
187200 os.makedirs(test_dir, exist_ok=True)
188- cache_data = {
189- 'result': result
190- }
191- with open(metadata_file, 'w') as f:
201+ cache_data = {"result": result}
202+ with open(metadata_file, "w") as f:
192203 json.dump(cache_data, f, indent=2)
193- with open(compressed_file, 'wb') as f:
204+ with open(compressed_file, "wb") as f:
194205 f.write(encoded)
195206 print(f" Results saved to: {test_dir}")
196207
197208 # Upload to memobin if API key is set and upload is enabled
198- memobin_api_key = os.environ.get('MEMOBIN_API_KEY')
199- upload_enabled = os.environ.get('UPLOAD_TO_MEMOBIN') == '1'
209+ memobin_api_key = os.environ.get("MEMOBIN_API_KEY")
210+ upload_enabled = os.environ.get("UPLOAD_TO_MEMOBIN") == "1"
200211 if memobin_api_key and upload_enabled:
201212 if verbose:
202213 print(" Uploading results to memobin...")
203214 try:
204215 memobin_url = construct_memobin_url(
205- alg_name, dataset['name'],
206- algorithm['version'], dataset['version'],
207- system_version
216+ alg_name,
217+ dataset["name"],
218+ algorithm["version"],
219+ dataset["version"],
220+ system_version,
208221 )
209222 upload_to_memobin(
210223 cache_data,
211224 memobin_url,
212- os.environ.get('MEMOBIN_USER_ID', 'default'),
213- memobin_api_key
225+ os.environ.get("MEMOBIN_USER_ID", "default"),
226+ memobin_api_key,
214227 )
215228 if verbose:
216229 print(" Successfully uploaded to memobin")
@@ -218,4 +231,4 @@ def run_benchmarks(cache_dir: str = '.benchmark_cache', verbose: bool = True) ->
218231 print(f" Warning: Failed to upload to memobin: {str(e)}")
219232
220233 print("\n=== Benchmark Run Complete ===\n")
221- return {'results': results}
234+ return {"results": results}