holobench 1.40.1__py3-none-any.whl → 1.42.0__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.
- CHANGELOG.md +10 -0
- bencher/__init__.py +20 -2
- bencher/bench_cfg.py +265 -61
- bencher/bench_report.py +2 -2
- bencher/bench_runner.py +96 -10
- bencher/bencher.py +421 -89
- bencher/caching.py +1 -4
- bencher/class_enum.py +70 -7
- bencher/example/example_composable_container_image.py +60 -0
- bencher/example/example_composable_container_video.py +49 -0
- bencher/example/example_dataframe.py +2 -2
- bencher/example/example_image.py +17 -21
- bencher/example/example_image1.py +16 -20
- bencher/example/example_levels.py +17 -173
- bencher/example/example_pareto.py +107 -31
- bencher/example/example_rerun2.py +1 -1
- bencher/example/example_simple_bool.py +2 -2
- bencher/example/example_simple_float2d.py +6 -1
- bencher/example/example_video.py +35 -17
- bencher/example/experimental/example_hvplot_explorer.py +3 -4
- bencher/example/inputs_0D/example_0_in_1_out.py +25 -15
- bencher/example/inputs_0D/example_0_in_2_out.py +12 -3
- bencher/example/inputs_0_float/example_0_cat_in_2_out.py +88 -0
- bencher/example/inputs_0_float/example_1_cat_in_2_out.py +98 -0
- bencher/example/inputs_0_float/example_2_cat_in_2_out.py +107 -0
- bencher/example/inputs_0_float/example_3_cat_in_2_out.py +111 -0
- bencher/example/inputs_1D/example1d_common.py +48 -12
- bencher/example/inputs_1D/example_0_float_1_cat.py +33 -0
- bencher/example/inputs_1D/example_1_cat_in_2_out_repeats.py +68 -0
- bencher/example/inputs_1D/example_1_float_2_cat_repeats.py +15 -0
- bencher/example/inputs_1D/example_1_int_in_1_out.py +98 -0
- bencher/example/inputs_1D/example_1_int_in_2_out.py +101 -0
- bencher/example/inputs_1D/example_1_int_in_2_out_repeats.py +99 -0
- bencher/example/inputs_1_float/example_1_float_0_cat_in_2_out.py +117 -0
- bencher/example/inputs_1_float/example_1_float_1_cat_in_2_out.py +124 -0
- bencher/example/inputs_1_float/example_1_float_2_cat_in_2_out.py +132 -0
- bencher/example/inputs_1_float/example_1_float_3_cat_in_2_out.py +140 -0
- bencher/example/inputs_2D/example_2_cat_in_4_out_repeats.py +104 -0
- bencher/example/inputs_2_float/example_2_float_0_cat_in_2_out.py +98 -0
- bencher/example/inputs_2_float/example_2_float_1_cat_in_2_out.py +112 -0
- bencher/example/inputs_2_float/example_2_float_2_cat_in_2_out.py +122 -0
- bencher/example/inputs_2_float/example_2_float_3_cat_in_2_out.py +138 -0
- bencher/example/inputs_3_float/example_3_float_0_cat_in_2_out.py +111 -0
- bencher/example/inputs_3_float/example_3_float_1_cat_in_2_out.py +117 -0
- bencher/example/inputs_3_float/example_3_float_2_cat_in_2_out.py +124 -0
- bencher/example/inputs_3_float/example_3_float_3_cat_in_2_out.py +129 -0
- bencher/example/meta/generate_examples.py +124 -7
- bencher/example/meta/generate_meta.py +88 -40
- bencher/job.py +175 -12
- bencher/plotting/plot_filter.py +52 -17
- bencher/results/bench_result.py +119 -26
- bencher/results/bench_result_base.py +119 -10
- bencher/results/composable_container/composable_container_video.py +39 -12
- bencher/results/dataset_result.py +6 -200
- bencher/results/explorer_result.py +23 -0
- bencher/results/{hvplot_result.py → histogram_result.py} +3 -18
- bencher/results/holoview_results/__init__.py +0 -0
- bencher/results/holoview_results/bar_result.py +79 -0
- bencher/results/holoview_results/curve_result.py +110 -0
- bencher/results/holoview_results/distribution_result/__init__.py +0 -0
- bencher/results/holoview_results/distribution_result/box_whisker_result.py +73 -0
- bencher/results/holoview_results/distribution_result/distribution_result.py +109 -0
- bencher/results/holoview_results/distribution_result/scatter_jitter_result.py +92 -0
- bencher/results/holoview_results/distribution_result/violin_result.py +70 -0
- bencher/results/holoview_results/heatmap_result.py +319 -0
- bencher/results/holoview_results/holoview_result.py +346 -0
- bencher/results/holoview_results/line_result.py +240 -0
- bencher/results/holoview_results/scatter_result.py +107 -0
- bencher/results/holoview_results/surface_result.py +158 -0
- bencher/results/holoview_results/table_result.py +14 -0
- bencher/results/holoview_results/tabulator_result.py +20 -0
- bencher/results/laxtex_result.py +42 -35
- bencher/results/optuna_result.py +30 -115
- bencher/results/video_controls.py +38 -0
- bencher/results/video_result.py +39 -36
- bencher/results/video_summary.py +2 -2
- bencher/results/{plotly_result.py → volume_result.py} +29 -8
- bencher/utils.py +176 -30
- bencher/variables/inputs.py +122 -15
- bencher/video_writer.py +38 -2
- bencher/worker_job.py +34 -7
- {holobench-1.40.1.dist-info → holobench-1.42.0.dist-info}/METADATA +21 -25
- holobench-1.42.0.dist-info/RECORD +147 -0
- bencher/example/example_composable_container.py +0 -106
- bencher/example/example_levels2.py +0 -37
- bencher/example/inputs_1D/example_1_in_1_out.py +0 -62
- bencher/example/inputs_1D/example_1_in_2_out.py +0 -63
- bencher/example/inputs_1D/example_1_in_2_out_repeats.py +0 -61
- bencher/results/holoview_result.py +0 -787
- bencher/results/panel_result.py +0 -41
- holobench-1.40.1.dist-info/RECORD +0 -111
- {holobench-1.40.1.dist-info → holobench-1.42.0.dist-info}/WHEEL +0 -0
- {holobench-1.40.1.dist-info → holobench-1.42.0.dist-info}/licenses/LICENSE +0 -0
bencher/caching.py
CHANGED
@@ -3,9 +3,6 @@ from diskcache import Cache
|
|
3
3
|
from bencher.variables.parametrised_sweep import ParametrizedSweep
|
4
4
|
from bencher.utils import hash_sha1
|
5
5
|
import logging
|
6
|
-
from sortedcontainers import SortedDict
|
7
|
-
|
8
|
-
# from job import job,JobCache,JobFunctionCache
|
9
6
|
|
10
7
|
|
11
8
|
class CachedParams(ParametrizedSweep):
|
@@ -20,7 +17,7 @@ class CachedParams(ParametrizedSweep):
|
|
20
17
|
self.cache.clear()
|
21
18
|
|
22
19
|
def kwargs_to_hash_key(self, **kwargs):
|
23
|
-
return tuple(
|
20
|
+
return tuple(sorted(kwargs.items(), key=lambda item: str(item[0])))
|
24
21
|
|
25
22
|
def in_cache(self, **kwargs):
|
26
23
|
self.update_params_from_kwargs(**kwargs)
|
bencher/class_enum.py
CHANGED
@@ -1,52 +1,115 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
from strenum import StrEnum
|
3
|
-
from typing import Any
|
3
|
+
from typing import Any, TypeVar
|
4
4
|
import importlib
|
5
5
|
from abc import abstractmethod
|
6
6
|
from dataclasses import dataclass
|
7
7
|
from enum import auto
|
8
8
|
|
9
|
+
T = TypeVar("T") # Generic type for return value of to_class
|
10
|
+
|
9
11
|
|
10
12
|
class ClassEnum(StrEnum):
|
11
|
-
"""A
|
13
|
+
"""A string-based enum class that maps enum values to corresponding class instances.
|
14
|
+
|
15
|
+
ClassEnum is a pattern to make it easier to create a factory method that converts
|
16
|
+
from an enum value to a corresponding class instance. Subclasses should implement
|
17
|
+
the to_class() method which takes an enum value and returns an instance of the
|
18
|
+
corresponding class.
|
19
|
+
|
20
|
+
This pattern is useful for configuration-driven class instantiation, allowing
|
21
|
+
classes to be selected via string configuration values that match enum names.
|
22
|
+
"""
|
12
23
|
|
13
24
|
@classmethod
|
14
25
|
def to_class_generic(cls, module_import: str, class_name: str) -> Any:
|
15
|
-
"""Create an instance of
|
26
|
+
"""Create an instance of a class from its module path and class name.
|
27
|
+
|
28
|
+
This utility method dynamically imports a module and instantiates a class from it.
|
29
|
+
|
30
|
+
Args:
|
31
|
+
module_import (str): The module path to import (e.g., "bencher.class_enum")
|
32
|
+
class_name (str): The name of the class to instantiate
|
16
33
|
|
17
34
|
Returns:
|
18
|
-
Any: instance of the class
|
35
|
+
Any: A new instance of the specified class
|
19
36
|
"""
|
20
|
-
|
21
37
|
class_def = getattr(importlib.import_module(module_import), class_name)
|
22
38
|
return class_def()
|
23
39
|
|
24
40
|
@classmethod
|
25
41
|
@abstractmethod
|
26
42
|
def to_class(cls, enum_val: ClassEnum) -> Any:
|
27
|
-
"""
|
28
|
-
|
43
|
+
"""Convert an enum value to its corresponding class instance.
|
44
|
+
|
45
|
+
Subclasses must override this method to implement the mapping from
|
46
|
+
enum values to class instances.
|
47
|
+
|
48
|
+
Args:
|
49
|
+
enum_val (ClassEnum): The enum value to convert to a class instance
|
50
|
+
|
51
|
+
Returns:
|
52
|
+
Any: An instance of the class corresponding to the enum value
|
53
|
+
|
54
|
+
Raises:
|
55
|
+
NotImplementedError: If this method is not overridden by a subclass
|
56
|
+
"""
|
57
|
+
raise NotImplementedError("Subclasses must implement to_class()")
|
29
58
|
|
30
59
|
|
31
60
|
@dataclass
|
32
61
|
class BaseClass:
|
62
|
+
"""Base class for the ClassEnum example.
|
63
|
+
|
64
|
+
A simple dataclass that serves as the base class for the ClassEnum example classes.
|
65
|
+
|
66
|
+
Attributes:
|
67
|
+
baseclassname (str): A name for the base class
|
68
|
+
"""
|
69
|
+
|
33
70
|
baseclassname: str = "class0"
|
34
71
|
|
35
72
|
|
36
73
|
@dataclass
|
37
74
|
class Class1(BaseClass):
|
75
|
+
"""Example subclass 1 for the ClassEnum demonstration.
|
76
|
+
|
77
|
+
Attributes:
|
78
|
+
classname (str): A name for this class
|
79
|
+
"""
|
80
|
+
|
38
81
|
classname: str = "class1"
|
39
82
|
|
40
83
|
|
41
84
|
@dataclass
|
42
85
|
class Class2(BaseClass):
|
86
|
+
"""Example subclass 2 for the ClassEnum demonstration.
|
87
|
+
|
88
|
+
Attributes:
|
89
|
+
classname (str): A name for this class
|
90
|
+
"""
|
91
|
+
|
43
92
|
classname: str = "class2"
|
44
93
|
|
45
94
|
|
46
95
|
class ExampleEnum(ClassEnum):
|
96
|
+
"""An example implementation of ClassEnum.
|
97
|
+
|
98
|
+
This enum demonstrates how to use ClassEnum to map enum values to class instances.
|
99
|
+
Each enum value corresponds to a class name that can be instantiated.
|
100
|
+
"""
|
101
|
+
|
47
102
|
Class1 = auto()
|
48
103
|
Class2 = auto()
|
49
104
|
|
50
105
|
@classmethod
|
51
106
|
def to_class(cls, enum_val: ExampleEnum) -> BaseClass:
|
107
|
+
"""Convert an ExampleEnum value to its corresponding class instance.
|
108
|
+
|
109
|
+
Args:
|
110
|
+
enum_val (ExampleEnum): The enum value to convert
|
111
|
+
|
112
|
+
Returns:
|
113
|
+
BaseClass: An instance of either Class1 or Class2, depending on the enum value
|
114
|
+
"""
|
52
115
|
return cls.to_class_generic("bencher.class_enum", enum_val)
|
@@ -0,0 +1,60 @@
|
|
1
|
+
import bencher as bch
|
2
|
+
|
3
|
+
from bencher.example.example_image import BenchPolygons
|
4
|
+
|
5
|
+
|
6
|
+
class BenchComposableContainerImage(BenchPolygons):
|
7
|
+
compose_method = bch.EnumSweep(bch.ComposeType)
|
8
|
+
labels = bch.BoolSweep()
|
9
|
+
num_frames = bch.IntSweep(default=5, bounds=[1, 100])
|
10
|
+
|
11
|
+
polygon_vid = bch.ResultVideo()
|
12
|
+
|
13
|
+
def __call__(self, **kwargs):
|
14
|
+
self.update_params_from_kwargs(**kwargs)
|
15
|
+
var_name = None
|
16
|
+
var_value = None
|
17
|
+
|
18
|
+
if self.labels:
|
19
|
+
var_name = "sides"
|
20
|
+
var_value = self.sides
|
21
|
+
vr = bch.ComposableContainerVideo()
|
22
|
+
for i in range(self.num_frames):
|
23
|
+
res = super().__call__(start_angle=i)
|
24
|
+
print(res)
|
25
|
+
vr.append(res["polygon"])
|
26
|
+
self.polygon_vid = vr.to_video(
|
27
|
+
bch.RenderCfg(
|
28
|
+
compose_method=self.compose_method,
|
29
|
+
var_name=var_name,
|
30
|
+
var_value=var_value,
|
31
|
+
max_frame_duration=1.0 / 20.0,
|
32
|
+
)
|
33
|
+
)
|
34
|
+
return self.get_results_values_as_dict()
|
35
|
+
|
36
|
+
|
37
|
+
def example_composable_container_image(
|
38
|
+
run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None
|
39
|
+
) -> bch.Bench:
|
40
|
+
bench = BenchComposableContainerImage().to_bench(run_cfg, report)
|
41
|
+
# bench.add_plot_callback(bch.BenchResult.to_panes)
|
42
|
+
# bench.add_plot_callback(bch.BenchResult.to_video_grid, result_types=(bch.ResultVideo))
|
43
|
+
# bench.add_plot_callback(bch.BenchResult.to_video_summary, result_types=(bch.ResultVideo))
|
44
|
+
# bench.plot_sweep(input_vars=["compose_method", "labels"])
|
45
|
+
|
46
|
+
bench.plot_sweep(input_vars=["compose_method"])
|
47
|
+
|
48
|
+
# bench.compose_
|
49
|
+
# bench.plot_sweep(
|
50
|
+
# input_vars=[bch.p("num_frames", [2, 8, 20])],
|
51
|
+
# const_vars=dict(compose_method=bch.ComposeType.sequence),
|
52
|
+
# )
|
53
|
+
|
54
|
+
return bench
|
55
|
+
|
56
|
+
|
57
|
+
if __name__ == "__main__":
|
58
|
+
ex_run_cfg = bch.BenchRunCfg()
|
59
|
+
ex_composable_image = example_composable_container_image(ex_run_cfg)
|
60
|
+
ex_composable_image.report.show()
|
@@ -0,0 +1,49 @@
|
|
1
|
+
import bencher as bch
|
2
|
+
from bencher.example.example_composable_container_image import BenchComposableContainerImage
|
3
|
+
|
4
|
+
|
5
|
+
class BenchComposableContainerVideo(bch.ParametrizedSweep):
|
6
|
+
unequal_length = bch.BoolSweep()
|
7
|
+
compose_method = bch.EnumSweep(bch.ComposeType)
|
8
|
+
labels = bch.BoolSweep()
|
9
|
+
polygon_vid = bch.ResultVideo()
|
10
|
+
|
11
|
+
def __call__(self, **kwargs):
|
12
|
+
self.update_params_from_kwargs(**kwargs)
|
13
|
+
vr = bch.ComposableContainerVideo()
|
14
|
+
for i in range(3, 5):
|
15
|
+
num_frames = i * 10 if self.unequal_length else 5
|
16
|
+
res = BenchComposableContainerImage().__call__(
|
17
|
+
compose_method=bch.ComposeType.sequence, sides=i, num_frames=num_frames
|
18
|
+
)
|
19
|
+
vr.append(res["polygon_vid"])
|
20
|
+
|
21
|
+
self.polygon_vid = vr.to_video(bch.RenderCfg(compose_method=kwargs.get("compose_method")))
|
22
|
+
return self.get_results_values_as_dict()
|
23
|
+
|
24
|
+
|
25
|
+
def example_composable_container_video(
|
26
|
+
run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None
|
27
|
+
) -> bch.Bench:
|
28
|
+
bench = BenchComposableContainerVideo().to_bench(run_cfg, report)
|
29
|
+
|
30
|
+
bench.result_vars = ["polygon_vid"]
|
31
|
+
bench.add_plot_callback(bch.BenchResult.to_panes)
|
32
|
+
bench.add_plot_callback(bch.BenchResult.to_video_grid, result_types=(bch.ResultVideo))
|
33
|
+
bench.add_plot_callback(bch.BenchResult.to_video_summary, result_types=(bch.ResultVideo))
|
34
|
+
bench.plot_sweep(input_vars=["compose_method", "labels"], const_vars=dict(unequal_length=True))
|
35
|
+
|
36
|
+
res = bench.plot_sweep(
|
37
|
+
input_vars=[],
|
38
|
+
const_vars=dict(unequal_length=False, compose_method=bch.ComposeType.sequence),
|
39
|
+
plot_callbacks=False,
|
40
|
+
)
|
41
|
+
|
42
|
+
bench.report.append(res.to_video_grid())
|
43
|
+
|
44
|
+
return bench
|
45
|
+
|
46
|
+
|
47
|
+
if __name__ == "__main__":
|
48
|
+
ex_run_cfg = bch.BenchRunCfg()
|
49
|
+
example_composable_container_video(ex_run_cfg).report.show()
|
@@ -25,7 +25,7 @@ class ExampleMergeDataset(bch.ParametrizedSweep):
|
|
25
25
|
|
26
26
|
def example_dataset(run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None):
|
27
27
|
bench = ExampleMergeDataset().to_bench(run_cfg, report)
|
28
|
-
|
28
|
+
bench.plot_sweep(input_vars=["value"], const_vars=dict(repeats_x=4))
|
29
29
|
# bench.report.append(res.to_panes(target_dimension=1))
|
30
30
|
# bench.report.append(res.to_panes(target_dimension=2))
|
31
31
|
# bench.reprt.append(res.to_video_grid
|
@@ -39,7 +39,7 @@ def example_dataset(run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = N
|
|
39
39
|
# )
|
40
40
|
# bench.report.append(res.to_panes(container=hv.Bars,target_dimension=1))
|
41
41
|
# bench.report.append(res.to_panes(container=hv.Curve))
|
42
|
-
bench.
|
42
|
+
bench.add(bch.DataSetResult, container=hv.Curve)
|
43
43
|
return bench
|
44
44
|
|
45
45
|
|
bencher/example/example_image.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import bencher as bch
|
2
2
|
import numpy as np
|
3
3
|
import math
|
4
|
-
import
|
4
|
+
from PIL import Image, ImageDraw
|
5
5
|
|
6
6
|
|
7
7
|
def polygon_points(radius: float, sides: int, start_angle: float):
|
@@ -16,7 +16,6 @@ class BenchPolygons(bch.ParametrizedSweep):
|
|
16
16
|
sides = bch.IntSweep(default=3, bounds=(3, 7))
|
17
17
|
radius = bch.FloatSweep(default=1, bounds=(0.2, 1))
|
18
18
|
linewidth = bch.FloatSweep(default=1, bounds=(1, 10))
|
19
|
-
linestyle = bch.StringSweep(["solid", "dashed", "dotted"])
|
20
19
|
color = bch.StringSweep(["red", "green", "blue"])
|
21
20
|
start_angle = bch.FloatSweep(default=0, bounds=[0, 360])
|
22
21
|
polygon = bch.ResultImage()
|
@@ -26,33 +25,30 @@ class BenchPolygons(bch.ParametrizedSweep):
|
|
26
25
|
def __call__(self, **kwargs):
|
27
26
|
self.update_params_from_kwargs(**kwargs)
|
28
27
|
points = polygon_points(self.radius, self.sides, self.start_angle)
|
29
|
-
|
30
|
-
self.polygon = self.points_to_polygon_png(points,
|
28
|
+
filepath = bch.gen_image_path("polygon")
|
29
|
+
self.polygon = self.points_to_polygon_png(points, filepath)
|
30
|
+
# Verify filepath is being returned
|
31
|
+
assert isinstance(self.polygon, str), f"Expected string filepath, got {type(self.polygon)}"
|
31
32
|
|
32
33
|
self.side_length = 2 * self.radius * math.sin(math.pi / self.sides)
|
33
34
|
self.area = (self.sides * self.side_length**2) / (4 * math.tan(math.pi / self.sides))
|
34
35
|
return super().__call__()
|
35
36
|
|
36
37
|
def points_to_polygon_png(self, points: list[float], filename: str):
|
37
|
-
"""Draw a closed polygon and save to png"""
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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)
|
38
|
+
"""Draw a closed polygon and save to png using PIL"""
|
39
|
+
size = 300
|
40
|
+
img = Image.new("RGBA", (size, size), (0, 0, 0, 0))
|
41
|
+
draw = ImageDraw.Draw(img)
|
42
|
+
|
43
|
+
# Scale points to image size (from [-1,1] to [0,size])
|
44
|
+
scaled_points = [(((p[0] + 1) * size / 2), ((1 - p[1]) * size / 2)) for p in points]
|
50
45
|
|
51
|
-
|
52
|
-
|
53
|
-
fig.savefig(filename, dpi=30)
|
46
|
+
# Draw polygon outline
|
47
|
+
draw.line(scaled_points, fill=self.color, width=int(self.linewidth))
|
54
48
|
|
55
|
-
|
49
|
+
img.save(filename, "PNG")
|
50
|
+
# Explicitly return the filename string
|
51
|
+
return str(filename)
|
56
52
|
|
57
53
|
|
58
54
|
def example_image(run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None) -> bch.Bench:
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import bencher as bch
|
2
2
|
import numpy as np
|
3
3
|
import math
|
4
|
-
import
|
4
|
+
from PIL import Image, ImageDraw
|
5
5
|
|
6
6
|
|
7
7
|
def polygon_points(radius: float, sides: int, start_angle: float):
|
@@ -28,36 +28,32 @@ class BenchPolygons(bch.ParametrizedSweep):
|
|
28
28
|
def __call__(self, **kwargs):
|
29
29
|
self.update_params_from_kwargs(**kwargs)
|
30
30
|
points = polygon_points(self.radius, self.sides, self.start_angle)
|
31
|
-
|
32
|
-
self.polygon = self.points_to_polygon_png(points,
|
31
|
+
filepath = bch.gen_image_path("polygon")
|
32
|
+
self.polygon = self.points_to_polygon_png(points, filepath, dpi=30)
|
33
33
|
self.polygon_small = self.points_to_polygon_png(
|
34
34
|
points, bch.gen_image_path("polygon"), dpi=10
|
35
35
|
)
|
36
|
+
# Verify filepaths are being returned
|
37
|
+
assert isinstance(self.polygon, str), f"Expected string filepath, got {type(self.polygon)}"
|
38
|
+
assert isinstance(self.polygon_small, str), (
|
39
|
+
f"Expected string filepath, got {type(self.polygon_small)}"
|
40
|
+
)
|
36
41
|
|
37
42
|
self.side_length = 2 * self.radius * math.sin(math.pi / self.sides)
|
38
43
|
self.area = (self.sides * self.side_length**2) / (4 * math.tan(math.pi / self.sides))
|
39
44
|
return super().__call__()
|
40
45
|
|
41
46
|
def points_to_polygon_png(self, points: list[float], filename: str, dpi):
|
42
|
-
"""Draw a closed polygon and save to png"""
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
ax.plot(
|
47
|
-
[p[0] for p in points],
|
48
|
-
[p[1] for p in points],
|
49
|
-
linewidth=self.linewidth,
|
50
|
-
linestyle=self.linestyle,
|
51
|
-
color=self.color,
|
52
|
-
)
|
53
|
-
ax.set_xlim(-1, 1)
|
54
|
-
ax.set_ylim(-1, 1)
|
47
|
+
"""Draw a closed polygon and save to png using PIL"""
|
48
|
+
size = int(100 * (dpi / 30))
|
49
|
+
img = Image.new("RGBA", (size, size), (0, 0, 0, 0))
|
50
|
+
draw = ImageDraw.Draw(img)
|
55
51
|
|
56
|
-
|
57
|
-
|
58
|
-
fig.savefig(filename, dpi=dpi)
|
52
|
+
scaled_points = [(((p[0] + 1) * size / 2), ((1 - p[1]) * size / 2)) for p in points]
|
53
|
+
draw.line(scaled_points, fill=self.color, width=int(self.linewidth))
|
59
54
|
|
60
|
-
|
55
|
+
img.save(filename, "PNG")
|
56
|
+
return str(filename)
|
61
57
|
|
62
58
|
|
63
59
|
def example_image_vid_sequential1(
|
@@ -1,179 +1,23 @@
|
|
1
1
|
import bencher as bch
|
2
|
-
from bencher.
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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 upper 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,
|
2
|
+
from bencher.example.meta.example_meta import BenchMeta
|
3
|
+
|
4
|
+
|
5
|
+
def example_levels(run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None) -> bch.Bench:
|
6
|
+
bench = BenchMeta().to_bench(run_cfg, report)
|
7
|
+
|
8
|
+
bench.plot_sweep(
|
9
|
+
title="Using Levels to define sample density",
|
10
|
+
description="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",
|
11
|
+
input_vars=[
|
12
|
+
bch.p("float_vars", [1, 2]),
|
13
|
+
bch.p("level", [2, 3, 4, 5]),
|
14
|
+
],
|
15
|
+
const_vars=[
|
16
|
+
BenchMeta.param.categorical_vars.with_const(0),
|
17
|
+
],
|
86
18
|
)
|
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(run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None) -> bch.Bench:
|
165
|
-
hv.extension("bokeh")
|
166
|
-
opts.defaults(
|
167
|
-
opts.Curve(show_legend=False),
|
168
|
-
opts.Points(show_legend=False),
|
169
|
-
)
|
170
|
-
|
171
|
-
bench = bch.Bench("Levels", LevelsExample(), run_cfg=run_cfg, report=report)
|
172
|
-
bench = run_levels_1D(bench)
|
173
|
-
bench = run_levels_2D(bench)
|
174
|
-
|
175
19
|
return bench
|
176
20
|
|
177
21
|
|
178
22
|
if __name__ == "__main__":
|
179
|
-
|
23
|
+
example_levels().report.show()
|