holobench 1.18.0__py2.py3-none-any.whl → 1.30.0__py2.py3-none-any.whl
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.
- bencher/__init__.py +13 -1
- bencher/bench_cfg.py +1 -1
- bencher/bench_report.py +6 -109
- bencher/bench_runner.py +1 -1
- bencher/bencher.py +117 -62
- bencher/example/benchmark_data.py +0 -4
- bencher/example/example_composable_container.py +106 -0
- bencher/example/example_composable_container2.py +160 -0
- bencher/example/example_consts.py +39 -0
- bencher/example/example_custom_sweep2.py +42 -0
- bencher/example/example_dataframe.py +48 -0
- bencher/example/example_filepath.py +27 -0
- bencher/example/example_image.py +31 -16
- bencher/example/example_image1.py +81 -0
- bencher/example/example_levels2.py +37 -0
- bencher/example/example_simple_float.py +15 -25
- bencher/example/example_simple_float2d.py +29 -0
- bencher/example/example_strings.py +3 -2
- bencher/example/example_video.py +2 -11
- bencher/example/meta/example_meta.py +2 -2
- bencher/example/meta/example_meta_cat.py +2 -2
- bencher/example/meta/example_meta_float.py +1 -1
- bencher/example/meta/example_meta_levels.py +2 -2
- bencher/optuna_conversions.py +3 -2
- bencher/plotting/plt_cnt_cfg.py +1 -0
- bencher/results/bench_result.py +3 -1
- bencher/results/bench_result_base.py +65 -8
- bencher/results/composable_container/composable_container_base.py +25 -12
- bencher/results/composable_container/composable_container_dataframe.py +52 -0
- bencher/results/composable_container/composable_container_panel.py +17 -18
- bencher/results/composable_container/composable_container_video.py +163 -55
- bencher/results/dataset_result.py +227 -0
- bencher/results/holoview_result.py +15 -7
- bencher/results/optuna_result.py +4 -3
- bencher/results/panel_result.py +1 -3
- bencher/results/video_summary.py +104 -99
- bencher/utils.py +29 -3
- bencher/variables/__init__.py +0 -0
- bencher/variables/inputs.py +24 -1
- bencher/variables/parametrised_sweep.py +8 -24
- bencher/variables/results.py +67 -9
- bencher/variables/time.py +22 -0
- bencher/video_writer.py +20 -74
- {holobench-1.18.0.dist-info → holobench-1.30.0.dist-info}/METADATA +77 -35
- {holobench-1.18.0.dist-info → holobench-1.30.0.dist-info}/RECORD +48 -34
- {holobench-1.18.0.dist-info → holobench-1.30.0.dist-info}/WHEEL +1 -1
- holobench-1.30.0.dist-info/licenses/LICENSE +21 -0
- resource/bencher +0 -0
bencher/utils.py
CHANGED
@@ -8,8 +8,9 @@ from colorsys import hsv_to_rgb
|
|
8
8
|
from pathlib import Path
|
9
9
|
from uuid import uuid4
|
10
10
|
from functools import partial
|
11
|
-
from typing import Callable, Any, List
|
11
|
+
from typing import Callable, Any, List, Tuple
|
12
12
|
import param
|
13
|
+
import numpy as np
|
13
14
|
|
14
15
|
|
15
16
|
def hmap_canonical_input(dic: dict) -> tuple:
|
@@ -98,6 +99,23 @@ def un_camel(camel: str) -> str:
|
|
98
99
|
return capitalise_words(re.sub("([a-z])([A-Z])", r"\g<1> \g<2>", camel.replace("_", " ")))
|
99
100
|
|
100
101
|
|
102
|
+
def mult_tuple(inp: Tuple[float], val: float) -> Tuple[float]:
|
103
|
+
return tuple(np.array(inp) * val)
|
104
|
+
|
105
|
+
|
106
|
+
def tabs_in_markdown(regular_str: str, spaces: int = 2) -> str:
|
107
|
+
"""Given a string with tabs in the form \t convert the to   which is a double space in markdown
|
108
|
+
|
109
|
+
Args:
|
110
|
+
regular_str (str): A string with tabs in it
|
111
|
+
spaces (int): the number of spaces per tab
|
112
|
+
|
113
|
+
Returns:
|
114
|
+
str: A string with sets of to represent the tabs in markdown
|
115
|
+
"""
|
116
|
+
return regular_str.replace("\t", "".join([" "] * spaces))
|
117
|
+
|
118
|
+
|
101
119
|
def int_to_col(int_val, sat=0.5, val=0.95, alpha=-1) -> tuple[float, float, float]:
|
102
120
|
"""Uses the golden angle to generate colors programmatically with minimum overlap between colors.
|
103
121
|
https://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
|
@@ -129,13 +147,21 @@ def color_tuple_to_css(color: tuple[float, float, float]) -> str:
|
|
129
147
|
return f"rgb{(color[0] * 255, color[1] * 255, color[2] * 255)}"
|
130
148
|
|
131
149
|
|
132
|
-
def
|
150
|
+
def color_tuple_to_255(color: tuple[float, float, float]) -> tuple[float, float, float]:
|
151
|
+
return (
|
152
|
+
min(int(color[0] * 255), 255),
|
153
|
+
min(int(color[1] * 255), 255),
|
154
|
+
min(int(color[2] * 255), 255),
|
155
|
+
)
|
156
|
+
|
157
|
+
|
158
|
+
def gen_path(filename, folder="generic", suffix=".dat"):
|
133
159
|
path = Path(f"cachedir/{folder}/{filename}/")
|
134
160
|
path.mkdir(parents=True, exist_ok=True)
|
135
161
|
return f"{path.absolute().as_posix()}/{filename}_{uuid4()}{suffix}"
|
136
162
|
|
137
163
|
|
138
|
-
def gen_video_path(video_name: str = "vid", extension: str = ".
|
164
|
+
def gen_video_path(video_name: str = "vid", extension: str = ".mp4") -> str:
|
139
165
|
return gen_path(video_name, "vid", extension)
|
140
166
|
|
141
167
|
|
File without changes
|
bencher/variables/inputs.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
from enum import Enum
|
2
|
-
from typing import List, Any
|
2
|
+
from typing import List, Any, Dict
|
3
3
|
|
4
4
|
import numpy as np
|
5
5
|
from param import Integer, Number, Selector
|
@@ -174,6 +174,29 @@ def box(name, center, width):
|
|
174
174
|
return var
|
175
175
|
|
176
176
|
|
177
|
+
def p(
|
178
|
+
name: str, values: List[Any] = None, samples: int = None, max_level: int = None
|
179
|
+
) -> Dict[str, Any]:
|
180
|
+
"""
|
181
|
+
Create a parameter dictionary with optional values, samples, and max_level.
|
182
|
+
|
183
|
+
Args:
|
184
|
+
name (str): The name of the parameter.
|
185
|
+
values (List[Any], optional): A list of values for the parameter. Defaults to None.
|
186
|
+
samples (int, optional): The number of samples. Must be greater than 0 if provided. Defaults to None.
|
187
|
+
max_level (int, optional): The maximum level. Must be greater than 0 if provided. Defaults to None.
|
188
|
+
|
189
|
+
Returns:
|
190
|
+
Dict[str, Any]: A dictionary containing the parameter details.
|
191
|
+
"""
|
192
|
+
if max_level is not None and max_level <= 0:
|
193
|
+
raise ValueError("max_level must be greater than 0")
|
194
|
+
|
195
|
+
if samples is not None and samples <= 0:
|
196
|
+
raise ValueError("samples must be greater than 0")
|
197
|
+
return {"name": name, "values": values, "max_level": max_level, "samples": samples}
|
198
|
+
|
199
|
+
|
177
200
|
def with_level(arr: list, level) -> list:
|
178
201
|
return IntSweep(sample_values=arr).with_level(level).values()
|
179
202
|
# return tmp.with_sample_values(arr).with_level(level).values()
|
@@ -3,19 +3,11 @@ from typing import List, Tuple, Any
|
|
3
3
|
from param import Parameter, Parameterized
|
4
4
|
import holoviews as hv
|
5
5
|
import panel as pn
|
6
|
-
|
6
|
+
from copy import deepcopy
|
7
7
|
|
8
8
|
from bencher.utils import make_namedtuple, hash_sha1
|
9
|
-
from bencher.variables.results import
|
10
|
-
|
11
|
-
ResultVec,
|
12
|
-
ResultHmap,
|
13
|
-
ResultVideo,
|
14
|
-
ResultImage,
|
15
|
-
ResultString,
|
16
|
-
ResultContainer,
|
17
|
-
ResultReference,
|
18
|
-
)
|
9
|
+
from bencher.variables.results import ALL_RESULT_TYPES, ResultHmap
|
10
|
+
from bencher.bench_cfg import BenchRunCfg
|
19
11
|
|
20
12
|
|
21
13
|
class ParametrizedSweep(Parameterized):
|
@@ -78,16 +70,7 @@ class ParametrizedSweep(Parameterized):
|
|
78
70
|
for k, v in cls.param.objects().items():
|
79
71
|
if isinstance(
|
80
72
|
v,
|
81
|
-
|
82
|
-
ResultVar,
|
83
|
-
ResultVec,
|
84
|
-
ResultHmap,
|
85
|
-
ResultVideo,
|
86
|
-
ResultImage,
|
87
|
-
ResultString,
|
88
|
-
ResultContainer,
|
89
|
-
ResultReference,
|
90
|
-
),
|
73
|
+
ALL_RESULT_TYPES,
|
91
74
|
):
|
92
75
|
results[k] = v
|
93
76
|
else:
|
@@ -144,7 +127,7 @@ class ParametrizedSweep(Parameterized):
|
|
144
127
|
inp = cls.get_inputs_only()
|
145
128
|
defaults = {}
|
146
129
|
for i in inp:
|
147
|
-
defaults[i.name] = i.default
|
130
|
+
defaults[i.name] = deepcopy(i.default)
|
148
131
|
|
149
132
|
for k, v in kwargs.items():
|
150
133
|
defaults[k] = v
|
@@ -209,13 +192,14 @@ class ParametrizedSweep(Parameterized):
|
|
209
192
|
)
|
210
193
|
)
|
211
194
|
|
212
|
-
def __call__(self):
|
195
|
+
def __call__(self, **kwargs):
|
213
196
|
return self.get_results_values_as_dict()
|
214
197
|
|
215
198
|
def plot_hmap(self, **kwargs):
|
216
199
|
return self.__call__(**kwargs)["hmap"]
|
217
200
|
|
218
|
-
|
201
|
+
# TODO Add type hints here and fix the circular imports
|
202
|
+
def to_bench(self, run_cfg: BenchRunCfg = None, report=None, name: str = None):
|
219
203
|
from bencher import Bench
|
220
204
|
|
221
205
|
assert isinstance(self, ParametrizedSweep)
|
bencher/variables/results.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
from enum import auto
|
2
2
|
from typing import List, Callable, Any, Optional
|
3
|
-
|
3
|
+
from functools import partial
|
4
4
|
import panel as pn
|
5
5
|
import param
|
6
6
|
from param import Number
|
@@ -99,7 +99,7 @@ def curve(
|
|
99
99
|
return hv.Curve(zip(x_vals, y_vals), kdims=[x_name], vdims=[y_name], label=label, **kwargs)
|
100
100
|
|
101
101
|
|
102
|
-
class
|
102
|
+
class ResultPath(param.Filename):
|
103
103
|
__slots__ = ["units"]
|
104
104
|
|
105
105
|
def __init__(self, default=None, units="path", **params):
|
@@ -110,15 +110,33 @@ class PathResult(param.Filename):
|
|
110
110
|
"""A hash function that avoids the PYTHONHASHSEED 'feature' which returns a different hash value each time the program is run"""
|
111
111
|
return hash_sha1(self)
|
112
112
|
|
113
|
+
def to_container(self):
|
114
|
+
"""Returns a partial function for creating a FileDownload widget with embedding enabled. This function is used to create a panel container to represent the ResultPath object"""
|
115
|
+
return partial(pn.widgets.FileDownload, embed=True)
|
116
|
+
|
113
117
|
|
114
|
-
class ResultVideo(
|
115
|
-
|
116
|
-
|
118
|
+
class ResultVideo(param.Filename):
|
119
|
+
__slots__ = ["units"]
|
120
|
+
|
121
|
+
def __init__(self, default=None, units="path", **params):
|
122
|
+
super().__init__(default=default, check_exists=False, **params)
|
123
|
+
self.units = units
|
117
124
|
|
125
|
+
def hash_persistent(self) -> str:
|
126
|
+
"""A hash function that avoids the PYTHONHASHSEED 'feature' which returns a different hash value each time the program is run"""
|
127
|
+
return hash_sha1(self)
|
118
128
|
|
119
|
-
|
120
|
-
|
121
|
-
|
129
|
+
|
130
|
+
class ResultImage(param.Filename):
|
131
|
+
__slots__ = ["units"]
|
132
|
+
|
133
|
+
def __init__(self, default=None, units="path", **params):
|
134
|
+
super().__init__(default=default, check_exists=False, **params)
|
135
|
+
self.units = units
|
136
|
+
|
137
|
+
def hash_persistent(self) -> str:
|
138
|
+
"""A hash function that avoids the PYTHONHASHSEED 'feature' which returns a different hash value each time the program is run"""
|
139
|
+
return hash_sha1(self)
|
122
140
|
|
123
141
|
|
124
142
|
class ResultString(param.String):
|
@@ -168,6 +186,25 @@ class ResultReference(param.Parameter):
|
|
168
186
|
return hash_sha1(self)
|
169
187
|
|
170
188
|
|
189
|
+
class ResultDataSet(param.Parameter):
|
190
|
+
__slots__ = ["units", "obj"]
|
191
|
+
|
192
|
+
def __init__(
|
193
|
+
self,
|
194
|
+
obj: Any = None,
|
195
|
+
default: Any = None,
|
196
|
+
units: str = "dataset",
|
197
|
+
**params,
|
198
|
+
):
|
199
|
+
super().__init__(default=default, **params)
|
200
|
+
self.units = units
|
201
|
+
self.obj = obj
|
202
|
+
|
203
|
+
def hash_persistent(self) -> str:
|
204
|
+
"""A hash function that avoids the PYTHONHASHSEED 'feature' which returns a different hash value each time the program is run"""
|
205
|
+
return hash_sha1(self)
|
206
|
+
|
207
|
+
|
171
208
|
class ResultVolume(param.Parameter):
|
172
209
|
__slots__ = ["units", "obj"]
|
173
210
|
|
@@ -181,4 +218,25 @@ class ResultVolume(param.Parameter):
|
|
181
218
|
return hash_sha1(self)
|
182
219
|
|
183
220
|
|
184
|
-
PANEL_TYPES = (
|
221
|
+
PANEL_TYPES = (
|
222
|
+
ResultPath,
|
223
|
+
ResultImage,
|
224
|
+
ResultVideo,
|
225
|
+
ResultContainer,
|
226
|
+
ResultString,
|
227
|
+
ResultReference,
|
228
|
+
ResultDataSet,
|
229
|
+
)
|
230
|
+
|
231
|
+
ALL_RESULT_TYPES = (
|
232
|
+
ResultVar,
|
233
|
+
ResultVec,
|
234
|
+
ResultHmap,
|
235
|
+
ResultPath,
|
236
|
+
ResultVideo,
|
237
|
+
ResultImage,
|
238
|
+
ResultString,
|
239
|
+
ResultContainer,
|
240
|
+
ResultDataSet,
|
241
|
+
ResultReference,
|
242
|
+
)
|
bencher/variables/time.py
CHANGED
@@ -9,6 +9,28 @@ from bencher.variables.sweep_base import SweepBase, shared_slots
|
|
9
9
|
class TimeBase(SweepBase, Selector):
|
10
10
|
"""A class to capture a time snapshot of benchmark values. Time is reprented as a continous value i.e a datetime which is converted into a np.datetime64. To represent time as a discrete value use the TimeEvent class. The distinction is because holoview and plotly code makes different assumptions about discrete vs continous variables"""
|
11
11
|
|
12
|
+
def __init__(
|
13
|
+
self,
|
14
|
+
objects=None,
|
15
|
+
default=None,
|
16
|
+
instantiate=False,
|
17
|
+
compute_default_fn=None,
|
18
|
+
check_on_set=None,
|
19
|
+
allow_None=None,
|
20
|
+
empty_default=False,
|
21
|
+
**params,
|
22
|
+
):
|
23
|
+
super().__init__(
|
24
|
+
objects,
|
25
|
+
default,
|
26
|
+
instantiate,
|
27
|
+
compute_default_fn,
|
28
|
+
check_on_set,
|
29
|
+
allow_None,
|
30
|
+
empty_default,
|
31
|
+
**params,
|
32
|
+
)
|
33
|
+
|
12
34
|
__slots__ = shared_slots
|
13
35
|
|
14
36
|
def values(self) -> List[str]:
|
bencher/video_writer.py
CHANGED
@@ -4,13 +4,6 @@ from pathlib import Path
|
|
4
4
|
from .utils import gen_video_path, gen_image_path
|
5
5
|
|
6
6
|
import moviepy
|
7
|
-
from moviepy.editor import (
|
8
|
-
VideoFileClip,
|
9
|
-
ImageClip,
|
10
|
-
ImageSequenceClip,
|
11
|
-
clips_array,
|
12
|
-
concatenate_videoclips,
|
13
|
-
)
|
14
7
|
from PIL import Image, ImageDraw
|
15
8
|
|
16
9
|
|
@@ -25,97 +18,50 @@ class VideoWriter:
|
|
25
18
|
self.images.append(img)
|
26
19
|
|
27
20
|
def write(self) -> str:
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
21
|
+
if len(self.images) > 0:
|
22
|
+
clip = moviepy.video.io.ImageSequenceClip.ImageSequenceClip(
|
23
|
+
self.images, fps=30, with_mask=False, load_images=True
|
24
|
+
)
|
25
|
+
self.write_video_raw(clip)
|
32
26
|
return self.filename
|
33
27
|
|
34
28
|
@staticmethod
|
35
|
-
def create_label(label, width=None, height=
|
29
|
+
def create_label(label, width=None, height=16, color=(255, 255, 255)):
|
36
30
|
if width is None:
|
37
|
-
width = len(label) *
|
38
|
-
new_img = Image.new("RGB", (width, height),
|
31
|
+
width = len(label) * 10
|
32
|
+
new_img = Image.new("RGB", (width, height), color=color)
|
39
33
|
# ImageDraw.Draw(new_img).text((width/2, 0), label, (0, 0, 0),align="center",achor="ms")
|
40
|
-
ImageDraw.Draw(new_img).text(
|
34
|
+
ImageDraw.Draw(new_img).text(
|
35
|
+
(width / 2.0, 0), label, (0, 0, 0), anchor="mt", font_size=height
|
36
|
+
)
|
41
37
|
|
42
38
|
return new_img
|
43
39
|
|
44
40
|
@staticmethod
|
45
|
-
def label_image(path: Path, label, padding=20) -> Path:
|
41
|
+
def label_image(path: Path, label, padding=20, color=(255, 255, 255)) -> Path:
|
46
42
|
image = Image.open(path)
|
47
|
-
new_img = VideoWriter.create_label(
|
43
|
+
new_img = VideoWriter.create_label(
|
44
|
+
label, image.size[0], image.size[1] + padding, color=color
|
45
|
+
)
|
48
46
|
new_img.paste(image, (0, padding))
|
49
47
|
return new_img
|
50
48
|
|
51
|
-
def append_file(self, filepath, label=None):
|
52
|
-
if label is not None:
|
53
|
-
path = Path(filepath)
|
54
|
-
new_path = path.with_name(path.stem + "_labelled" + path.suffix).as_posix()
|
55
|
-
padding = 20
|
56
|
-
match path.suffix:
|
57
|
-
case ".png" | ".jpg":
|
58
|
-
image = Image.open(filepath)
|
59
|
-
new_img = self.create_label(label, image.size[0], image.size[1] + padding)
|
60
|
-
new_img.paste(image, (0, padding))
|
61
|
-
new_img.save(new_path)
|
62
|
-
self.image_files.append(new_path)
|
63
|
-
case ".webm":
|
64
|
-
import warnings
|
65
|
-
|
66
|
-
video_clip = VideoFileClip(filepath)
|
67
|
-
new_img = self.create_label(label, video_clip.w, padding)
|
68
|
-
|
69
|
-
# Convert PIL image to MoviePy clip
|
70
|
-
label_clip = ImageClip(np.array(new_img), duration=video_clip.duration)
|
71
|
-
|
72
|
-
labeled_video_clip = clips_array([[label_clip], [video_clip]])
|
73
|
-
|
74
|
-
# otherwise ffmpeg complains that the file is not getting read. We don't need the file just the size
|
75
|
-
with warnings.catch_warnings():
|
76
|
-
warnings.simplefilter(action="ignore")
|
77
|
-
labeled_video_clip.write_videofile(new_path, remove_temp=True, logger=None)
|
78
|
-
self.video_files.append(new_path)
|
79
|
-
else:
|
80
|
-
self.image_files.append(filepath)
|
81
|
-
|
82
|
-
def to_images_sequence(self, images, target_duration: float = 10.0, frame_time=None, **kwargs):
|
83
|
-
target_duration = kwargs.pop("target_duration", target_duration)
|
84
|
-
if isinstance(images, list) and len(images) > 0:
|
85
|
-
if frame_time is None:
|
86
|
-
fps = len(images) / target_duration
|
87
|
-
fps = max(fps, 1) # never slower that 1 seconds per frame
|
88
|
-
fps = min(fps, 30)
|
89
|
-
else:
|
90
|
-
fps = 1.0 / frame_time
|
91
|
-
return ImageSequenceClip(images, fps=fps, with_mask=False)
|
92
|
-
return None
|
93
|
-
|
94
|
-
def write_png(self, **kwargs):
|
95
|
-
clip = None
|
96
|
-
if len(self.image_files) > 0:
|
97
|
-
clip = self.to_images_sequence(self.image_files, **kwargs)
|
98
|
-
if len(self.video_files) > 0:
|
99
|
-
clip = concatenate_videoclips([VideoFileClip(f) for f in self.video_files])
|
100
|
-
if clip is not None:
|
101
|
-
clip.write_videofile(self.filename)
|
102
|
-
return self.filename
|
103
|
-
return None
|
104
|
-
|
105
49
|
def write_video_raw(self, video_clip: moviepy.video.VideoClip, fps: int = 30) -> str:
|
106
50
|
video_clip.write_videofile(
|
107
51
|
self.filename,
|
108
|
-
codec="
|
52
|
+
codec="libx264",
|
109
53
|
audio=False,
|
110
54
|
bitrate="0",
|
111
55
|
fps=fps,
|
112
|
-
ffmpeg_params=["-crf", "
|
56
|
+
ffmpeg_params=["-crf", "23"],
|
57
|
+
threads=8,
|
113
58
|
)
|
114
59
|
video_clip.close()
|
115
60
|
return self.filename
|
116
61
|
|
117
62
|
|
118
|
-
def add_image(np_array: np.ndarray, name: str = "img"):
|
63
|
+
def add_image(np_array: np.ndarray, name: str = "img") -> str:
|
64
|
+
"""Creates a file on disk from a numpy array and returns the created image path"""
|
119
65
|
filename = gen_image_path(name)
|
120
66
|
Image.fromarray(np_array).save(filename)
|
121
67
|
return filename
|
@@ -1,37 +1,39 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.3
|
2
2
|
Name: holobench
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.30.0
|
4
4
|
Summary: A package for benchmarking the performance of arbitrary functions
|
5
|
-
Author-email: Austin Gregg-Smith <blooop@gmail.com>
|
6
|
-
Description-Content-Type: text/markdown
|
7
|
-
Requires-Dist: holoviews>=1.15,<=1.18.3
|
8
|
-
Requires-Dist: numpy>=1.0,<=1.26.4
|
9
|
-
Requires-Dist: param>=1.13.0,<=2.1.0
|
10
|
-
Requires-Dist: hvplot>=0.8,<=0.10.0
|
11
|
-
Requires-Dist: matplotlib>=3.6.3,<=3.8.4
|
12
|
-
Requires-Dist: panel>=1.3.6,<=1.4.2
|
13
|
-
Requires-Dist: diskcache>=5.6,<=5.6.3
|
14
|
-
Requires-Dist: optuna>=3.2,<=3.6.1
|
15
|
-
Requires-Dist: xarray>=2023.7,<=2024.5.0
|
16
|
-
Requires-Dist: plotly>=5.15,<=5.22.0
|
17
|
-
Requires-Dist: sortedcontainers>=2.4,<=2.4
|
18
|
-
Requires-Dist: pandas>=2.0,<=2.2.2
|
19
|
-
Requires-Dist: strenum>=0.4.0,<=0.4.15
|
20
|
-
Requires-Dist: scikit-learn>=1.2,<=1.4.2
|
21
|
-
Requires-Dist: str2bool>=1.1,<=1.1
|
22
|
-
Requires-Dist: scoop>=0.7.0,<=0.7.2.0
|
23
|
-
Requires-Dist: moviepy>=1.0.3,<=1.0.3
|
24
|
-
Requires-Dist: black>=23,<=24.4.2 ; extra == "test"
|
25
|
-
Requires-Dist: pylint>=2.16,<=3.1.0 ; extra == "test"
|
26
|
-
Requires-Dist: pytest-cov>=4.1,<=5.0.0 ; extra == "test"
|
27
|
-
Requires-Dist: pytest>=7.4,<=8.2.0 ; extra == "test"
|
28
|
-
Requires-Dist: hypothesis>=6.82,<=6.101.0 ; extra == "test"
|
29
|
-
Requires-Dist: ruff>=0.0.280,<=0.4.4 ; extra == "test"
|
30
|
-
Requires-Dist: coverage>=7.2.7,<=7.5.1 ; extra == "test"
|
31
|
-
Project-URL: Documentation, https://bencher.readthedocs.io/en/latest/
|
32
|
-
Project-URL: Home, https://github.com/dyson-ai/bencher
|
33
5
|
Project-URL: Repository, https://github.com/dyson-ai/bencher
|
6
|
+
Project-URL: Home, https://github.com/dyson-ai/bencher
|
7
|
+
Project-URL: Documentation, https://bencher.readthedocs.io/en/latest/
|
8
|
+
Author-email: Austin Gregg-Smith <blooop@gmail.com>
|
9
|
+
License-Expression: MIT
|
10
|
+
License-File: LICENSE
|
11
|
+
Requires-Dist: diskcache<=5.6.3,>=5.6
|
12
|
+
Requires-Dist: holoviews<=1.19.1,>=1.15
|
13
|
+
Requires-Dist: hvplot<=0.10.0,>=0.8
|
14
|
+
Requires-Dist: matplotlib<=3.9.2,>=3.6.3
|
15
|
+
Requires-Dist: moviepy-fix-codec
|
16
|
+
Requires-Dist: numpy<=2.1.0,>=1.0
|
17
|
+
Requires-Dist: optuna<=4.0.0,>=3.2
|
18
|
+
Requires-Dist: pandas<=2.2.2,>=2.0
|
19
|
+
Requires-Dist: panel<=1.4.5,>=1.3.6
|
20
|
+
Requires-Dist: param<=2.1.1,>=1.13.0
|
21
|
+
Requires-Dist: plotly<=5.24.0,>=5.15
|
22
|
+
Requires-Dist: scikit-learn<=1.5.1,>=1.2
|
23
|
+
Requires-Dist: scoop<=0.7.2.0,>=0.7.0
|
24
|
+
Requires-Dist: sortedcontainers<=2.4,>=2.4
|
25
|
+
Requires-Dist: str2bool<=1.1,>=1.1
|
26
|
+
Requires-Dist: strenum<=0.4.15,>=0.4.0
|
27
|
+
Requires-Dist: xarray<=2024.7.0,>=2023.7
|
34
28
|
Provides-Extra: test
|
29
|
+
Requires-Dist: black<=24.8.0,>=23; extra == 'test'
|
30
|
+
Requires-Dist: coverage<=7.6.1,>=7.5.4; extra == 'test'
|
31
|
+
Requires-Dist: hypothesis<=6.112.2,>=6.104.2; extra == 'test'
|
32
|
+
Requires-Dist: pylint<=3.3.1,>=3.2.5; extra == 'test'
|
33
|
+
Requires-Dist: pytest-cov<=5.0.0,>=4.1; extra == 'test'
|
34
|
+
Requires-Dist: pytest<=8.3.3,>=7.4; extra == 'test'
|
35
|
+
Requires-Dist: ruff<=0.6.8,>=0.5.0; extra == 'test'
|
36
|
+
Description-Content-Type: text/markdown
|
35
37
|
|
36
38
|
# Bencher
|
37
39
|
|
@@ -43,10 +45,16 @@ Provides-Extra: test
|
|
43
45
|
[](https://GitHub.com/dyson-ai/bencher/issues/)
|
44
46
|
[](https://github.com/dyson-ai/bencher/pulls?q=is%3Amerged)
|
45
47
|
[](https://pypi.org/project/holobench/)
|
46
|
-
[](https://pypistats.org/packages/holobench)
|
47
49
|
[](https://opensource.org/license/mit/)
|
48
|
-
[](https://www.python.org/downloads/
|
50
|
+
[](https://www.python.org/downloads/)
|
51
|
+
[](https://pixi.sh)
|
52
|
+
|
53
|
+
## Install
|
49
54
|
|
55
|
+
```bash
|
56
|
+
pip install holobench
|
57
|
+
```
|
50
58
|
|
51
59
|
## Intro
|
52
60
|
|
@@ -77,9 +85,43 @@ Bencher is designed to work with stochastic pure functions with no side effects.
|
|
77
85
|
combine latest data with historical data
|
78
86
|
|
79
87
|
store the results using the input hash as a key
|
80
|
-
deduce the type of plot based on the input types
|
88
|
+
deduce the type of plot based on the input and output types
|
81
89
|
return data and plot
|
82
90
|
|
83
|
-
### Example Output
|
84
91
|
|
85
|
-
|
92
|
+
## Demo
|
93
|
+
|
94
|
+
if you have [pixi](https://github.com/prefix-dev/pixi/) installed you can run a demo example with:
|
95
|
+
|
96
|
+
```bash
|
97
|
+
pixi run demo
|
98
|
+
```
|
99
|
+
|
100
|
+
An example of the type of output bencher produces can be seen here:
|
101
|
+
|
102
|
+
https://dyson-ai.github.io/bencher/
|
103
|
+
|
104
|
+
|
105
|
+
## Examples
|
106
|
+
|
107
|
+
Most of the features that are supported are demonstrated in the examples folder.
|
108
|
+
|
109
|
+
Start with example_simple_float.py and explore other examples based on your data types:
|
110
|
+
- example_float.py: More complex float operations
|
111
|
+
- example_float2D.py: 2D float sweeps
|
112
|
+
- example_float3D.py: 3D float sweeps
|
113
|
+
- example_categorical.py: Sweeping categorical values (enums)
|
114
|
+
- example_strings.py: Sweeping categorical string values
|
115
|
+
- example_float_cat.py: Mixing float and categorical values
|
116
|
+
- example_image.py: Output images as part of the sweep
|
117
|
+
- example_video.py: Output videos as part of the sweep
|
118
|
+
- example_filepath.py: Output arbitrary files as part of the sweep
|
119
|
+
- and many others
|
120
|
+
|
121
|
+
|
122
|
+
## Documentation
|
123
|
+
|
124
|
+
API documentation can be found at https://bencher.readthedocs.io/en/latest/
|
125
|
+
|
126
|
+
More documentation is needed for the examples and general workflow.
|
127
|
+
|