BenchMatcha 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- benchmatcha-0.0.1/LICENSE +28 -0
- benchmatcha-0.0.1/PKG-INFO +147 -0
- benchmatcha-0.0.1/README.md +70 -0
- benchmatcha-0.0.1/pyproject.toml +169 -0
- benchmatcha-0.0.1/requirements.txt +8 -0
- benchmatcha-0.0.1/setup.cfg +4 -0
- benchmatcha-0.0.1/src/BenchMatcha/__init__.py +32 -0
- benchmatcha-0.0.1/src/BenchMatcha/complexity.py +208 -0
- benchmatcha-0.0.1/src/BenchMatcha/config.py +108 -0
- benchmatcha-0.0.1/src/BenchMatcha/errors.py +89 -0
- benchmatcha-0.0.1/src/BenchMatcha/handlers.py +154 -0
- benchmatcha-0.0.1/src/BenchMatcha/plotting.py +247 -0
- benchmatcha-0.0.1/src/BenchMatcha/py.typed +0 -0
- benchmatcha-0.0.1/src/BenchMatcha/runner.py +339 -0
- benchmatcha-0.0.1/src/BenchMatcha/sifter.py +89 -0
- benchmatcha-0.0.1/src/BenchMatcha/structure.py +362 -0
- benchmatcha-0.0.1/src/BenchMatcha/utils.py +83 -0
- benchmatcha-0.0.1/src/BenchMatcha.egg-info/PKG-INFO +147 -0
- benchmatcha-0.0.1/src/BenchMatcha.egg-info/SOURCES.txt +21 -0
- benchmatcha-0.0.1/src/BenchMatcha.egg-info/dependency_links.txt +1 -0
- benchmatcha-0.0.1/src/BenchMatcha.egg-info/entry_points.txt +2 -0
- benchmatcha-0.0.1/src/BenchMatcha.egg-info/requires.txt +32 -0
- benchmatcha-0.0.1/src/BenchMatcha.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, Spill-Tea
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: BenchMatcha
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Google Benchmark Suite Runner and Regression Analyzer.
|
|
5
|
+
Author-email: Jason C Del Rio <spillthetea917@gmail.com>
|
|
6
|
+
Maintainer-email: Jason C Del Rio <spillthetea917@gmail.com>
|
|
7
|
+
License: BSD 3-Clause License
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2025, Spill-Tea
|
|
10
|
+
|
|
11
|
+
Redistribution and use in source and binary forms, with or without
|
|
12
|
+
modification, are permitted provided that the following conditions are met:
|
|
13
|
+
|
|
14
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
15
|
+
list of conditions and the following disclaimer.
|
|
16
|
+
|
|
17
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
18
|
+
this list of conditions and the following disclaimer in the documentation
|
|
19
|
+
and/or other materials provided with the distribution.
|
|
20
|
+
|
|
21
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
22
|
+
contributors may be used to endorse or promote products derived from
|
|
23
|
+
this software without specific prior written permission.
|
|
24
|
+
|
|
25
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
26
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
27
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
28
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
29
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
30
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
31
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
32
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
33
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
34
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
35
|
+
Project-URL: homepage, https://github.com/Spill-Tea/BenchMatcha
|
|
36
|
+
Project-URL: issues, https://github.com/Spill-Tea/BenchMatcha/issues
|
|
37
|
+
Keywords: benchmark,regression,analysis
|
|
38
|
+
Classifier: Programming Language :: Python :: 3
|
|
39
|
+
Classifier: Development Status :: 1 - Planning
|
|
40
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
41
|
+
Classifier: Intended Audience :: Developers
|
|
42
|
+
Classifier: Intended Audience :: Science/Research
|
|
43
|
+
Classifier: Topic :: Utilities
|
|
44
|
+
Classifier: Topic :: System :: Benchmark
|
|
45
|
+
Classifier: Topic :: Software Development :: Testing
|
|
46
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
47
|
+
Requires-Python: >=3.11
|
|
48
|
+
Description-Content-Type: text/markdown
|
|
49
|
+
License-File: LICENSE
|
|
50
|
+
Requires-Dist: google-benchmark
|
|
51
|
+
Requires-Dist: numpy
|
|
52
|
+
Requires-Dist: orjson
|
|
53
|
+
Requires-Dist: plotly
|
|
54
|
+
Requires-Dist: pytest
|
|
55
|
+
Requires-Dist: scipy
|
|
56
|
+
Requires-Dist: toml
|
|
57
|
+
Requires-Dist: wurlitzer
|
|
58
|
+
Provides-Extra: dev
|
|
59
|
+
Requires-Dist: BenchMatcha[commit,doc,lint,test,type]; extra == "dev"
|
|
60
|
+
Provides-Extra: doc
|
|
61
|
+
Requires-Dist: sphinx; extra == "doc"
|
|
62
|
+
Requires-Dist: furo; extra == "doc"
|
|
63
|
+
Requires-Dist: sphinx_multiversion; extra == "doc"
|
|
64
|
+
Provides-Extra: test
|
|
65
|
+
Requires-Dist: pytest; extra == "test"
|
|
66
|
+
Requires-Dist: coverage>=7.10.3; extra == "test"
|
|
67
|
+
Requires-Dist: pytest-xdist; extra == "test"
|
|
68
|
+
Requires-Dist: tox; extra == "test"
|
|
69
|
+
Provides-Extra: commit
|
|
70
|
+
Requires-Dist: pre-commit; extra == "commit"
|
|
71
|
+
Provides-Extra: lint
|
|
72
|
+
Requires-Dist: pylint; extra == "lint"
|
|
73
|
+
Requires-Dist: ruff; extra == "lint"
|
|
74
|
+
Provides-Extra: type
|
|
75
|
+
Requires-Dist: mypy; extra == "type"
|
|
76
|
+
Dynamic: license-file
|
|
77
|
+
|
|
78
|
+
# BenchMatcha
|
|
79
|
+
[![build status][buildstatus-image]][buildstatus-url]
|
|
80
|
+
|
|
81
|
+
[buildstatus-image]: https://github.com/Spill-Tea/BenchMatcha/actions/workflows/python-app.yml/badge.svg?branch=main
|
|
82
|
+
[buildstatus-url]: https://github.com/Spill-Tea/BenchMatcha/actions?query=branch%3Amain
|
|
83
|
+
|
|
84
|
+

