/ concept-collection / benchcompress
Sign in
concept-collection / benchcompress
paper page
Jeremy Magland <jmagland@flatironinstitute.org> committed commit 00922833add9 parent bcd9497 Browse files
13 changed files+543−63
web-ui/package-lock.jsonmodified+291−1View file
@@ -11,12 +11,15 @@
1111 "@tanstack/react-table": "^8.20.6",
1212 "@types/plotly.js": "^2.35.2",
1313 "axios": "^1.7.9",
14+ "katex": "^0.16.21",
1415 "plotly.js-dist-min": "^2.35.3",
1516 "react": "^18.3.1",
1617 "react-dom": "^18.3.1",
1718 "react-markdown": "^9.0.3",
1819 "react-plotly.js": "^2.6.0",
19- "react-router-dom": "^7.1.3"
20+ "react-router-dom": "^7.1.3",
21+ "rehype-katex": "^7.0.1",
22+ "remark-math": "^6.0.0"
2023 },
2124 "devDependencies": {
2225 "@eslint/js": "^9.17.0",
@@ -1654,6 +1657,11 @@
16541657 "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
16551658 "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="
16561659 },
1660+ "node_modules/@types/katex": {
1661+ "version": "0.16.7",
1662+ "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.7.tgz",
1663+ "integrity": "sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ=="
1664+ },
16571665 "node_modules/@types/mapbox__point-geometry": {
16581666 "version": "0.1.4",
16591667 "resolved": "https://registry.npmjs.org/@types/mapbox__point-geometry/-/mapbox__point-geometry-0.1.4.tgz",
@@ -3181,6 +3189,17 @@
31813189 "node": ">=10.13.0"
31823190 }
31833191 },
3192+ "node_modules/entities": {
3193+ "version": "4.5.0",
3194+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
3195+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
3196+ "engines": {
3197+ "node": ">=0.12"
3198+ },
3199+ "funding": {
3200+ "url": "https://github.com/fb55/entities?sponsor=1"
3201+ }
3202+ },
31843203 "node_modules/es-module-lexer": {
31853204 "version": "1.6.0",
31863205 "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz",
@@ -4232,6 +4251,95 @@
42324251 "node": ">= 0.4"
42334252 }
42344253 },
4254+ "node_modules/hast-util-from-dom": {
4255+ "version": "5.0.1",
4256+ "resolved": "https://registry.npmjs.org/hast-util-from-dom/-/hast-util-from-dom-5.0.1.tgz",
4257+ "integrity": "sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==",
4258+ "dependencies": {
4259+ "@types/hast": "^3.0.0",
4260+ "hastscript": "^9.0.0",
4261+ "web-namespaces": "^2.0.0"
4262+ },
4263+ "funding": {
4264+ "type": "opencollective",
4265+ "url": "https://opencollective.com/unified"
4266+ }
4267+ },
4268+ "node_modules/hast-util-from-html": {
4269+ "version": "2.0.3",
4270+ "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz",
4271+ "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==",
4272+ "dependencies": {
4273+ "@types/hast": "^3.0.0",
4274+ "devlop": "^1.1.0",
4275+ "hast-util-from-parse5": "^8.0.0",
4276+ "parse5": "^7.0.0",
4277+ "vfile": "^6.0.0",
4278+ "vfile-message": "^4.0.0"
4279+ },
4280+ "funding": {
4281+ "type": "opencollective",
4282+ "url": "https://opencollective.com/unified"
4283+ }
4284+ },
4285+ "node_modules/hast-util-from-html-isomorphic": {
4286+ "version": "2.0.0",
4287+ "resolved": "https://registry.npmjs.org/hast-util-from-html-isomorphic/-/hast-util-from-html-isomorphic-2.0.0.tgz",
4288+ "integrity": "sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==",
4289+ "dependencies": {
4290+ "@types/hast": "^3.0.0",
4291+ "hast-util-from-dom": "^5.0.0",
4292+ "hast-util-from-html": "^2.0.0",
4293+ "unist-util-remove-position": "^5.0.0"
4294+ },
4295+ "funding": {
4296+ "type": "opencollective",
4297+ "url": "https://opencollective.com/unified"
4298+ }
4299+ },
4300+ "node_modules/hast-util-from-parse5": {
4301+ "version": "8.0.2",
4302+ "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.2.tgz",
4303+ "integrity": "sha512-SfMzfdAi/zAoZ1KkFEyyeXBn7u/ShQrfd675ZEE9M3qj+PMFX05xubzRyF76CCSJu8au9jgVxDV1+okFvgZU4A==",
4304+ "dependencies": {
4305+ "@types/hast": "^3.0.0",
4306+ "@types/unist": "^3.0.0",
4307+ "devlop": "^1.0.0",
4308+ "hastscript": "^9.0.0",
4309+ "property-information": "^6.0.0",
4310+ "vfile": "^6.0.0",
4311+ "vfile-location": "^5.0.0",
4312+ "web-namespaces": "^2.0.0"
4313+ },
4314+ "funding": {
4315+ "type": "opencollective",
4316+ "url": "https://opencollective.com/unified"
4317+ }
4318+ },
4319+ "node_modules/hast-util-is-element": {
4320+ "version": "3.0.0",
4321+ "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz",
4322+ "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==",
4323+ "dependencies": {
4324+ "@types/hast": "^3.0.0"
4325+ },
4326+ "funding": {
4327+ "type": "opencollective",
4328+ "url": "https://opencollective.com/unified"
4329+ }
4330+ },
4331+ "node_modules/hast-util-parse-selector": {
4332+ "version": "4.0.0",
4333+ "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz",
4334+ "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==",
4335+ "dependencies": {
4336+ "@types/hast": "^3.0.0"
4337+ },
4338+ "funding": {
4339+ "type": "opencollective",
4340+ "url": "https://opencollective.com/unified"
4341+ }
4342+ },
42354343 "node_modules/hast-util-to-jsx-runtime": {
42364344 "version": "2.3.2",
42374345 "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.2.tgz",
@@ -4258,6 +4366,21 @@
42584366 "url": "https://opencollective.com/unified"
42594367 }
42604368 },
4369+ "node_modules/hast-util-to-text": {
4370+ "version": "4.0.2",
4371+ "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz",
4372+ "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==",
4373+ "dependencies": {
4374+ "@types/hast": "^3.0.0",
4375+ "@types/unist": "^3.0.0",
4376+ "hast-util-is-element": "^3.0.0",
4377+ "unist-util-find-after": "^5.0.0"
4378+ },
4379+ "funding": {
4380+ "type": "opencollective",
4381+ "url": "https://opencollective.com/unified"
4382+ }
4383+ },
42614384 "node_modules/hast-util-whitespace": {
42624385 "version": "3.0.0",
42634386 "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz",
@@ -4270,6 +4393,22 @@
42704393 "url": "https://opencollective.com/unified"
42714394 }
42724395 },
4396+ "node_modules/hastscript": {
4397+ "version": "9.0.0",
4398+ "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.0.tgz",
4399+ "integrity": "sha512-jzaLBGavEDKHrc5EfFImKN7nZKKBdSLIdGvCwDZ9TfzbF2ffXiov8CKE445L2Z1Ek2t/m4SKQ2j6Ipv7NyUolw==",
4400+ "dependencies": {
4401+ "@types/hast": "^3.0.0",
4402+ "comma-separated-tokens": "^2.0.0",
4403+ "hast-util-parse-selector": "^4.0.0",
4404+ "property-information": "^6.0.0",
4405+ "space-separated-tokens": "^2.0.0"
4406+ },
4407+ "funding": {
4408+ "type": "opencollective",
4409+ "url": "https://opencollective.com/unified"
4410+ }
4411+ },
42734412 "node_modules/hsluv": {
42744413 "version": "0.0.3",
42754414 "resolved": "https://registry.npmjs.org/hsluv/-/hsluv-0.0.3.tgz",
@@ -4651,6 +4790,29 @@
46514790 "node": ">=6"
46524791 }
46534792 },
4793+ "node_modules/katex": {
4794+ "version": "0.16.21",
4795+ "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.21.tgz",
4796+ "integrity": "sha512-XvqR7FgOHtWupfMiigNzmh+MgUVmDGU2kXZm899ZkPfcuoPuFxyHmXsgATDpFZDAXCI8tvinaVcDo8PIIJSo4A==",
4797+ "funding": [
4798+ "https://opencollective.com/katex",
4799+ "https://github.com/sponsors/katex"
4800+ ],
4801+ "dependencies": {
4802+ "commander": "^8.3.0"
4803+ },
4804+ "bin": {
4805+ "katex": "cli.js"
4806+ }
4807+ },
4808+ "node_modules/katex/node_modules/commander": {
4809+ "version": "8.3.0",
4810+ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
4811+ "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
4812+ "engines": {
4813+ "node": ">= 12"
4814+ }
4815+ },
46544816 "node_modules/kdbush": {
46554817 "version": "4.0.2",
46564818 "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz",
@@ -4921,6 +5083,24 @@
49215083 "url": "https://opencollective.com/unified"
49225084 }
49235085 },
5086+ "node_modules/mdast-util-math": {
5087+ "version": "3.0.0",
5088+ "resolved": "https://registry.npmjs.org/mdast-util-math/-/mdast-util-math-3.0.0.tgz",
5089+ "integrity": "sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==",
5090+ "dependencies": {
5091+ "@types/hast": "^3.0.0",
5092+ "@types/mdast": "^4.0.0",
5093+ "devlop": "^1.0.0",
5094+ "longest-streak": "^3.0.0",
5095+ "mdast-util-from-markdown": "^2.0.0",
5096+ "mdast-util-to-markdown": "^2.1.0",
5097+ "unist-util-remove-position": "^5.0.0"
5098+ },
5099+ "funding": {
5100+ "type": "opencollective",
5101+ "url": "https://opencollective.com/unified"
5102+ }
5103+ },
49245104 "node_modules/mdast-util-mdx-expression": {
49255105 "version": "2.0.1",
49265106 "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz",
@@ -5125,6 +5305,24 @@
51255305 "micromark-util-types": "^2.0.0"
51265306 }
51275307 },
5308+ "node_modules/micromark-extension-math": {
5309+ "version": "3.1.0",
5310+ "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz",
5311+ "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==",
5312+ "dependencies": {
5313+ "@types/katex": "^0.16.0",
5314+ "devlop": "^1.0.0",
5315+ "katex": "^0.16.0",
5316+ "micromark-factory-space": "^2.0.0",
5317+ "micromark-util-character": "^2.0.0",
5318+ "micromark-util-symbol": "^2.0.0",
5319+ "micromark-util-types": "^2.0.0"
5320+ },
5321+ "funding": {
5322+ "type": "opencollective",
5323+ "url": "https://opencollective.com/unified"
5324+ }
5325+ },
51285326 "node_modules/micromark-factory-destination": {
51295327 "version": "2.0.1",
51305328 "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz",
@@ -5810,6 +6008,17 @@
58106008 "integrity": "sha512-hrqldJHokR3Qj88EIlV/kAyAi/G5R2+R56TBANxNMy0uPlYcttx0jnMW6Yx5KsKPSbC3KddM/7qQm3+0wEXKxg==",
58116009 "peer": true
58126010 },
6011+ "node_modules/parse5": {
6012+ "version": "7.2.1",
6013+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz",
6014+ "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==",
6015+ "dependencies": {
6016+ "entities": "^4.5.0"
6017+ },
6018+ "funding": {
6019+ "url": "https://github.com/inikulin/parse5?sponsor=1"
6020+ }
6021+ },
58136022 "node_modules/path-exists": {
58146023 "version": "4.0.0",
58156024 "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -6405,6 +6614,39 @@
64056614 "regl-scatter2d": "^3.2.3"
64066615 }
64076616 },
6617+ "node_modules/rehype-katex": {
6618+ "version": "7.0.1",
6619+ "resolved": "https://registry.npmjs.org/rehype-katex/-/rehype-katex-7.0.1.tgz",
6620+ "integrity": "sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==",
6621+ "dependencies": {
6622+ "@types/hast": "^3.0.0",
6623+ "@types/katex": "^0.16.0",
6624+ "hast-util-from-html-isomorphic": "^2.0.0",
6625+ "hast-util-to-text": "^4.0.0",
6626+ "katex": "^0.16.0",
6627+ "unist-util-visit-parents": "^6.0.0",
6628+ "vfile": "^6.0.0"
6629+ },
6630+ "funding": {
6631+ "type": "opencollective",
6632+ "url": "https://opencollective.com/unified"
6633+ }
6634+ },
6635+ "node_modules/remark-math": {
6636+ "version": "6.0.0",
6637+ "resolved": "https://registry.npmjs.org/remark-math/-/remark-math-6.0.0.tgz",
6638+ "integrity": "sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==",
6639+ "dependencies": {
6640+ "@types/mdast": "^4.0.0",
6641+ "mdast-util-math": "^3.0.0",
6642+ "micromark-extension-math": "^3.0.0",
6643+ "unified": "^11.0.0"
6644+ },
6645+ "funding": {
6646+ "type": "opencollective",
6647+ "url": "https://opencollective.com/unified"
6648+ }
6649+ },
64086650 "node_modules/remark-parse": {
64096651 "version": "11.0.0",
64106652 "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz",
@@ -7256,6 +7498,19 @@
72567498 "url": "https://github.com/sponsors/sindresorhus"
72577499 }
72587500 },
7501+ "node_modules/unist-util-find-after": {
7502+ "version": "5.0.0",
7503+ "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz",
7504+ "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==",
7505+ "dependencies": {
7506+ "@types/unist": "^3.0.0",
7507+ "unist-util-is": "^6.0.0"
7508+ },
7509+ "funding": {
7510+ "type": "opencollective",
7511+ "url": "https://opencollective.com/unified"
7512+ }
7513+ },
72597514 "node_modules/unist-util-is": {
72607515 "version": "6.0.0",
72617516 "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz",
@@ -7280,6 +7535,19 @@
72807535 "url": "https://opencollective.com/unified"
72817536 }
72827537 },
7538+ "node_modules/unist-util-remove-position": {
7539+ "version": "5.0.0",
7540+ "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz",
7541+ "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==",
7542+ "dependencies": {
7543+ "@types/unist": "^3.0.0",
7544+ "unist-util-visit": "^5.0.0"
7545+ },
7546+ "funding": {
7547+ "type": "opencollective",
7548+ "url": "https://opencollective.com/unified"
7549+ }
7550+ },
72837551 "node_modules/unist-util-stringify-position": {
72847552 "version": "4.0.0",
72857553 "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz",
@@ -7387,6 +7655,19 @@
73877655 "url": "https://opencollective.com/unified"
73887656 }
73897657 },
7658+ "node_modules/vfile-location": {
7659+ "version": "5.0.3",
7660+ "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz",
7661+ "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==",
7662+ "dependencies": {
7663+ "@types/unist": "^3.0.0",
7664+ "vfile": "^6.0.0"
7665+ },
7666+ "funding": {
7667+ "type": "opencollective",
7668+ "url": "https://opencollective.com/unified"
7669+ }
7670+ },
73907671 "node_modules/vfile-message": {
73917672 "version": "4.0.2",
73927673 "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz",
@@ -7501,6 +7782,15 @@
75017782 "integrity": "sha512-lNR9aAefbGPpHO7AEnY0hCFjz1eTkWCXYvkTRrTHs9qv8zJp+SkVYpzfLIFXQQiG3tVvbNFQgVg2bQS8YGgxyw==",
75027783 "peer": true
75037784 },
7785+ "node_modules/web-namespaces": {
7786+ "version": "2.0.1",
7787+ "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz",
7788+ "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==",
7789+ "funding": {
7790+ "type": "github",
7791+ "url": "https://github.com/sponsors/wooorm"
7792+ }
7793+ },
75047794 "node_modules/webgl-context": {
75057795 "version": "2.2.0",
75067796 "resolved": "https://registry.npmjs.org/webgl-context/-/webgl-context-2.2.0.tgz",
web-ui/package.jsonmodified+4−1View file
@@ -15,12 +15,15 @@
1515 "@tanstack/react-table": "^8.20.6",
1616 "@types/plotly.js": "^2.35.2",
1717 "axios": "^1.7.9",
18+ "katex": "^0.16.21",
1819 "plotly.js-dist-min": "^2.35.3",
1920 "react": "^18.3.1",
2021 "react-dom": "^18.3.1",
2122 "react-markdown": "^9.0.3",
2223 "react-plotly.js": "^2.6.0",
23- "react-router-dom": "^7.1.3"
24+ "react-router-dom": "^7.1.3",
25+ "rehype-katex": "^7.0.1",
26+ "remark-math": "^6.0.0"
2427 },
2528 "devDependencies": {
2629 "@eslint/js": "^9.17.0",
web-ui/src/App.tsxmodified+24−10View file
@@ -5,6 +5,7 @@ import { ScrollToTop } from "./components/ScrollToTop";
55 import "./components/AppHeader.css";
66 import Home from "./pages/Home";
77 import About from "./pages/About";
8+import Paper from "./pages/Paper";
89 import { BenchmarkData } from "./types";
910
1011 function App() {
@@ -111,16 +112,28 @@ function App() {
111112 </span>
112113 </span>
113114 </Link>
114- <Link
115- to="/about"
116- style={{
117- color: "#0066cc",
118- textDecoration: "none",
119- fontWeight: "500",
120- }}
121- >
122- About
123- </Link>
115+ <div style={{ display: "flex", gap: "1.5rem" }}>
116+ <Link
117+ to="/paper"
118+ style={{
119+ color: "#0066cc",
120+ textDecoration: "none",
121+ fontWeight: "500",
122+ }}
123+ >
124+ Paper
125+ </Link>
126+ <Link
127+ to="/about"
128+ style={{
129+ color: "#0066cc",
130+ textDecoration: "none",
131+ fontWeight: "500",
132+ }}
133+ >
134+ About
135+ </Link>
136+ </div>
124137 </div>
125138 </nav>
126139 <main>
@@ -148,6 +161,7 @@ function App() {
148161 element={<Home benchmarkData={benchmarkData} />}
149162 />
150163 <Route path="/about" element={<About />} />
164+ <Route path="/paper" element={<Paper />} />
151165 </Routes>
152166 )}
153167 </main>
web-ui/src/components/algorithm/AlgorithmContent.cssadded+15−0View file
@@ -0,0 +1,15 @@
1+.algorithm-tag {
2+ display: inline-block;
3+ background-color: #e1e1e1;
4+ padding: 2px 6px;
5+ border-radius: 3px;
6+ margin: 2px;
7+ font-size: 0.8rem;
8+ cursor: pointer;
9+ transition: all 0.2s ease;
10+}
11+
12+.algorithm-tag:hover {
13+ background-color: #d1d1d1;
14+ transform: translateY(-1px);
15+}
web-ui/src/components/algorithm/AlgorithmContent.tsxmodified+6−8View file
@@ -1,4 +1,6 @@
11 import { Algorithm, BenchmarkData } from "../../types";
2+import "./AlgorithmContent.css";
3+import { useNavigate } from "react-router-dom";
24 import { BenchmarkCharts } from "../benchmark/charts/BenchmarkCharts";
35 import { BenchmarkTable } from "../benchmark/table/BenchmarkTable";
46
@@ -20,6 +22,8 @@ export const AlgorithmContent = ({
2022 benchmarkData,
2123 chartData,
2224 }: AlgorithmContentProps) => {
25+ const navigate = useNavigate();
26+
2327 return (
2428 <div>
2529 <div style={{ marginBottom: "1.5rem" }}>
@@ -45,15 +49,9 @@ export const AlgorithmContent = ({
4549 <span style={{ fontWeight: "bold", fontSize: "0.9rem" }}>Tags: </span>
4650 {algorithm.tags.map((tag) => (
4751 <span
52+ onClick={() => navigate(`/algorithms?tag=${tag}`)}
4853 key={tag}
49- style={{
50- display: "inline-block",
51- backgroundColor: "#e1e1e1",
52- padding: "2px 6px",
53- borderRadius: "3px",
54- margin: "2px",
55- fontSize: "0.8rem",
56- }}
54+ className="algorithm-tag"
5755 >
5856 {tag}
5957 </span>
web-ui/src/components/dataset/DatasetContent.cssadded+15−0View file
@@ -0,0 +1,15 @@
1+.dataset-tag {
2+ display: inline-block;
3+ background-color: #e1e1e1;
4+ padding: 2px 6px;
5+ border-radius: 3px;
6+ margin: 2px;
7+ font-size: 0.8rem;
8+ cursor: pointer;
9+ transition: all 0.2s ease;
10+}
11+
12+.dataset-tag:hover {
13+ background-color: #d1d1d1;
14+ transform: translateY(-1px);
15+}
web-ui/src/components/dataset/DatasetContent.tsxmodified+5−8View file
@@ -1,4 +1,6 @@
11 import { Dataset, BenchmarkData } from "../../types";
2+import { useNavigate } from "react-router-dom";
3+import "./DatasetContent.css";
24 import TimeseriesView from "./TimeseriesView";
35 import { BenchmarkCharts } from "../benchmark/charts/BenchmarkCharts";
46 import { BenchmarkTable } from "../benchmark/table/BenchmarkTable";
@@ -21,6 +23,7 @@ export const DatasetContent = ({
2123 benchmarkData,
2224 chartData,
2325 }: DatasetContentProps) => {
26+ const navigate = useNavigate();
2427 const containerRef = useRef<HTMLDivElement>(null);
2528 const [containerWidth, setContainerWidth] = useState(1200);
2629
@@ -66,14 +69,8 @@ export const DatasetContent = ({
6669 {dataset.tags.map((tag) => (
6770 <span
6871 key={tag}
69- style={{
70- display: "inline-block",
71- backgroundColor: "#e1e1e1",
72- padding: "2px 6px",
73- borderRadius: "3px",
74- margin: "2px",
75- fontSize: "0.8rem",
76- }}
72+ className="dataset-tag"
73+ onClick={() => navigate(`/datasets?tag=${tag}`)}
7774 >
7875 {tag}
7976 </span>
web-ui/src/components/tables/DatasetAlgorithmTables.tsxmodified+12−12View file
@@ -5,29 +5,29 @@ import { Dataset, Algorithm } from "../../types";
55 interface DatasetTableProps {
66 filteredDatasets: Dataset[];
77 availableDatasetTags: string[];
8- datasetTags: string[];
9- toggleDatasetTag: (tag: string) => void;
8+ selectedTags: string[];
9+ toggleTag: (tag: string) => void;
1010 }
1111
1212 interface AlgorithmTableProps {
1313 filteredAlgorithms: Algorithm[];
1414 availableAlgorithmTags: string[];
15- algorithmTags: string[];
16- toggleAlgorithmTag: (tag: string) => void;
15+ selectedTags: string[];
16+ toggleTag: (tag: string) => void;
1717 }
1818
1919 export const DatasetTable = ({
2020 filteredDatasets,
2121 availableDatasetTags,
22- datasetTags,
23- toggleDatasetTag,
22+ selectedTags,
23+ toggleTag,
2424 }: DatasetTableProps) => (
2525 <div style={{ overflowX: "auto" }}>
2626 <div style={{ marginBottom: "1rem" }}>
2727 <TagFilter
2828 availableTags={availableDatasetTags}
29- selectedTags={datasetTags}
30- onTagToggle={toggleDatasetTag}
29+ selectedTags={selectedTags}
30+ onTagToggle={toggleTag}
3131 label="Filter datasets"
3232 />
3333 </div>
@@ -212,15 +212,15 @@ export const DatasetTable = ({
212212 export const AlgorithmTable = ({
213213 filteredAlgorithms,
214214 availableAlgorithmTags,
215- algorithmTags,
216- toggleAlgorithmTag,
215+ selectedTags,
216+ toggleTag,
217217 }: AlgorithmTableProps) => (
218218 <div style={{ overflowX: "auto" }}>
219219 <div style={{ marginBottom: "1rem" }}>
220220 <TagFilter
221221 availableTags={availableAlgorithmTags}
222- selectedTags={algorithmTags}
223- onTagToggle={toggleAlgorithmTag}
222+ selectedTags={selectedTags}
223+ onTagToggle={toggleTag}
224224 label="Filter algorithms"
225225 />
226226 </div>
web-ui/src/hooks/useTagFilter.tsmodified+4−11View file
@@ -4,9 +4,10 @@ interface TaggableItem {
44 tags: string[];
55 }
66
7-export function useTagFilter<T extends TaggableItem>(items: T[]) {
8- const [selectedTags, setSelectedTags] = useState<string[]>([]);
9-
7+export function useTagFilter<T extends TaggableItem>(
8+ items: T[],
9+ selectedTags: string[],
10+) {
1011 const availableTags = useMemo(() => {
1112 const tagSet = new Set<string>();
1213 items.forEach((item) => {
@@ -22,16 +23,8 @@ export function useTagFilter<T extends TaggableItem>(items: T[]) {
2223 );
2324 }, [items, selectedTags]);
2425
25- const toggleTag = (tag: string) => {
26- setSelectedTags((prev) =>
27- prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag],
28- );
29- };
30-
3126 return {
32- selectedTags,
3327 availableTags,
3428 filteredItems,
35- toggleTag,
3629 };
3730 }
web-ui/src/pages/Home.tsxmodified+30−12View file
@@ -81,21 +81,39 @@ export default function Home({ benchmarkData }: HomeProps) {
8181
8282 console.log("chartData", chartData);
8383
84- // Set up tag filtering for datasets
84+ // Get selected tags from URL
85+ const searchParams = new URLSearchParams(location.search);
86+ const selectedTags = searchParams.get("tag")?.split(",") || [];
87+
88+ // Set up tag filtering for datasets and algorithms
8589 const {
86- selectedTags: datasetTags,
8790 availableTags: availableDatasetTags,
8891 filteredItems: filteredDatasets,
89- toggleTag: toggleDatasetTag,
90- } = useTagFilter(benchmarkData?.datasets || []);
92+ } = useTagFilter(
93+ benchmarkData?.datasets || [],
94+ location.pathname.includes("/datasets") ? selectedTags : [],
95+ );
9196
92- // Set up tag filtering for algorithms
9397 const {
94- selectedTags: algorithmTags,
9598 availableTags: availableAlgorithmTags,
9699 filteredItems: filteredAlgorithms,
97- toggleTag: toggleAlgorithmTag,
98- } = useTagFilter(benchmarkData?.algorithms || []);
100+ } = useTagFilter(
101+ benchmarkData?.algorithms || [],
102+ location.pathname.includes("/algorithms") ? selectedTags : [],
103+ );
104+
105+ // Handle tag toggling by updating URL
106+ const handleTagToggle = (tag: string) => {
107+ const newTags = selectedTags.includes(tag)
108+ ? selectedTags.filter((t) => t !== tag)
109+ : [...selectedTags, tag];
110+
111+ const params = new URLSearchParams();
112+ if (newTags.length > 0) {
113+ params.set("tag", newTags.join(","));
114+ }
115+ navigate({ search: params.toString() });
116+ };
99117
100118 return (
101119 <div>
@@ -216,15 +234,15 @@ export default function Home({ benchmarkData }: HomeProps) {
216234 <DatasetTable
217235 filteredDatasets={filteredDatasets}
218236 availableDatasetTags={availableDatasetTags}
219- datasetTags={datasetTags}
220- toggleDatasetTag={toggleDatasetTag}
237+ selectedTags={selectedTags}
238+ toggleTag={handleTagToggle}
221239 />
222240 ) : (
223241 <AlgorithmTable
224242 filteredAlgorithms={filteredAlgorithms}
225243 availableAlgorithmTags={availableAlgorithmTags}
226- algorithmTags={algorithmTags}
227- toggleAlgorithmTag={toggleAlgorithmTag}
244+ selectedTags={selectedTags}
245+ toggleTag={handleTagToggle}
228246 />
229247 )}
230248 </div>
web-ui/src/pages/Paper.cssadded+53−0View file
@@ -0,0 +1,53 @@
1+.paper-container {
2+ max-width: 800px;
3+ margin: 0 auto;
4+ padding: 1.5rem;
5+ background-color: white;
6+ box-shadow: 0 0 10px rgba(0,0,0,0.1);
7+ font-family: 'Roboto', sans-serif;
8+}
9+
10+.paper-content h1 {
11+ font-size: 22px;
12+ font-weight: bold;
13+ margin-bottom: 0.5rem;
14+ text-align: center;
15+}
16+
17+.paper-content h2 {
18+ font-size: 16px;
19+ font-weight: bold;
20+ margin-top: 1rem;
21+ margin-bottom: 0.5rem;
22+}
23+
24+.paper-content h3 {
25+ font-size: 14px;
26+ font-weight: bold;
27+ margin-top: 1rem;
28+ margin-bottom: 0.25rem;
29+}
30+
31+.paper-content p {
32+ font-size: 15px;
33+ line-height: 1.3;
34+ margin-bottom: 0.5rem;
35+ text-align: justify;
36+}
37+
38+.paper-content em {
39+ font-style: italic;
40+}
41+
42+.paper-content .math-display {
43+ margin: 0.5rem 0;
44+ overflow-x: auto;
45+ text-align: center;
46+}
47+
48+.paper-content code {
49+ font-size: 12px;
50+ background-color: #f5f5f5;
51+ padding: 1px 3px;
52+ border-radius: 2px;
53+}
web-ui/src/pages/Paper.tsxadded+24−0View file
@@ -0,0 +1,24 @@
1+import React from "react";
2+import ReactMarkdown from "react-markdown";
3+import remarkMath from "remark-math";
4+import rehypeKatex from "rehype-katex";
5+import paperContent from "./paper.md?raw";
6+import "katex/dist/katex.min.css";
7+import "./Paper.css";
8+
9+const Paper: React.FC = () => {
10+ return (
11+ <div className="paper-container">
12+ <div className="paper-content">
13+ <ReactMarkdown
14+ remarkPlugins={[remarkMath]}
15+ rehypePlugins={[rehypeKatex]}
16+ >
17+ {paperContent}
18+ </ReactMarkdown>
19+ </div>
20+ </div>
21+ );
22+};
23+
24+export default Paper;
web-ui/src/pages/paper.mdadded+60−0View file
@@ -0,0 +1,60 @@
1+# Benchmarking Compression Algorithms for Numeric Scientific Data
2+
3+*Jeremy Magland, Center for Computational Mathematics, Flatiron Institute*
4+
5+*Last updated: January 2025*
6+
7+**This is a draft paper, work in progress.**
8+
9+## Abstract
10+
11+*Benchcompress* is a benchmarking framework designed to evaluate the performance of various compression algorithms on numeric array datasets, with a particular focus on scientific data. The framework automates the benchmarking process, measuring compression ratio, encoding throughput, and decoding throughput for each algorithm-dataset pair. Results are verified through decompression and comparison with the original data, ensuring accuracy and reliability. The benchmark results are stored and visualized through an interactive web interface, allowing users to filter, sort, and explore the data. This paper presents the design, implementation, and preliminary results of Benchcompress, highlighting its utility in identifying optimal compression techniques for scientific datasets.
12+
13+## Introduction
14+
15+This is the introduction.
16+
17+## Methods
18+
19+### Compression Algorithms
20+
21+Describe the various compression methods.
22+
23+### Dataset Generation
24+
25+Describe the datasets we use for benchmarking.
26+
27+## Theory
28+
29+For independently and identically distributed (i.i.d.) discrete data, where each sample is drawn from a discrete probability distribution (e.g., Bernoulli sampling or quantized Gaussian noise), the theoretical compressed size in bits per sample is determined by the Shannon entropy formula:
30+$$
31+H(X) = -\sum_{i} p(x_i) \log_2 p(x_i).
32+$$
33+
34+Here, $p(x_i)$ represents the probability of occurrence of the $i$-th symbol $x_i$ in the discrete distribution. So for example, if we have a Bernoulli distribution with $p=0.5$, the entropy is
35+$$
36+H_{\text{Bernoulli, p=0.5}} = -0.5 \log_2 0.5 - 0.5 \log_2 0.5 = 1
37+$$
38+bits per sample. This means that the optimal compression ratio for such a dataset is 8, assuming the samples are stored as 8-bit integers. On the other hand, if $p\neq 0.5$, the entropy becomes lower and we can achieve compression at a rate of less than 1 bit per sample (e.g., for $p=0.1$, the entropy is around 0.47 bits per sample, so the compression ratio would be around 17).
39+
40+In practice, achieving this theoretical compression ratio requires sophisticated encoding techniques. Arithmetic encoding [ref] is one such method, but it is challenging to implement and can be computationally inefficient. A more modern and efficient alternative is Asymmetric Numeric Systems (ANS) [ref], which closely approaches the theoretical limit and is incorporated into state-of-the-art compressors such as ZStandard [ref]. However, these algorithms are primarily optimized for structured data types, such as text, rather than for scientific numerical data.
41+
42+In our benchmarks, we evaluate a simple implementation of ANS using a Python package we developed, called `simple_ans`. As anticipated, ANS demonstrates superior performance when compressing i.i.d. samples from a discrete distribution. However, its efficiency diminishes when handling more structured data, such as continuous signals (e.g., voltage traces in electrophysiology).
43+
44+Applying delta encoding partially mitigates this limitation by leveraging the continuity properties of the data through differencing. This preprocessing step enhances ANS performance, though it still falls short of the compression achieved by methods like ZStandard. Additional preprocessing techniques, such as linear Markov predictive modeling (where the residual error after prediction is compressed instead of the original signal), further improve ANS performance. In these scenarios, the residual data is smaller and exhibits reduced correlation, enabling ANS to achieve better compression results relative to other methods.
45+
46+## Implementation
47+
48+[To be added]
49+
50+## Results
51+
52+[Preliminary results to be added]
53+
54+## Discussion
55+
56+[Discussion to be added]
57+
58+## Conclusion
59+
60+[Conclusion to be added]
moveopenescclose