holobench 1.3.5__py3-none-any.whl → 1.22.2__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.
Files changed (77) hide show
  1. bencher/__init__.py +3 -0
  2. bencher/bench_cfg.py +29 -33
  3. bencher/bench_plot_server.py +5 -1
  4. bencher/bench_report.py +14 -14
  5. bencher/bench_runner.py +2 -1
  6. bencher/bencher.py +77 -52
  7. bencher/class_enum.py +52 -0
  8. bencher/job.py +6 -4
  9. bencher/optuna_conversions.py +1 -1
  10. bencher/utils.py +42 -4
  11. bencher/video_writer.py +101 -10
  12. holobench-1.22.2.data/data/share/bencher/package.xml +33 -0
  13. holobench-1.22.2.dist-info/LICENSE +21 -0
  14. {holobench-1.3.5.dist-info → holobench-1.22.2.dist-info}/METADATA +39 -31
  15. holobench-1.22.2.dist-info/RECORD +20 -0
  16. {holobench-1.3.5.dist-info → holobench-1.22.2.dist-info}/WHEEL +2 -1
  17. holobench-1.22.2.dist-info/top_level.txt +1 -0
  18. bencher/example/benchmark_data.py +0 -200
  19. bencher/example/example_all.py +0 -45
  20. bencher/example/example_categorical.py +0 -99
  21. bencher/example/example_custom_sweep.py +0 -59
  22. bencher/example/example_docs.py +0 -34
  23. bencher/example/example_float3D.py +0 -101
  24. bencher/example/example_float_cat.py +0 -98
  25. bencher/example/example_floats.py +0 -89
  26. bencher/example/example_floats2D.py +0 -93
  27. bencher/example/example_holosweep.py +0 -104
  28. bencher/example/example_holosweep_objects.py +0 -111
  29. bencher/example/example_holosweep_tap.py +0 -144
  30. bencher/example/example_image.py +0 -82
  31. bencher/example/example_levels.py +0 -181
  32. bencher/example/example_pareto.py +0 -53
  33. bencher/example/example_sample_cache.py +0 -85
  34. bencher/example/example_sample_cache_context.py +0 -116
  35. bencher/example/example_simple.py +0 -134
  36. bencher/example/example_simple_bool.py +0 -34
  37. bencher/example/example_simple_cat.py +0 -47
  38. bencher/example/example_simple_float.py +0 -38
  39. bencher/example/example_strings.py +0 -46
  40. bencher/example/example_time_event.py +0 -62
  41. bencher/example/example_video.py +0 -124
  42. bencher/example/example_workflow.py +0 -189
  43. bencher/example/experimental/example_bokeh_plotly.py +0 -38
  44. bencher/example/experimental/example_hover_ex.py +0 -45
  45. bencher/example/experimental/example_hvplot_explorer.py +0 -39
  46. bencher/example/experimental/example_interactive.py +0 -75
  47. bencher/example/experimental/example_streamnd.py +0 -49
  48. bencher/example/experimental/example_streams.py +0 -36
  49. bencher/example/experimental/example_template.py +0 -40
  50. bencher/example/experimental/example_updates.py +0 -84
  51. bencher/example/experimental/example_vector.py +0 -84
  52. bencher/example/meta/example_meta.py +0 -171
  53. bencher/example/meta/example_meta_cat.py +0 -25
  54. bencher/example/meta/example_meta_float.py +0 -23
  55. bencher/example/meta/example_meta_levels.py +0 -26
  56. bencher/example/optuna/example_optuna.py +0 -78
  57. bencher/example/shelved/example_float2D_scatter.py +0 -109
  58. bencher/example/shelved/example_float3D_cone.py +0 -96
  59. bencher/example/shelved/example_kwargs.py +0 -63
  60. bencher/plotting/__init__.py +0 -0
  61. bencher/plotting/plot_filter.py +0 -110
  62. bencher/plotting/plt_cnt_cfg.py +0 -74
  63. bencher/results/__init__.py +0 -0
  64. bencher/results/bench_result.py +0 -80
  65. bencher/results/bench_result_base.py +0 -405
  66. bencher/results/float_formatter.py +0 -44
  67. bencher/results/holoview_result.py +0 -592
  68. bencher/results/optuna_result.py +0 -354
  69. bencher/results/panel_result.py +0 -113
  70. bencher/results/plotly_result.py +0 -65
  71. bencher/variables/inputs.py +0 -193
  72. bencher/variables/parametrised_sweep.py +0 -206
  73. bencher/variables/results.py +0 -176
  74. bencher/variables/sweep_base.py +0 -167
  75. bencher/variables/time.py +0 -74
  76. holobench-1.3.5.dist-info/RECORD +0 -74
  77. /bencher/example/__init__.py → /holobench-1.22.2.data/data/share/ament_index/resource_index/packages/bencher +0 -0
