holobench 1.25.1__py3-none-any.whl → 1.26.3__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/example/benchmark_data.py +196 -0
- bencher/example/example_all.py +45 -0
- bencher/example/example_categorical.py +99 -0
- 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_sweep.py +59 -0
- bencher/example/example_custom_sweep2.py +42 -0
- bencher/example/example_docs.py +34 -0
- bencher/example/example_filepath.py +27 -0
- bencher/example/example_float3D.py +101 -0
- bencher/example/example_float_cat.py +99 -0
- bencher/example/example_floats.py +89 -0
- bencher/example/example_floats2D.py +93 -0
- bencher/example/example_holosweep.py +98 -0
- bencher/example/example_holosweep_objects.py +111 -0
- bencher/example/example_holosweep_tap.py +144 -0
- bencher/example/example_image.py +155 -0
- bencher/example/example_levels.py +181 -0
- bencher/example/example_levels2.py +37 -0
- bencher/example/example_pareto.py +53 -0
- bencher/example/example_sample_cache.py +85 -0
- bencher/example/example_sample_cache_context.py +116 -0
- bencher/example/example_simple.py +134 -0
- bencher/example/example_simple_bool.py +35 -0
- bencher/example/example_simple_cat.py +48 -0
- bencher/example/example_simple_float.py +28 -0
- bencher/example/example_simple_float2d.py +29 -0
- bencher/example/example_strings.py +47 -0
- bencher/example/example_time_event.py +63 -0
- bencher/example/example_video.py +118 -0
- bencher/example/example_workflow.py +189 -0
- bencher/example/experimental/example_bokeh_plotly.py +38 -0
- bencher/example/experimental/example_hover_ex.py +45 -0
- bencher/example/experimental/example_hvplot_explorer.py +39 -0
- bencher/example/experimental/example_interactive.py +75 -0
- bencher/example/experimental/example_streamnd.py +49 -0
- bencher/example/experimental/example_streams.py +36 -0
- bencher/example/experimental/example_template.py +40 -0
- bencher/example/experimental/example_updates.py +84 -0
- bencher/example/experimental/example_vector.py +84 -0
- bencher/example/meta/example_meta.py +171 -0
- bencher/example/meta/example_meta_cat.py +25 -0
- bencher/example/meta/example_meta_float.py +23 -0
- bencher/example/meta/example_meta_levels.py +26 -0
- bencher/example/optuna/example_optuna.py +78 -0
- bencher/example/shelved/example_float2D_scatter.py +109 -0
- bencher/example/shelved/example_float3D_cone.py +96 -0
- bencher/example/shelved/example_kwargs.py +63 -0
- bencher/plotting/__init__.py +0 -0
- bencher/plotting/plot_filter.py +110 -0
- bencher/plotting/plt_cnt_cfg.py +75 -0
- bencher/results/__init__.py +0 -0
- bencher/results/bench_result.py +94 -0
- bencher/results/bench_result_base.py +476 -0
- bencher/results/composable_container/__init__.py +0 -0
- bencher/results/composable_container/composable_container_base.py +73 -0
- bencher/results/composable_container/composable_container_panel.py +39 -0
- bencher/results/composable_container/composable_container_video.py +184 -0
- bencher/results/float_formatter.py +44 -0
- bencher/results/holoview_result.py +753 -0
- bencher/results/optuna_result.py +354 -0
- bencher/results/panel_result.py +41 -0
- bencher/results/plotly_result.py +65 -0
- bencher/results/video_result.py +38 -0
- bencher/results/video_summary.py +222 -0
- bencher/variables/__init__.py +0 -0
- bencher/variables/inputs.py +202 -0
- bencher/variables/parametrised_sweep.py +208 -0
- bencher/variables/results.py +214 -0
- bencher/variables/sweep_base.py +162 -0
- bencher/variables/time.py +92 -0
- holobench-1.26.3.data/data/share/ament_index/resource_index/packages/bencher +0 -0
- {holobench-1.25.1.dist-info → holobench-1.26.3.dist-info}/METADATA +5 -7
- holobench-1.26.3.dist-info/RECORD +93 -0
- holobench-1.25.1.dist-info/RECORD +0 -20
- /holobench-1.25.1.data/data/share/ament_index/resource_index/packages/bencher → /bencher/example/__init__.py +0 -0
- {holobench-1.25.1.data → holobench-1.26.3.data}/data/share/bencher/package.xml +0 -0
- {holobench-1.25.1.dist-info → holobench-1.26.3.dist-info}/LICENSE +0 -0
- {holobench-1.25.1.dist-info → holobench-1.26.3.dist-info}/WHEEL +0 -0
- {holobench-1.25.1.dist-info → holobench-1.26.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,111 @@
|
|
1
|
+
# THIS IS NOT A WORKING EXAMPLE YET
|
2
|
+
|
3
|
+
# pylint: disable=duplicate-code,unused-argument
|
4
|
+
|
5
|
+
|
6
|
+
import bencher as bch
|
7
|
+
import math
|
8
|
+
import random
|
9
|
+
import numpy as np
|
10
|
+
import holoviews as hv
|
11
|
+
|
12
|
+
from strenum import StrEnum
|
13
|
+
from enum import auto
|
14
|
+
|
15
|
+
|
16
|
+
class Function(StrEnum):
|
17
|
+
fn_cos = auto()
|
18
|
+
fn_sin = auto()
|
19
|
+
fn_log = auto()
|
20
|
+
fn_arctan = auto()
|
21
|
+
|
22
|
+
def call(self, arg) -> float:
|
23
|
+
"""Calls the function defined by the name of the enum
|
24
|
+
|
25
|
+
Returns:
|
26
|
+
float: The result of calling the function defined by the enum
|
27
|
+
"""
|
28
|
+
return getattr(np, self.removeprefix("fn_"))(arg)
|
29
|
+
|
30
|
+
|
31
|
+
class FunctionInputs(bch.ParametrizedSweep):
|
32
|
+
phase = bch.FloatSweep(
|
33
|
+
default=0, bounds=[0, math.pi], doc="Input angle", units="rad", samples=5
|
34
|
+
)
|
35
|
+
|
36
|
+
freq = bch.FloatSweep(default=1, bounds=[0, math.pi], doc="Input angle", units="rad", samples=5)
|
37
|
+
|
38
|
+
theta = bch.FloatSweep(
|
39
|
+
default=0, bounds=[0, math.pi], doc="Input angle", units="rad", samples=10
|
40
|
+
)
|
41
|
+
|
42
|
+
compute_fn = bch.EnumSweep(Function)
|
43
|
+
|
44
|
+
|
45
|
+
class FunctionOutputs(bch.ParametrizedSweep):
|
46
|
+
fn_output = bch.ResultVar(units="v", doc="sin of theta with some noise")
|
47
|
+
|
48
|
+
out_sum = bch.ResultVar(units="v", doc="The sum")
|
49
|
+
|
50
|
+
hmap = bch.ResultHmap()
|
51
|
+
|
52
|
+
hmap2 = bch.ResultHmap()
|
53
|
+
|
54
|
+
|
55
|
+
def bench_fn(self, **kwargs) -> dict:
|
56
|
+
fin = FunctionInputs()
|
57
|
+
fin.update_params_from_kwargs(**kwargs)
|
58
|
+
|
59
|
+
output = FunctionOutputs()
|
60
|
+
|
61
|
+
output.fn_output = fin.compute_fn.call(fin.phase + fin.freq * fin.theta) + random.uniform(0, 0)
|
62
|
+
output.hmap = hv.Text(0, 0, f"{fin.phase}\n{fin.freq}\n {fin.theta}")
|
63
|
+
output.hmap2 = hv.Ellipse(0, 0, 1)
|
64
|
+
return output
|
65
|
+
|
66
|
+
|
67
|
+
def plot_holo(self, plot=True) -> hv.core.ViewableElement:
|
68
|
+
"""Plots a generic representation of the object that is not a basic hv datatype. In this case its an image of the values of the object, but it could be any representation of the object, e.g. a screenshot of the object state"""
|
69
|
+
if plot:
|
70
|
+
pt = hv.Text(0, 0, f"{self.phase}\n{self.freq}\n {self.theta}")
|
71
|
+
pt *= hv.Ellipse(0, 0, 1)
|
72
|
+
return pt
|
73
|
+
return None
|
74
|
+
|
75
|
+
|
76
|
+
def example_holosweep(
|
77
|
+
run_cfg: bch.BenchRunCfg = bch.BenchRunCfg(), report: bch.BenchReport = bch.BenchReport()
|
78
|
+
) -> bch.Bench:
|
79
|
+
# wv = PlotFunctions()
|
80
|
+
|
81
|
+
bench = bch.Bench(
|
82
|
+
"waves", bench_fn, worker_input_cfg=FunctionInputs, run_cfg=run_cfg, report=report
|
83
|
+
)
|
84
|
+
|
85
|
+
res = bench.plot_sweep(
|
86
|
+
"phase",
|
87
|
+
input_vars=[FunctionInputs.param.theta, FunctionInputs.param.freq],
|
88
|
+
result_vars=[
|
89
|
+
FunctionOutputs.param.fn_output,
|
90
|
+
FunctionOutputs.param.hmap,
|
91
|
+
FunctionOutputs.param.hmap2,
|
92
|
+
],
|
93
|
+
)
|
94
|
+
|
95
|
+
# bench.report.append(res.summarise_sweep())
|
96
|
+
# bench.report.append(res.to_optuna())
|
97
|
+
# bench.report.append(res.get_best_holomap())
|
98
|
+
# bench.report.append(res.to_curve(), "Slider view")
|
99
|
+
# bench.report.append(res.to_holomap().layout())
|
100
|
+
# print(res.to_holomap())
|
101
|
+
bench.report.append(res.to_holomap())
|
102
|
+
# bench.report.append(res.to_holomap())
|
103
|
+
|
104
|
+
return bench
|
105
|
+
|
106
|
+
|
107
|
+
if __name__ == "__main__":
|
108
|
+
bench_run = bch.BenchRunner("bench_runner_test", run_cfg=bch.BenchRunCfg())
|
109
|
+
|
110
|
+
bench_run.add_run(example_holosweep)
|
111
|
+
bench_run.run(level=4, show=True)
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# THIS IS NOT A WORKING EXAMPLE YET
|
2
|
+
|
3
|
+
# pylint: disable=duplicate-code,unused-argument
|
4
|
+
|
5
|
+
|
6
|
+
import bencher as bch
|
7
|
+
import math
|
8
|
+
import random
|
9
|
+
import numpy as np
|
10
|
+
import holoviews as hv
|
11
|
+
|
12
|
+
from strenum import StrEnum
|
13
|
+
from enum import auto
|
14
|
+
|
15
|
+
|
16
|
+
class Function(StrEnum):
|
17
|
+
fn_cos = auto()
|
18
|
+
fn_sin = auto()
|
19
|
+
fn_log = auto()
|
20
|
+
fn_arctan = auto()
|
21
|
+
|
22
|
+
def call(self, arg) -> float:
|
23
|
+
"""Calls the function defined by the name of the enum
|
24
|
+
|
25
|
+
Returns:
|
26
|
+
float: The result of calling the function defined by the enum
|
27
|
+
"""
|
28
|
+
return getattr(np, self.removeprefix("fn_"))(arg)
|
29
|
+
|
30
|
+
|
31
|
+
class PlotFunctions(bch.ParametrizedSweep):
|
32
|
+
phase = bch.FloatSweep(
|
33
|
+
default=0, bounds=[0, math.pi], doc="Input angle", units="rad", samples=5
|
34
|
+
)
|
35
|
+
|
36
|
+
freq = bch.FloatSweep(default=1, bounds=[0, math.pi], doc="Input angle", units="rad", samples=5)
|
37
|
+
|
38
|
+
theta = bch.FloatSweep(
|
39
|
+
default=0, bounds=[0, math.pi], doc="Input angle", units="rad", samples=10
|
40
|
+
)
|
41
|
+
|
42
|
+
compute_fn = bch.EnumSweep(Function)
|
43
|
+
|
44
|
+
fn_output = bch.ResultVar(units="v", doc="sin of theta with some noise")
|
45
|
+
|
46
|
+
out_sum = bch.ResultVar(units="v", doc="The sum")
|
47
|
+
|
48
|
+
hmap = bch.ResultHmap()
|
49
|
+
|
50
|
+
def __call__(self, plot=True, **kwargs) -> dict:
|
51
|
+
self.update_params_from_kwargs(**kwargs)
|
52
|
+
noise = 0.1
|
53
|
+
|
54
|
+
self.fn_output = self.compute_fn.call(self.phase + self.freq * self.theta) + random.uniform(
|
55
|
+
0, noise
|
56
|
+
)
|
57
|
+
self.hmap = self.plot_holo(plot)
|
58
|
+
|
59
|
+
return self.get_results_values_as_dict()
|
60
|
+
|
61
|
+
def plot_holo(self, plot=True) -> hv.core.ViewableElement:
|
62
|
+
"""Plots a generic representation of the object that is not a basic hv datatype. In this case its an image of the values of the object, but it could be any representation of the object, e.g. a screenshot of the object state"""
|
63
|
+
if plot:
|
64
|
+
pt = hv.Text(0, 0, f"phase:{self.phase}\nfreq:{self.freq}\ntheta:{self.theta}")
|
65
|
+
pt *= hv.Ellipse(0, 0, 1)
|
66
|
+
return pt
|
67
|
+
return None
|
68
|
+
|
69
|
+
def calc_vec(self, **kwargs) -> dict:
|
70
|
+
theta = self.param.theta.values()
|
71
|
+
kwargs.pop("theta", 0)
|
72
|
+
dat = [self.__call__(plot=False, theta=i, **kwargs)["fn_output"] for i in theta]
|
73
|
+
# print(dat)
|
74
|
+
self.out_sum = sum(dat)
|
75
|
+
self.hmap = hv.Curve((theta, dat), "theta", "voltage")
|
76
|
+
# pt = hv.Text(0, 0, f"{self.compute_fn}\n{self.phase}\n{self.freq}")
|
77
|
+
# pt *= hv.Ellipse(0, 0, 1)
|
78
|
+
return self.get_results_values_as_dict()
|
79
|
+
|
80
|
+
|
81
|
+
def example_holosweep_tap(
|
82
|
+
run_cfg: bch.BenchRunCfg = bch.BenchRunCfg(), report: bch.BenchReport = bch.BenchReport()
|
83
|
+
) -> bch.Bench:
|
84
|
+
wv = PlotFunctions()
|
85
|
+
|
86
|
+
run_cfg.use_optuna = True
|
87
|
+
run_cfg.auto_plot = False
|
88
|
+
bench = bch.Bench("waves", wv, run_cfg=run_cfg, report=report)
|
89
|
+
|
90
|
+
res = bench.plot_sweep(
|
91
|
+
"phase",
|
92
|
+
input_vars=[PlotFunctions.param.theta, PlotFunctions.param.freq],
|
93
|
+
result_vars=[PlotFunctions.param.fn_output, PlotFunctions.param.hmap],
|
94
|
+
run_cfg=run_cfg,
|
95
|
+
)
|
96
|
+
|
97
|
+
bench.report.append(res.describe_sweep())
|
98
|
+
bench.report.append(res.to_heatmap_tap(PlotFunctions.param.fn_output))
|
99
|
+
|
100
|
+
return bench
|
101
|
+
|
102
|
+
|
103
|
+
def example_holosweep_tap_slider(
|
104
|
+
run_cfg: bch.BenchRunCfg = bch.BenchRunCfg(), report: bch.BenchReport = bch.BenchReport()
|
105
|
+
) -> bch.Bench: # pragma: no cover
|
106
|
+
wv = PlotFunctions()
|
107
|
+
|
108
|
+
run_cfg.use_optuna = True
|
109
|
+
bench = bch.Bench("waves", wv, run_cfg=run_cfg, report=report)
|
110
|
+
|
111
|
+
res = bench.plot_sweep(
|
112
|
+
"phase",
|
113
|
+
input_vars=[PlotFunctions.param.theta, PlotFunctions.param.freq, PlotFunctions.param.phase],
|
114
|
+
result_vars=[PlotFunctions.param.fn_output],
|
115
|
+
run_cfg=run_cfg,
|
116
|
+
)
|
117
|
+
|
118
|
+
print(res.get_best_trial_params())
|
119
|
+
bench.report.append(res.get_best_holomap())
|
120
|
+
|
121
|
+
heatmap = res.to_heatmap().opts(tools=["hover", "tap"])
|
122
|
+
posxy = hv.streams.Tap(source=heatmap, x=0, y=0)
|
123
|
+
sld1 = wv.param.phase.as_slider()
|
124
|
+
|
125
|
+
def tap_plot(x, y):
|
126
|
+
print(x, y)
|
127
|
+
selres = bch.get_nearest_coords(res.ds, theta=x, freq=y, phase=sld1.value, repeat=1)
|
128
|
+
return res.hmaps[bch.hmap_canonical_input(selres)]
|
129
|
+
|
130
|
+
tap_dmap = hv.DynamicMap(tap_plot, streams=[posxy])
|
131
|
+
|
132
|
+
bench.report.append_tab(heatmap + tap_dmap, "Interactive Heatmap")
|
133
|
+
bench.report.append(sld1)
|
134
|
+
|
135
|
+
bench.report.append_tab(res.to_curve(), "Slider view")
|
136
|
+
|
137
|
+
return bench
|
138
|
+
|
139
|
+
|
140
|
+
if __name__ == "__main__":
|
141
|
+
example_holosweep_tap(bch.BenchRunCfg()).report.show()
|
142
|
+
|
143
|
+
|
144
|
+
# todo https://discourse.holoviz.org/t/pointdraw-as-parameterized-class/3539
|
@@ -0,0 +1,155 @@
|
|
1
|
+
import bencher as bch
|
2
|
+
import numpy as np
|
3
|
+
import math
|
4
|
+
import matplotlib.pyplot as plt
|
5
|
+
|
6
|
+
|
7
|
+
def polygon_points(radius: float, sides: int, start_angle: float):
|
8
|
+
points = []
|
9
|
+
for ang in np.linspace(0, 360, sides + 1):
|
10
|
+
angle = math.radians(start_angle + ang)
|
11
|
+
points.append(([math.sin(angle) * radius, math.cos(angle) * radius]))
|
12
|
+
return points
|
13
|
+
|
14
|
+
|
15
|
+
class BenchPolygons(bch.ParametrizedSweep):
|
16
|
+
sides = bch.IntSweep(default=3, bounds=(3, 7))
|
17
|
+
radius = bch.FloatSweep(default=1, bounds=(0.2, 1))
|
18
|
+
linewidth = bch.FloatSweep(default=1, bounds=(1, 10))
|
19
|
+
linestyle = bch.StringSweep(["solid", "dashed", "dotted"])
|
20
|
+
color = bch.StringSweep(["red", "green", "blue"])
|
21
|
+
start_angle = bch.FloatSweep(default=0, bounds=[0, 360])
|
22
|
+
polygon = bch.ResultImage()
|
23
|
+
area = bch.ResultVar()
|
24
|
+
side_length = bch.ResultVar()
|
25
|
+
|
26
|
+
def __call__(self, **kwargs):
|
27
|
+
self.update_params_from_kwargs(**kwargs)
|
28
|
+
points = polygon_points(self.radius, self.sides, self.start_angle)
|
29
|
+
# self.hmap = hv.Curve(points)
|
30
|
+
self.polygon = self.points_to_polygon_png(points, bch.gen_image_path("polygon"))
|
31
|
+
|
32
|
+
self.side_length = 2 * self.radius * math.sin(math.pi / self.sides)
|
33
|
+
self.area = (self.sides * self.side_length**2) / (4 * math.tan(math.pi / self.sides))
|
34
|
+
return super().__call__()
|
35
|
+
|
36
|
+
def points_to_polygon_png(self, points: list[float], filename: str):
|
37
|
+
"""Draw a closed polygon and save to png"""
|
38
|
+
fig = plt.figure(frameon=False)
|
39
|
+
ax = plt.Axes(fig, [0.0, 0.0, 1.0, 1.0], frameon=False)
|
40
|
+
ax.set_axis_off()
|
41
|
+
ax.plot(
|
42
|
+
[p[0] for p in points],
|
43
|
+
[p[1] for p in points],
|
44
|
+
linewidth=self.linewidth,
|
45
|
+
linestyle=self.linestyle,
|
46
|
+
color=self.color,
|
47
|
+
)
|
48
|
+
ax.set_xlim(-1, 1)
|
49
|
+
ax.set_ylim(-1, 1)
|
50
|
+
|
51
|
+
ax.set_aspect("equal")
|
52
|
+
fig.add_axes(ax)
|
53
|
+
fig.savefig(filename, dpi=30)
|
54
|
+
|
55
|
+
return filename
|
56
|
+
|
57
|
+
|
58
|
+
def example_image(
|
59
|
+
run_cfg: bch.BenchRunCfg = bch.BenchRunCfg(), report: bch.BenchReport = bch.BenchReport()
|
60
|
+
) -> bch.Bench:
|
61
|
+
run_cfg.use_cache = False
|
62
|
+
bench = bch.Bench("polygons", BenchPolygons(), run_cfg=run_cfg, report=report)
|
63
|
+
|
64
|
+
bench.result_vars = ["polygon", "area"]
|
65
|
+
|
66
|
+
bench.add_plot_callback(bch.BenchResult.to_sweep_summary)
|
67
|
+
# bench.add_plot_callback(bch.BenchResult.to_auto, level=2)
|
68
|
+
bench.add_plot_callback(bch.BenchResult.to_panes, level=3)
|
69
|
+
# bench.add_plot_callback(bch.BenchResult.to_panes)
|
70
|
+
|
71
|
+
sweep_vars = ["sides", "radius", "linewidth", "color"]
|
72
|
+
|
73
|
+
# sweep_vars = ["sides", "radius" ]
|
74
|
+
|
75
|
+
for i in range(1, len(sweep_vars)):
|
76
|
+
s = sweep_vars[:i]
|
77
|
+
bench.plot_sweep(
|
78
|
+
f"Polygons Sweeping {len(s)} Parameters",
|
79
|
+
input_vars=s,
|
80
|
+
)
|
81
|
+
bench.report.append(bench.get_result().to_panes())
|
82
|
+
|
83
|
+
return bench
|
84
|
+
|
85
|
+
|
86
|
+
def example_image_vid(run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None) -> bch.Bench:
|
87
|
+
bench = BenchPolygons().to_bench(run_cfg, report)
|
88
|
+
bench.add_plot_callback(bch.BenchResult.to_sweep_summary)
|
89
|
+
bench.add_plot_callback(
|
90
|
+
bch.BenchResult.to_video_grid,
|
91
|
+
target_duration=0.06,
|
92
|
+
compose_method_list=[
|
93
|
+
bch.ComposeType.right,
|
94
|
+
bch.ComposeType.right,
|
95
|
+
bch.ComposeType.sequence,
|
96
|
+
],
|
97
|
+
)
|
98
|
+
# from functools import partial
|
99
|
+
# bench.add_plot_callback(bch.BenchResult.to_video_summary)
|
100
|
+
# bench.add_plot_callback(bch.BenchResult.to_video_grid, time_sequence_dimension=0)
|
101
|
+
# bench.add_plot_callback(bch.BenchResult.to_video_grid)
|
102
|
+
# bench.add_plot_callback(bch.BenchResult.to_video_grid, time_sequence_dimension=2)
|
103
|
+
# bench.add_plot_callback(bch.BenchResult.to_video_grid, time_sequence_dimension=3)
|
104
|
+
|
105
|
+
bench.plot_sweep(input_vars=["radius"])
|
106
|
+
# res = bench.plot_sweep(input_vars=["radius"], plot=False)
|
107
|
+
# bench.report.append(res.to_video_grid(target_duration=0.06))
|
108
|
+
bench.plot_sweep(input_vars=["radius", "sides"])
|
109
|
+
# bench.plot_sweep(input_vars=["radius", "sides", "linewidth"])
|
110
|
+
# bench.plot_sweep(input_vars=["radius", "sides", "linewidth", "color"])
|
111
|
+
|
112
|
+
return bench
|
113
|
+
|
114
|
+
|
115
|
+
if __name__ == "__main__":
|
116
|
+
|
117
|
+
def simple():
|
118
|
+
bench = BenchPolygons().to_bench(bch.BenchRunCfg(level=4))
|
119
|
+
|
120
|
+
# bench.plot_sweep(input_vars=["sides","color","radius"])
|
121
|
+
|
122
|
+
# res = bench.sweep(input_vars=["sides", "radius"])
|
123
|
+
|
124
|
+
# bench.report.append(res.to_heatmap(target_dimension=3))
|
125
|
+
|
126
|
+
bench.plot_sweep(input_vars=["sides"])
|
127
|
+
bench.plot_sweep(input_vars=["sides", "color"])
|
128
|
+
|
129
|
+
bench.plot_sweep(input_vars=["sides", "radius"])
|
130
|
+
|
131
|
+
# bench.report.append(res.to_line(target_dimension=1))
|
132
|
+
|
133
|
+
return bench
|
134
|
+
|
135
|
+
def example_image_vid_sequential(
|
136
|
+
run_cfg: bch.BenchRunCfg = bch.BenchRunCfg(), report: bch.BenchReport = bch.BenchReport()
|
137
|
+
) -> bch.Bench:
|
138
|
+
bench = BenchPolygons().to_bench(run_cfg, report)
|
139
|
+
bench.add_plot_callback(bch.BenchResult.to_title)
|
140
|
+
bench.add_plot_callback(bch.BenchResult.to_video_grid)
|
141
|
+
bench.sweep_sequential(input_vars=["radius", "sides", "linewidth", "color"], group_size=4)
|
142
|
+
return bench
|
143
|
+
|
144
|
+
# def example_image_pairs()
|
145
|
+
|
146
|
+
ex_run_cfg = bch.BenchRunCfg()
|
147
|
+
ex_run_cfg.use_sample_cache = True
|
148
|
+
# ex_run_cfg.debug = True
|
149
|
+
# ex_run_cfg.repeats = 2
|
150
|
+
ex_run_cfg.level = 4
|
151
|
+
example_image_vid(ex_run_cfg).report.show()
|
152
|
+
# simple().report.show()
|
153
|
+
|
154
|
+
# example_image_vid_sequential(ex_run_cfg).report.show()
|
155
|
+
# example_image(ex_run_cfg).report.show()
|
@@ -0,0 +1,181 @@
|
|
1
|
+
import bencher as bch
|
2
|
+
from bencher.utils import int_to_col
|
3
|
+
|
4
|
+
import math
|
5
|
+
import holoviews as hv
|
6
|
+
from typing import Any, List
|
7
|
+
import panel as pn
|
8
|
+
from holoviews import opts
|
9
|
+
|
10
|
+
|
11
|
+
class LevelsExample(bch.ParametrizedSweep):
|
12
|
+
xval = bch.FloatSweep(bounds=[0, 3.14])
|
13
|
+
yval = bch.FloatSweep(bounds=[0, 3.14])
|
14
|
+
level = bch.IntSweep(default=1, bounds=[1, 6])
|
15
|
+
|
16
|
+
output = bch.ResultVar(units="v")
|
17
|
+
hmap = bch.ResultHmap()
|
18
|
+
|
19
|
+
def __call__(self, **kwargs: Any) -> Any:
|
20
|
+
self.update_params_from_kwargs(**kwargs)
|
21
|
+
self.output = math.sin(self.xval) + math.cos(self.yval)
|
22
|
+
self.hmap = hv.Points((self.xval, self.yval)).opts(
|
23
|
+
marker="o", size=110 - self.level * 20, color=int_to_col(self.level - 1)
|
24
|
+
)
|
25
|
+
|
26
|
+
return self.get_results_values_as_dict()
|
27
|
+
|
28
|
+
|
29
|
+
class RunWithLevel(bch.ParametrizedSweep):
|
30
|
+
level = bch.IntSweep(default=1, bounds=[1, 8])
|
31
|
+
dimensions = bch.IntSweep(default=1, bounds=[1, 2])
|
32
|
+
|
33
|
+
level_samples = bch.ResultVar()
|
34
|
+
|
35
|
+
def __call__(self, **kwargs) -> dict():
|
36
|
+
self.update_params_from_kwargs(**kwargs)
|
37
|
+
|
38
|
+
self.level_samples = int(
|
39
|
+
pow(
|
40
|
+
len(bch.FloatSweep(bounds=[0, 1]).with_level(self.level).values()),
|
41
|
+
self.dimensions,
|
42
|
+
)
|
43
|
+
)
|
44
|
+
return self.get_results_values_as_dict()
|
45
|
+
|
46
|
+
|
47
|
+
def run_with_dim(bench: bch.Bench, dims: List[bch.SweepBase]) -> List[bch.BenchResult]:
|
48
|
+
results = []
|
49
|
+
for level in range(1, 6):
|
50
|
+
print(level)
|
51
|
+
res = bench.plot_sweep(
|
52
|
+
f"Level:{level}",
|
53
|
+
input_vars=dims,
|
54
|
+
const_vars=LevelsExample.get_input_defaults(
|
55
|
+
[LevelsExample.param.level.with_const(level)]
|
56
|
+
),
|
57
|
+
result_vars=[LevelsExample.param.output, LevelsExample.param.hmap],
|
58
|
+
run_cfg=bch.BenchRunCfg(level=level, auto_plot=False),
|
59
|
+
)
|
60
|
+
|
61
|
+
results.append(res)
|
62
|
+
return results
|
63
|
+
|
64
|
+
|
65
|
+
def run_levels_1D(bench: bch.Bench) -> bch.Bench:
|
66
|
+
results = run_with_dim(bench, [LevelsExample.param.xval])
|
67
|
+
bench.report.append_title("Using Levels to define sample density")
|
68
|
+
|
69
|
+
bench1 = bch.Bench("levels", RunWithLevel(), run_cfg=bch.BenchRunCfg(auto_plot=False))
|
70
|
+
res1 = bench1.plot_sweep("Levels", input_vars=[RunWithLevel.param.level])
|
71
|
+
|
72
|
+
bench.report.append_markdown(
|
73
|
+
"Sample levels let you perform parameter sweeps without having to decide how many samples to take when defining the class. If you perform a sweep at level 2, then all the points are reused when sampling at level 3. The higher levels reuse the points from lower levels to avoid having to recompute potentially expensive samples. The other advantage is that it enables a workflow where you can quickly see the results of the sweep at a low resolution to sense check the code, and then run it at a high level to get the fidelity you want. When calling a sweep at a high level, you can publish the intermediate lower level results as the computiation continues so that you can track the progress of the computation and end the sweep early when you have sufficient resolution",
|
74
|
+
width=600,
|
75
|
+
)
|
76
|
+
row = pn.Row()
|
77
|
+
row.append(res1.to_table())
|
78
|
+
# row.append(res1.to_curve().opts(shared_axes=False))
|
79
|
+
row.append(res1.to_curve())
|
80
|
+
|
81
|
+
bench.report.append(row)
|
82
|
+
|
83
|
+
bench.report.append_markdown(
|
84
|
+
"Level 1 returns a single point at the lower bound of the parameter. Level 2 uses the uppper and lower bounds of the parameter. All subsequent levels are created by adding a sample between each previously calculated sample to ensure that all previous values can be reused while retaining an equal sample spacing. The following plots show the sample points as circles and the corresponding plot of a sin function sampled at that level.",
|
85
|
+
width=600,
|
86
|
+
)
|
87
|
+
|
88
|
+
combined_pts = hv.Overlay()
|
89
|
+
combined_curve = hv.Overlay()
|
90
|
+
for it, r in enumerate(results):
|
91
|
+
lvl = it + 1
|
92
|
+
row = pn.Row()
|
93
|
+
pts = r.to_holomap().overlay().opts(title=f"Sample Points for level: {lvl}", height=300)
|
94
|
+
ds = r.to_hv_dataset()
|
95
|
+
crv = r.to_curve_ds(ds.data).opts(shared_axes=False, height=300) * r.to_hv_dataset(
|
96
|
+
bch.ReduceType.NONE
|
97
|
+
).to(hv.Scatter).opts(
|
98
|
+
title=f"Function Values for level: {lvl}", size=5, height=300, shared_axes=False
|
99
|
+
)
|
100
|
+
|
101
|
+
combined_pts *= pts
|
102
|
+
combined_curve *= crv
|
103
|
+
row.append(pts)
|
104
|
+
row.append(crv)
|
105
|
+
bench.report.append_markdown(f"## {r.bench_cfg.title}")
|
106
|
+
bench.report.append(row)
|
107
|
+
|
108
|
+
bench.report.append_markdown(
|
109
|
+
"This plot overlays the previous plots into a single image. It shows how each level overlaps the previous level"
|
110
|
+
)
|
111
|
+
|
112
|
+
bench.report.append(pn.Row(combined_pts, combined_curve))
|
113
|
+
return bench
|
114
|
+
|
115
|
+
|
116
|
+
def run_levels_2D(bench: bch.Bench) -> bch.Bench:
|
117
|
+
results = run_with_dim(bench, [LevelsExample.param.xval, LevelsExample.param.yval])
|
118
|
+
bench.report.append_markdown("# Using Levels to define 2D sample density", "Levels 2D")
|
119
|
+
|
120
|
+
bench1 = bch.Bench("lol", RunWithLevel(), run_cfg=bch.BenchRunCfg(auto_plot=False))
|
121
|
+
res1 = bench1.plot_sweep(
|
122
|
+
"Levels",
|
123
|
+
input_vars=[RunWithLevel.param.level],
|
124
|
+
const_vars=[RunWithLevel.param.dimensions.with_const(2)],
|
125
|
+
)
|
126
|
+
row = pn.Row()
|
127
|
+
row.append(res1.to_table())
|
128
|
+
# row.append(res1.to_curve().opts(shared_axes=False))
|
129
|
+
row.append(res1.to_curve())
|
130
|
+
|
131
|
+
bench.report.append(row)
|
132
|
+
|
133
|
+
for it, r in enumerate(results):
|
134
|
+
lvl = it + 1
|
135
|
+
row = pn.Row()
|
136
|
+
bench.report.append_markdown(f"## {r.bench_cfg.title}")
|
137
|
+
row.append(
|
138
|
+
r.to_holomap()
|
139
|
+
.overlay()
|
140
|
+
.opts(title=f"Sample Points for level: {lvl}", shared_axes=False)
|
141
|
+
)
|
142
|
+
row.append(
|
143
|
+
r.to_heatmap_single(r.bench_cfg.result_vars[0], bch.ReduceType.NONE).opts(
|
144
|
+
title=f"Function Value Heatmap for level: {lvl}", shared_axes=False
|
145
|
+
)
|
146
|
+
)
|
147
|
+
bench.report.append(row)
|
148
|
+
|
149
|
+
bench.report.append_markdown(
|
150
|
+
"This plot overlays the previous plots into a single image. It shows how each level overlaps the previous level"
|
151
|
+
)
|
152
|
+
overlay = hv.Overlay()
|
153
|
+
for lvl, r in enumerate(results):
|
154
|
+
overlay *= (
|
155
|
+
r.to_holomap()
|
156
|
+
.overlay()
|
157
|
+
.opts(width=1000, height=1000, show_legend=False, shared_axes=False)
|
158
|
+
)
|
159
|
+
|
160
|
+
bench.report.append(overlay)
|
161
|
+
return bench
|
162
|
+
|
163
|
+
|
164
|
+
def run_levels(
|
165
|
+
run_cfg: bch.BenchRunCfg = bch.BenchRunCfg(), report: bch.BenchReport = bch.BenchReport()
|
166
|
+
) -> bch.Bench:
|
167
|
+
hv.extension("bokeh")
|
168
|
+
opts.defaults(
|
169
|
+
opts.Curve(show_legend=False),
|
170
|
+
opts.Points(show_legend=False),
|
171
|
+
)
|
172
|
+
|
173
|
+
bench = bch.Bench("Levels", LevelsExample(), run_cfg=run_cfg, report=report)
|
174
|
+
bench = run_levels_1D(bench)
|
175
|
+
bench = run_levels_2D(bench)
|
176
|
+
|
177
|
+
return bench
|
178
|
+
|
179
|
+
|
180
|
+
if __name__ == "__main__":
|
181
|
+
run_levels().report.show()
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import bencher as bch
|
2
|
+
|
3
|
+
|
4
|
+
class Square(bch.ParametrizedSweep):
|
5
|
+
"""An example of a datatype with an integer and float parameter"""
|
6
|
+
|
7
|
+
x = bch.FloatSweep(default=0, bounds=[0, 6])
|
8
|
+
|
9
|
+
result = bch.ResultVar("ul", doc="Square of x")
|
10
|
+
|
11
|
+
def __call__(self, **kwargs) -> dict:
|
12
|
+
self.update_params_from_kwargs(**kwargs)
|
13
|
+
self.result = self.x * self.x
|
14
|
+
return self.get_results_values_as_dict()
|
15
|
+
|
16
|
+
|
17
|
+
def example_levels2(run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None) -> bch.Bench:
|
18
|
+
"""This example shows how to define a custom set of value to sample from intead of a uniform sweep
|
19
|
+
|
20
|
+
Args:
|
21
|
+
run_cfg (BenchRunCfg): configuration of how to perform the param sweep
|
22
|
+
|
23
|
+
Returns:
|
24
|
+
Bench: results of the parameter sweep
|
25
|
+
"""
|
26
|
+
|
27
|
+
bench = Square().to_bench(run_cfg=run_cfg, report=report)
|
28
|
+
|
29
|
+
# These are all equivalent
|
30
|
+
bench.plot_sweep(input_vars=[Square.param.x.with_level(run_cfg.level, 3)])
|
31
|
+
bench.plot_sweep(input_vars=[bch.p("x", max_level=3)])
|
32
|
+
|
33
|
+
return bench
|
34
|
+
|
35
|
+
|
36
|
+
if __name__ == "__main__":
|
37
|
+
example_levels2(bch.BenchRunCfg(level=4)).report.show()
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# pylint: disable=duplicate-code
|
2
|
+
|
3
|
+
import bencher as bch
|
4
|
+
|
5
|
+
# All the examples will be using the data structures and benchmark function defined in this file
|
6
|
+
from bencher.example.benchmark_data import ExampleBenchCfgIn, ExampleBenchCfgOut, bench_function
|
7
|
+
|
8
|
+
|
9
|
+
def example_pareto(
|
10
|
+
run_cfg: bch.BenchRunCfg = bch.BenchRunCfg(), report: bch.BenchReport = bch.BenchReport()
|
11
|
+
) -> bch.Bench:
|
12
|
+
"""Example of how to calculate the pareto front of a parameter sweep
|
13
|
+
|
14
|
+
Args:
|
15
|
+
run_cfg (BenchRunCfg): configuration of how to perform the param sweep
|
16
|
+
|
17
|
+
Returns:
|
18
|
+
Bench: results of the parameter sweep
|
19
|
+
"""
|
20
|
+
run_cfg.use_optuna = True
|
21
|
+
|
22
|
+
bench = bch.Bench(
|
23
|
+
"Multi-objective optimisation",
|
24
|
+
bench_function,
|
25
|
+
ExampleBenchCfgIn,
|
26
|
+
run_cfg=run_cfg,
|
27
|
+
report=report,
|
28
|
+
)
|
29
|
+
|
30
|
+
res = bench.plot_sweep(
|
31
|
+
title="Pareto Optimisation with Optuna",
|
32
|
+
description="This example shows how to plot the pareto front of the tradeoff between multiple criteria. When multiple result variable are defined, and use_optuna=True a pareto plot and the relative importance of each input variable on the output criteria is plotted. A summary of the points on the pareto front is printed as well. You can use the pareto plot to decide the how to trade off one objective for another. Pareto plots are suppored for 2D and 3D. If you have more than 3 result variables the first 3 are selected for the pareto plot. Plotting 4D surfaces is left as an exercise to the reader",
|
33
|
+
input_vars=[
|
34
|
+
ExampleBenchCfgIn.param.theta,
|
35
|
+
ExampleBenchCfgIn.param.offset,
|
36
|
+
],
|
37
|
+
result_vars=[ExampleBenchCfgOut.param.out_sin, ExampleBenchCfgOut.param.out_cos],
|
38
|
+
const_vars=ExampleBenchCfgIn.get_input_defaults(
|
39
|
+
[ExampleBenchCfgIn.param.noisy.with_const(True)]
|
40
|
+
),
|
41
|
+
post_description="""# Post Description
|
42
|
+
This is a slightly unusual way of doing pareto optimisation as we are not using a typical multi-objective optimisation algorithm [TODO, add example]. Instead we are performing a grid search and looking at the resulting pareto plot. The reason for doing a grid search instead of standard pareto optimisation is that we can produce more isolated plots of how an input affects an output which can help understanding of the parameter space. Future examples will show how to use grid search to bootstrap further optimisation with a multi objective optimiser""",
|
43
|
+
)
|
44
|
+
|
45
|
+
bench.report.append(res.to_optuna_plots())
|
46
|
+
return bench
|
47
|
+
|
48
|
+
|
49
|
+
if __name__ == "__main__":
|
50
|
+
run_cfg_ex = bch.BenchRunCfg()
|
51
|
+
run_cfg_ex.repeats = 2
|
52
|
+
run_cfg_ex.level = 2
|
53
|
+
example_pareto(run_cfg_ex).report.show()
|