|
|
85
|
+
|
|
86
|
+
BenchMatcha is your companion pytest-like runner to google benchmarks.
|
|
87
|
+
Analyze, plot, and save your results over time to evaluate regression
|
|
88
|
+
over the lifetime of a project.
|
|
89
|
+
|
|
90
|
+
<!-- omit in toc -->
|
|
91
|
+
## Table of Contents
|
|
92
|
+
- [BenchMatcha](#benchmatcha)
|
|
93
|
+
- [Installation](#installation)
|
|
94
|
+
- [Install from pypi](#install-from-pypi)
|
|
95
|
+
- [Clone the repository](#clone-the-repository)
|
|
96
|
+
- [Pip install directly from github.](#pip-install-directly-from-github)
|
|
97
|
+
- [Development](#development)
|
|
98
|
+
- [For Developers](#for-developers)
|
|
99
|
+
- [License](#license)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
## Installation
|
|
103
|
+
You have options.
|
|
104
|
+
|
|
105
|
+
### Install from pypi
|
|
106
|
+
```bash
|
|
107
|
+
pip install BenchMatcha
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Clone the repository
|
|
111
|
+
```bash
|
|
112
|
+
git clone https://github.com/Spill-Tea/BenchMatcha.git
|
|
113
|
+
cd BenchMatcha
|
|
114
|
+
pip install .
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Pip install directly from github.
|
|
118
|
+
```bash
|
|
119
|
+
pip install git+https://github.com/Spill-Tea/BenchMatcha@main
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Development
|
|
123
|
+
|
|
124
|
+
BenchMatcha is currently in the planning stages of development. This means the project
|
|
125
|
+
is not ready for production use, and may be prone to change api without much notice.
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
## For Developers
|
|
129
|
+
After cloning the repository, create a new virtual environment and run the following
|
|
130
|
+
commands:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
pip install -e ".[dev]"
|
|
134
|
+
pre-commit install
|
|
135
|
+
pre-commit run --all-files
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Running unit tests locally is straightforward with tox. Make sure
|
|
139
|
+
you have all python versions available required for your project
|
|
140
|
+
The `p` flag is not required, but it runs tox environments in parallel.
|
|
141
|
+
```bash
|
|
142
|
+
tox -p
|
|
143
|
+
```
|
|
144
|
+
Be sure to run tox before creating a pull request.
|
|
145
|
+
|
|
146
|
+
## License
|
|
147
|
+
[BSD-3](LICENSE)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# BenchMatcha
|
|
2
|
+
[![build status][buildstatus-image]][buildstatus-url]
|
|
3
|
+
|
|
4
|
+
[buildstatus-image]: https://github.com/Spill-Tea/BenchMatcha/actions/workflows/python-app.yml/badge.svg?branch=main
|
|
5
|
+
[buildstatus-url]: https://github.com/Spill-Tea/BenchMatcha/actions?query=branch%3Amain
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
BenchMatcha is your companion pytest-like runner to google benchmarks.
|
|
10
|
+
Analyze, plot, and save your results over time to evaluate regression
|
|
11
|
+
over the lifetime of a project.
|
|
12
|
+
|
|
13
|
+
<!-- omit in toc -->
|
|
14
|
+
## Table of Contents
|
|
15
|
+
- [BenchMatcha](#benchmatcha)
|
|
16
|
+
- [Installation](#installation)
|
|
17
|
+
- [Install from pypi](#install-from-pypi)
|
|
18
|
+
- [Clone the repository](#clone-the-repository)
|
|
19
|
+
- [Pip install directly from github.](#pip-install-directly-from-github)
|
|
20
|
+
- [Development](#development)
|
|
21
|
+
- [For Developers](#for-developers)
|
|
22
|
+
- [License](#license)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
You have options.
|
|
27
|
+
|
|
28
|
+
### Install from pypi
|
|
29
|
+
```bash
|
|
30
|
+
pip install BenchMatcha
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Clone the repository
|
|
34
|
+
```bash
|
|
35
|
+
git clone https://github.com/Spill-Tea/BenchMatcha.git
|
|
36
|
+
cd BenchMatcha
|
|
37
|
+
pip install .
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Pip install directly from github.
|
|
41
|
+
```bash
|
|
42
|
+
pip install git+https://github.com/Spill-Tea/BenchMatcha@main
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Development
|
|
46
|
+
|
|
47
|
+
BenchMatcha is currently in the planning stages of development. This means the project
|
|
48
|
+
is not ready for production use, and may be prone to change api without much notice.
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
## For Developers
|
|
52
|
+
After cloning the repository, create a new virtual environment and run the following
|
|
53
|
+
commands:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install -e ".[dev]"
|
|
57
|
+
pre-commit install
|
|
58
|
+
pre-commit run --all-files
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Running unit tests locally is straightforward with tox. Make sure
|
|
62
|
+
you have all python versions available required for your project
|
|
63
|
+
The `p` flag is not required, but it runs tox environments in parallel.
|
|
64
|
+
```bash
|
|
65
|
+
tox -p
|
|
66
|
+
```
|
|
67
|
+
Be sure to run tox before creating a pull request.
|
|
68
|
+
|
|
69
|
+
## License
|
|
70
|
+
[BSD-3](LICENSE)
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=67.6.1"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "BenchMatcha"
|
|
7
|
+
authors = [{ name = "Jason C Del Rio", email = "spillthetea917@gmail.com" }]
|
|
8
|
+
maintainers = [{ name = "Jason C Del Rio", email = "spillthetea917@gmail.com" }]
|
|
9
|
+
description = "Google Benchmark Suite Runner and Regression Analyzer."
|
|
10
|
+
license = { file = "LICENSE" }
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
keywords = ["benchmark", "regression", "analysis"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"Development Status :: 1 - Planning",
|
|
16
|
+
"License :: OSI Approved :: BSD License",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Intended Audience :: Science/Research",
|
|
19
|
+
"Topic :: Utilities",
|
|
20
|
+
"Topic :: System :: Benchmark",
|
|
21
|
+
"Topic :: Software Development :: Testing",
|
|
22
|
+
"Topic :: Software Development :: Libraries",
|
|
23
|
+
]
|
|
24
|
+
dynamic = ["version", "readme", "dependencies"]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
homepage = "https://github.com/Spill-Tea/BenchMatcha"
|
|
28
|
+
issues = "https://github.com/Spill-Tea/BenchMatcha/issues"
|
|
29
|
+
|
|
30
|
+
[tool.setuptools.dynamic]
|
|
31
|
+
version = { attr = "BenchMatcha.__version__" }
|
|
32
|
+
readme = { file = ["README.md"], content-type = "text/markdown" }
|
|
33
|
+
dependencies = { file = ["requirements.txt"] }
|
|
34
|
+
|
|
35
|
+
[tool.setuptools]
|
|
36
|
+
package-dir = { "" = "src" }
|
|
37
|
+
|
|
38
|
+
[tool.setuptools.packages.find]
|
|
39
|
+
where = ["src"]
|
|
40
|
+
exclude = ["benchmarks", "docs", "tests"]
|
|
41
|
+
|
|
42
|
+
[tool.setuptools.package-data]
|
|
43
|
+
"*" = ["py.typed", "*.pyi"]
|
|
44
|
+
|
|
45
|
+
[project.scripts]
|
|
46
|
+
benchmatcha = "BenchMatcha.runner:main"
|
|
47
|
+
|
|
48
|
+
[project.optional-dependencies]
|
|
49
|
+
dev = ["BenchMatcha[commit,doc,test,lint,type]"]
|
|
50
|
+
doc = ["sphinx", "furo", "sphinx_multiversion"]
|
|
51
|
+
test = ["pytest", "coverage>=7.10.3", "pytest-xdist", "tox"]
|
|
52
|
+
commit = ["pre-commit"]
|
|
53
|
+
lint = ["pylint", "ruff"]
|
|
54
|
+
type = ["mypy"]
|
|
55
|
+
|
|
56
|
+
[tool.pytest.ini_options]
|
|
57
|
+
testpaths = ["tests"]
|
|
58
|
+
addopts = "-n auto -rA"
|
|
59
|
+
|
|
60
|
+
[tool.coverage.run]
|
|
61
|
+
parallel = true
|
|
62
|
+
branch = true
|
|
63
|
+
patch = ["subprocess"]
|
|
64
|
+
source = ["BenchMatcha"]
|
|
65
|
+
disable_warnings = ["no-data-collected", "module-not-imported"]
|
|
66
|
+
|
|
67
|
+
[tool.coverage.paths]
|
|
68
|
+
source = ["src", "*/.tox/py*/**/site-packages"]
|
|
69
|
+
|
|
70
|
+
[tool.coverage.report]
|
|
71
|
+
fail_under = 95.0
|
|
72
|
+
precision = 1
|
|
73
|
+
show_missing = true
|
|
74
|
+
skip_empty = true
|
|
75
|
+
exclude_also = ["def __repr__", 'if __name__ == "__main__"']
|
|
76
|
+
|
|
77
|
+
[tool.mypy]
|
|
78
|
+
mypy_path = "BenchMatcha"
|
|
79
|
+
allow_redefinition = false
|
|
80
|
+
warn_unused_ignores = true
|
|
81
|
+
|
|
82
|
+
[tool.pylint.main]
|
|
83
|
+
extension-pkg-allow-list = ["orjson"]
|
|
84
|
+
ignore = ["tests", "dist", "build"]
|
|
85
|
+
fail-under = 9.0
|
|
86
|
+
jobs = 0
|
|
87
|
+
limit-inference-results = 100
|
|
88
|
+
persistent = true
|
|
89
|
+
suggestion-mode = true
|
|
90
|
+
|
|
91
|
+
[tool.pylint.basic]
|
|
92
|
+
argument-naming-style = "snake_case"
|
|
93
|
+
attr-naming-style = "snake_case"
|
|
94
|
+
class-const-naming-style = "UPPER_CASE"
|
|
95
|
+
class-naming-style = "PascalCase"
|
|
96
|
+
variable-naming-style = "snake_case"
|
|
97
|
+
module-naming-style = "any"
|
|
98
|
+
|
|
99
|
+
[tool.pylint.format]
|
|
100
|
+
max-line-length = 88
|
|
101
|
+
|
|
102
|
+
[tool.pylint."messages control"]
|
|
103
|
+
disable = [
|
|
104
|
+
"R1731", # consider-using-max-builtin
|
|
105
|
+
"R0903", # too-few-public-methods
|
|
106
|
+
"R1735", # use-dict-literal
|
|
107
|
+
"W1514", # unspecified-encoding
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
[tool.pylint."*.pyi"]
|
|
111
|
+
# https://github.com/pylint-dev/pylint/issues/9096
|
|
112
|
+
# https://github.com/pylint-dev/pylint/issues/9417
|
|
113
|
+
disable = [
|
|
114
|
+
"W0613", # unused-argument
|
|
115
|
+
"W0231", # super-init-not-called
|
|
116
|
+
]
|
|
117
|
+
|
|
118
|
+
[tool.ruff]
|
|
119
|
+
line-length = 88
|
|
120
|
+
indent-width = 4
|
|
121
|
+
respect-gitignore = true
|
|
122
|
+
|
|
123
|
+
[tool.ruff.lint]
|
|
124
|
+
select = [
|
|
125
|
+
"B", # bugbear
|
|
126
|
+
"D", # pydocstyle
|
|
127
|
+
"E", # pycodestyle
|
|
128
|
+
"F", # pyflakes
|
|
129
|
+
"I", # isort
|
|
130
|
+
"PYI", # flake8-pyi
|
|
131
|
+
"RUF", # ruff
|
|
132
|
+
"W", # pycodestyle
|
|
133
|
+
"PIE", # flake8-pie
|
|
134
|
+
"PGH004", # pygrep-hooks - Use specific rule codes when using noqa
|
|
135
|
+
"PLE", # pylint error
|
|
136
|
+
"PLW", # pylint warning
|
|
137
|
+
"PLR1714", # Consider merging multiple comparisons
|
|
138
|
+
]
|
|
139
|
+
ignore = [
|
|
140
|
+
"D102", # undocumented-public-method (D102)
|
|
141
|
+
"D105", # undocumented-magic-method (D105)
|
|
142
|
+
"D107", # undocumented-public-init (D107)
|
|
143
|
+
"D203", # one-blank-line-before-class (D203)
|
|
144
|
+
"D213", # multi-line-summary-second-line (D213)
|
|
145
|
+
"PLR0913", # too-many-arguments (PLR0913)
|
|
146
|
+
"C408", # unnecessary-collection-call (C408)
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
[tool.ruff.lint.pydocstyle]
|
|
150
|
+
convention = "google" # Accepts: "google" | "numpy" | "pep257"
|
|
151
|
+
|
|
152
|
+
[tool.ruff.lint.isort]
|
|
153
|
+
lines-after-imports = 2
|
|
154
|
+
|
|
155
|
+
[tool.ruff.lint.per-file-ignores]
|
|
156
|
+
"__init__.py" = [
|
|
157
|
+
"E402", # Import Statement not at Top of File
|
|
158
|
+
"F401", # Unused Imports
|
|
159
|
+
]
|
|
160
|
+
"tests/*.py" = [
|
|
161
|
+
"D", # PyDocstyle
|
|
162
|
+
"PLR2004", # magic-value-comparison (PLR2004)
|
|
163
|
+
"F841", # unused-variable (F841)
|
|
164
|
+
]
|
|
165
|
+
|
|
166
|
+
[tool.ruff.format]
|
|
167
|
+
quote-style = "double"
|
|
168
|
+
indent-style = "space"
|
|
169
|
+
line-ending = "auto"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# BSD 3-Clause License
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2025, Spill-Tea
|
|
4
|
+
#
|
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
|
7
|
+
#
|
|
8
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
# list of conditions and the following disclaimer.
|
|
10
|
+
#
|
|
11
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
# this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
# and/or other materials provided with the distribution.
|
|
14
|
+
#
|
|
15
|
+
# 3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
# contributors may be used to endorse or promote products derived from
|
|
17
|
+
# this software without specific prior written permission.
|
|
18
|
+
#
|
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
29
|
+
|
|
30
|
+
"""BenchMatcha Project."""
|
|
31
|
+
|
|
32
|
+
__version__: str = "v0.0.1"
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# BSD 3-Clause License
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2025, Spill-Tea
|
|
4
|
+
#
|
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
|
7
|
+
#
|
|
8
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
# list of conditions and the following disclaimer.
|
|
10
|
+
#
|
|
11
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
# this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
# and/or other materials provided with the distribution.
|
|
14
|
+
#
|
|
15
|
+
# 3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
# contributors may be used to endorse or promote products derived from
|
|
17
|
+
# this software without specific prior written permission.
|
|
18
|
+
#
|
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
29
|
+
|
|
30
|
+
"""Complexity calculations."""
|
|
31
|
+
|
|
32
|
+
from collections.abc import Callable
|
|
33
|
+
from dataclasses import dataclass
|
|
34
|
+
|
|
35
|
+
import google_benchmark as gbench
|
|
36
|
+
import numpy as np
|
|
37
|
+
from scipy.optimize import curve_fit # type: ignore[import-untyped]
|
|
38
|
+
|
|
39
|
+
from .utils import _simple_stats
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass
|
|
43
|
+
class FitResult:
|
|
44
|
+
"""Curve fit result.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
bigo (str): Big O notation string identifier.
|
|
48
|
+
params (np.ndarray): coefficient value(s).
|
|
49
|
+
cov (np.ndarray): covariance std of coefficients
|
|
50
|
+
rms (float): root mean square error of fit.
|
|
51
|
+
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
bigo: str
|
|
55
|
+
params: np.ndarray
|
|
56
|
+
cov: np.ndarray
|
|
57
|
+
rms: float
|
|
58
|
+
|
|
59
|
+
@staticmethod
|
|
60
|
+
def _handle(x: np.ndarray) -> str:
|
|
61
|
+
a = " ".join([f"{j:.3E}" for j in x.tolist()])
|
|
62
|
+
|
|
63
|
+
return f"[{a}]"
|
|
64
|
+
|
|
65
|
+
def __repr__(self) -> str:
|
|
66
|
+
return (
|
|
67
|
+
f"FitResult(bigo={self.bigo},params={self._handle(self.params)}"
|
|
68
|
+
f",cov={self._handle(self.cov)},rms={self.rms:.3f})"
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# Define common complexity functions with all coefficients and intercept
|
|
73
|
+
Equation = (
|
|
74
|
+
Callable[[np.ndarray, float, float], np.ndarray]
|
|
75
|
+
| Callable[[np.ndarray, float, float, float], np.ndarray]
|
|
76
|
+
| Callable[[np.ndarray, float, float, float, float], np.ndarray]
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def constant(n: np.ndarray, a: float, b: float) -> np.ndarray:
|
|
81
|
+
"""Constant O(1) equation."""
|
|
82
|
+
return a * np.ones_like(n) + b
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def logn(n: np.ndarray, a: float, b: float) -> np.ndarray:
|
|
86
|
+
"""Log O(logN) equation."""
|
|
87
|
+
return a * np.log2(n) + b
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def linear(n: np.ndarray, a: float, b: float) -> np.ndarray:
|
|
91
|
+
"""Linear O(N) equation."""
|
|
92
|
+
return a * n + b
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def nlogn(n: np.ndarray, a: float, b: float) -> np.ndarray:
|
|
96
|
+
"""Log linear O(NlogN) equation."""
|
|
97
|
+
return a * n * np.log2(n) + b
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def quadratic(n: np.ndarray, a: float, b: float, c: float) -> np.ndarray:
|
|
101
|
+
"""Quadratic O(N^2) equation."""
|
|
102
|
+
return a * np.power(n, 2) + linear(n, b, c)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def cubic(n: np.ndarray, a: float, b: float, c: float, d: float) -> np.ndarray:
|
|
106
|
+
"""Cubic O(N^3) equation."""
|
|
107
|
+
return a * np.power(n, 3) + quadratic(n, b, c, d)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
complexity_functions: dict[str, Equation] = {
|
|
111
|
+
# gbench.oNone.name: "",
|
|
112
|
+
gbench.o1.name: constant,
|
|
113
|
+
gbench.oLogN.name: logn,
|
|
114
|
+
gbench.oN.name: linear,
|
|
115
|
+
gbench.oNLogN.name: nlogn,
|
|
116
|
+
gbench.oNSquared.name: quadratic,
|
|
117
|
+
gbench.oNCubed.name: cubic,
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def compute_rmsd(y_true: np.ndarray, y_pred: np.ndarray, k: int) -> float:
|
|
122
|
+
r"""Mean normalized root mean square deviation (RMSD).
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
y_true (np.ndarray): observed y values.
|
|
126
|
+
y_pred (np.ndarray): predicted y values.
|
|
127
|
+
k (int): number of parameters used to estimate predicted values.
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
(float): normalized RMSD
|
|
131
|
+
|
|
132
|
+
Equations:
|
|
133
|
+
$\frac{1}{\bar{y}} \sqrt{\frac{\sum_{i=0}^{N} (y_i - \hat{y}_i)^2}{N - k}}$
|
|
134
|
+
|
|
135
|
+
"""
|
|
136
|
+
residuals: np.ndarray = y_true - y_pred
|
|
137
|
+
sum_square_error: np.float64 = (residuals * residuals).sum()
|
|
138
|
+
dof: np.int64 = np.prod(y_pred.size) - k
|
|
139
|
+
|
|
140
|
+
return float(np.sqrt(sum_square_error / dof) / y_true.mean())
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def fit(
|
|
144
|
+
func: Callable,
|
|
145
|
+
label: str,
|
|
146
|
+
x: np.ndarray,
|
|
147
|
+
y: np.ndarray,
|
|
148
|
+
sigma: np.ndarray,
|
|
149
|
+
) -> FitResult | None:
|
|
150
|
+
"""Fit observed data to an equation.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
func (Callable): equation to fit.
|
|
154
|
+
label (str): complexity label
|
|
155
|
+
x (np.ndarray): x input values
|
|
156
|
+
y (np.ndarray): observed y values
|
|
157
|
+
sigma (np.ndarray): observed error in y values
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
(FitResult | None) returns fit result if converged.
|
|
161
|
+
|
|
162
|
+
"""
|
|
163
|
+
popt: np.ndarray
|
|
164
|
+
pcov: np.ndarray
|
|
165
|
+
try:
|
|
166
|
+
popt, pcov, *_ = curve_fit(
|
|
167
|
+
func,
|
|
168
|
+
x,
|
|
169
|
+
y,
|
|
170
|
+
sigma=sigma,
|
|
171
|
+
absolute_sigma=True,
|
|
172
|
+
)
|
|
173
|
+
pred = func(x, *popt)
|
|
174
|
+
cov = np.sqrt(pcov.diagonal())
|
|
175
|
+
rms = compute_rmsd(y, pred, len(popt))
|
|
176
|
+
|
|
177
|
+
return FitResult(
|
|
178
|
+
bigo=label,
|
|
179
|
+
params=popt,
|
|
180
|
+
cov=cov,
|
|
181
|
+
rms=rms,
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
except RuntimeError:
|
|
185
|
+
return None
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def fit_complexity(x: np.ndarray, y: np.ndarray, sigma: np.ndarray) -> list[FitResult]:
|
|
189
|
+
"""Perform curve fitting to available complexity algorithms."""
|
|
190
|
+
results: list[FitResult] = []
|
|
191
|
+
|
|
192
|
+
for label, func in complexity_functions.items():
|
|
193
|
+
if (res := fit(func, label, x, y, sigma)) is not None:
|
|
194
|
+
results.append(res)
|
|
195
|
+
|
|
196
|
+
return results
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def analyze_complexity(x: np.ndarray, y: np.ndarray) -> list[FitResult]:
|
|
200
|
+
"""Analyze algorithmic complexity."""
|
|
201
|
+
mean, std = _simple_stats(y)
|
|
202
|
+
|
|
203
|
+
return sorted(fit_complexity(x, mean, std), key=lambda x: x.rms)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def get_best_fit(fits: list[FitResult]) -> FitResult:
|
|
207
|
+
"""Return best fit by minimizing RMSD."""
|
|
208
|
+
return min(fits, key=lambda x: x.rms)
|