@@ -1,111 +0,0 @@
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)
@@ -1,144 +0,0 @@
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(run_cfg.debug)
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
@@ -1,82 +0,0 @@
1
- import bencher as bch
2
- import numpy as np
3
- import math
4
- import holoviews as hv
5
- import matplotlib.pyplot as plt
6
-
7
-
8
- def polygon_points(radius: float, sides: int):
9
- points = []
10
- for ang in np.linspace(0, math.pi * 2, sides + 1):
11
- points.append(([math.sin(ang) * radius, math.cos(ang) * radius]))
12
- return points
13
-
14
-
15
- class BenchPolygons(bch.ParametrizedSweep):
16
- sides = bch.IntSweep(default=3, bounds=(3, 5))
17
- radius = bch.FloatSweep(default=1, bounds=(1, 2))
18
- linewidth = bch.FloatSweep(default=1, bounds=(1, 10))
19
- linestyle = bch.StringSweep(["solid", "dashed", "dotted"])
20
- color = bch.StringSweep(["red", "green", "blue"])
21
- polygon = bch.ResultImage()
22
- hmap = bch.ResultHmap()
23
-
24
- def __call__(self, **kwargs):
25
- self.update_params_from_kwargs(**kwargs)
26
- points = polygon_points(self.radius, self.sides)
27
- self.hmap = hv.Curve(points)
28
- self.polygon = self.points_to_polygon_png(points, bch.gen_image_path("polygon"))
29
- return super().__call__()
30
-
31
- def points_to_polygon_png(self, points: list[float], filename: str):
32
- """Draw a closed polygon and save to png"""
33
- fig = plt.figure(frameon=False)
34
- ax = plt.Axes(fig, [0.0, 0.0, 1.0, 1.0], frameon=False)
35
- ax.set_axis_off()
36
- ax.plot(
37
- [p[0] for p in points],
38
- [p[1] for p in points],
39
- linewidth=self.linewidth,
40
- linestyle=self.linestyle,
41
- color=self.color,
42
- )
43
- ax.set_aspect("equal")
44
- fig.add_axes(ax)
45
- fig.savefig(filename, dpi=50)
46
- return filename
47
-
48
-
49
- def example_image(
50
- run_cfg: bch.BenchRunCfg = bch.BenchRunCfg(), report: bch.BenchReport = bch.BenchReport()
51
- ) -> bch.Bench:
52
- bench = bch.Bench("polygons", BenchPolygons(), run_cfg=run_cfg, report=report)
53
-
54
- for s in [
55
- [BenchPolygons.param.sides],
56
- [BenchPolygons.param.sides, BenchPolygons.param.linewidth],
57
- [BenchPolygons.param.sides, BenchPolygons.param.linewidth, BenchPolygons.param.linestyle],
58
- [
59
- BenchPolygons.param.sides,
60
- BenchPolygons.param.linewidth,
61
- BenchPolygons.param.linestyle,
62
- BenchPolygons.param.color,
63
- ],
64
- [
65
- BenchPolygons.param.sides,
66
- BenchPolygons.param.linewidth,
67
- BenchPolygons.param.linestyle,
68
- BenchPolygons.param.color,
69
- BenchPolygons.param.radius,
70
- ],
71
- ]:
72
- bench.plot_sweep(
73
- f"Polygons Sweeping {len(s)} Parameters",
74
- input_vars=s,
75
- result_vars=[BenchPolygons.param.polygon],
76
- )
77
-
78
- return bench
79
-
80
-
81
- if __name__ == "__main__":
82
- example_image(bch.BenchRunCfg(level=2)).report.show()
@@ -1,181 +0,0 @@
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(False)),
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()
@@ -1,53 +0,0 @@
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()
@@ -1,85 +0,0 @@
1
- import bencher as bch
2
-
3
-
4
- class UnreliableClass(bch.ParametrizedSweep):
5
- """This class helps demonstrate benchmarking a function that sometimes crashes during sampling. By using BenchRunCfg.use_sample_cache you can store the results of every call to the benchmark function so data is not lost in the event of a crash. However, because cache invalidation is hard (https://martinfowler.com/bliki/TwoHardThings.html) you need to be mindful of how you could get bad results due to incorrect cache data. For example if you change your benchmark function and use the sample cache you will not get correct values; you will need to use BenchRunCfg.clear_sample_cache to purge any out of date results."""
6
-
7
- input_val = bch.IntSweep(
8
- default=0,
9
- bounds=[0, 3],
10
- doc="If check limit=True the crashy_fn will crash if this value is >1",
11
- )
12
- return_value = bch.ResultVar(
13
- units="ul",
14
- doc="This is a dummy result variable. In this example, it is the same as the value passed in.",
15
- )
16
- trigger_crash = bch.ResultVar(
17
- units="True/False",
18
- doc="if true crashy_fn will crash when input_val >1",
19
- )
20
-
21
- def crashy_fn(self, input_val: int = 0, **kwargs) -> float: # pylint: disable=unused-argument
22
- if self.trigger_crash:
23
- if input_val > 1:
24
- raise RuntimeError("I crashed for no good reason ;P")
25
-
26
- return {"return_value": input_val, "trigger_crash": self.trigger_crash}
27
-
28
-
29
- def example_sample_cache(
30
- run_cfg: bch.BenchRunCfg = bch.BenchRunCfg(),
31
- report: bch.BenchReport = bch.BenchReport(),
32
- trigger_crash: bool = False,
33
- ) -> bch.Bench:
34
- """This example shows how to use the use_sample_cache option to deal with unreliable functions and to continue benchmarking using previously calculated results even if the code crashed during the run
35
-
36
- Args:
37
- run_cfg (BenchRunCfg): configuration of how to perform the param sweep
38
- trigger_crash: (bool): Turn on/off code to artificially trigger a crash
39
-
40
- Returns:
41
- Bench: results of the parameter sweep
42
- """
43
-
44
- instance = UnreliableClass()
45
- instance.trigger_crash = trigger_crash
46
-
47
- bencher = bch.Bench("example_sample_cache", instance.crashy_fn, run_cfg=run_cfg, report=report)
48
-
49
- bencher.plot_sweep(
50
- title="Example Crashy Function with the sample_cache",
51
- input_vars=[UnreliableClass.param.input_val],
52
- result_vars=[UnreliableClass.param.return_value, UnreliableClass.param.trigger_crash],
53
- description="""This example shows how to use the use_sample_cache option to deal with unreliable functions and to continue benchmarking using previously calculated results even if the code crashed during the run""",
54
- run_cfg=run_cfg,
55
- post_description="The input_val vs return value graph is a straight line as expected and there is no record of the fact the benchmark crashed halfway through. The second graph shows that for values >1 the trigger_crash value had to be 0 in order to proceed",
56
- )
57
- return bencher
58
-
59
-
60
- if __name__ == "__main__":
61
- ex_run_cfg = bch.BenchRunCfg()
62
- ex_run_cfg.repeats = 1
63
- ex_run_cfg.executor = bch.Executors.SCOOP
64
-
65
- # this will store the result of of every call to crashy_fn
66
- ex_run_cfg.use_sample_cache = True
67
- ex_run_cfg.clear_sample_cache = True
68
-
69
- try:
70
- # this will crash after iteration 2 because we are checking the crash_threshold >1. We don't want to lose those (potentially expensive to calculate) datapoints so they are stored in the sample_cache
71
- example_sample_cache(ex_run_cfg, trigger_crash=True)
72
- except RuntimeError as e:
73
- print(f"caught the exception {e}")
74
-
75
- print(
76
- "Running the same benchmark but without checking the limit. The benchmarking should load the previously calculated values and continue to finish calculating the values that were missed due to the crash"
77
- )
78
- ex_run_cfg.clear_sample_cache = False
79
- example_sample_cache(ex_run_cfg, trigger_crash=False)
80
-
81
- ex_run_cfg.repeats = 2
82
-
83
- example_sample_cache(ex_run_cfg, trigger_crash=False).report.show()
84
-
85
- # see the test_sample_cache for a more detailed explanation of the mechanisms of the cache