holobench 1.41.0__py3-none-any.whl → 1.43.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.
Files changed (84) hide show
  1. bencher/__init__.py +20 -2
  2. bencher/bench_cfg.py +262 -54
  3. bencher/bench_report.py +2 -2
  4. bencher/bench_runner.py +96 -10
  5. bencher/bencher.py +421 -89
  6. bencher/class_enum.py +70 -7
  7. bencher/example/example_dataframe.py +2 -2
  8. bencher/example/example_levels.py +17 -173
  9. bencher/example/example_pareto.py +107 -31
  10. bencher/example/example_rerun2.py +1 -1
  11. bencher/example/example_simple_bool.py +2 -2
  12. bencher/example/example_simple_float2d.py +6 -1
  13. bencher/example/example_video.py +2 -0
  14. bencher/example/experimental/example_hvplot_explorer.py +2 -2
  15. bencher/example/inputs_0D/example_0_in_1_out.py +25 -15
  16. bencher/example/inputs_0D/example_0_in_2_out.py +12 -3
  17. bencher/example/inputs_0_float/example_0_cat_in_2_out.py +88 -0
  18. bencher/example/inputs_0_float/example_1_cat_in_2_out.py +98 -0
  19. bencher/example/inputs_0_float/example_2_cat_in_2_out.py +107 -0
  20. bencher/example/inputs_0_float/example_3_cat_in_2_out.py +111 -0
  21. bencher/example/inputs_1D/example1d_common.py +48 -12
  22. bencher/example/inputs_1D/example_0_float_1_cat.py +33 -0
  23. bencher/example/inputs_1D/example_1_cat_in_2_out_repeats.py +68 -0
  24. bencher/example/inputs_1D/example_1_float_2_cat_repeats.py +3 -0
  25. bencher/example/inputs_1D/example_1_int_in_1_out.py +98 -0
  26. bencher/example/inputs_1D/example_1_int_in_2_out.py +101 -0
  27. bencher/example/inputs_1D/example_1_int_in_2_out_repeats.py +99 -0
  28. bencher/example/inputs_1_float/example_1_float_0_cat_in_2_out.py +117 -0
  29. bencher/example/inputs_1_float/example_1_float_1_cat_in_2_out.py +124 -0
  30. bencher/example/inputs_1_float/example_1_float_2_cat_in_2_out.py +132 -0
  31. bencher/example/inputs_1_float/example_1_float_3_cat_in_2_out.py +140 -0
  32. bencher/example/inputs_2D/example_2_cat_in_4_out_repeats.py +104 -0
  33. bencher/example/inputs_2_float/example_2_float_0_cat_in_2_out.py +98 -0
  34. bencher/example/inputs_2_float/example_2_float_1_cat_in_2_out.py +112 -0
  35. bencher/example/inputs_2_float/example_2_float_2_cat_in_2_out.py +122 -0
  36. bencher/example/inputs_2_float/example_2_float_3_cat_in_2_out.py +138 -0
  37. bencher/example/inputs_3_float/example_3_float_0_cat_in_2_out.py +111 -0
  38. bencher/example/inputs_3_float/example_3_float_1_cat_in_2_out.py +117 -0
  39. bencher/example/inputs_3_float/example_3_float_2_cat_in_2_out.py +124 -0
  40. bencher/example/inputs_3_float/example_3_float_3_cat_in_2_out.py +129 -0
  41. bencher/example/meta/generate_examples.py +118 -7
  42. bencher/example/meta/generate_meta.py +88 -40
  43. bencher/job.py +174 -9
  44. bencher/plotting/plot_filter.py +52 -17
  45. bencher/results/bench_result.py +117 -25
  46. bencher/results/bench_result_base.py +117 -8
  47. bencher/results/dataset_result.py +6 -200
  48. bencher/results/explorer_result.py +23 -0
  49. bencher/results/{hvplot_result.py → histogram_result.py} +3 -18
  50. bencher/results/holoview_results/__init__.py +0 -0
  51. bencher/results/holoview_results/bar_result.py +79 -0
  52. bencher/results/holoview_results/curve_result.py +110 -0
  53. bencher/results/holoview_results/distribution_result/__init__.py +0 -0
  54. bencher/results/holoview_results/distribution_result/box_whisker_result.py +73 -0
  55. bencher/results/holoview_results/distribution_result/distribution_result.py +109 -0
  56. bencher/results/holoview_results/distribution_result/scatter_jitter_result.py +92 -0
  57. bencher/results/holoview_results/distribution_result/violin_result.py +70 -0
  58. bencher/results/holoview_results/heatmap_result.py +319 -0
  59. bencher/results/holoview_results/holoview_result.py +346 -0
  60. bencher/results/holoview_results/line_result.py +240 -0
  61. bencher/results/holoview_results/scatter_result.py +107 -0
  62. bencher/results/holoview_results/surface_result.py +158 -0
  63. bencher/results/holoview_results/table_result.py +14 -0
  64. bencher/results/holoview_results/tabulator_result.py +20 -0
  65. bencher/results/optuna_result.py +30 -115
  66. bencher/results/video_controls.py +38 -0
  67. bencher/results/video_result.py +39 -36
  68. bencher/results/video_summary.py +2 -2
  69. bencher/results/{plotly_result.py → volume_result.py} +29 -8
  70. bencher/utils.py +175 -26
  71. bencher/variables/inputs.py +122 -15
  72. bencher/video_writer.py +2 -1
  73. bencher/worker_job.py +31 -3
  74. {holobench-1.41.0.dist-info → holobench-1.43.0.dist-info}/METADATA +24 -24
  75. holobench-1.43.0.dist-info/RECORD +147 -0
  76. bencher/example/example_levels2.py +0 -37
  77. bencher/example/inputs_1D/example_1_in_1_out.py +0 -62
  78. bencher/example/inputs_1D/example_1_in_2_out.py +0 -63
  79. bencher/example/inputs_1D/example_1_in_2_out_repeats.py +0 -61
  80. bencher/results/holoview_result.py +0 -796
  81. bencher/results/panel_result.py +0 -41
  82. holobench-1.41.0.dist-info/RECORD +0 -114
  83. {holobench-1.41.0.dist-info → holobench-1.43.0.dist-info}/WHEEL +0 -0
  84. {holobench-1.41.0.dist-info → holobench-1.43.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,138 @@
1
+ """Demonstration of benchmarking with 2 float and 3 categorical inputs producing visually distinct patterns.
2
+
3
+ Each categorical input has 2 conditions that create distinctly different surface shapes.
4
+ """
5
+
6
+ import random
7
+ import math
8
+ import bencher as bch
9
+
10
+ random.seed(0)
11
+
12
+
13
+ class PatternBenchmark(bch.ParametrizedSweep):
14
+ """Benchmark demonstrating patterns with distinctive shapes based on categorical settings."""
15
+
16
+ # Float input parameters
17
+ x_value = bch.FloatSweep(default=100, bounds=[1, 100], doc="X value parameter")
18
+ y_value = bch.FloatSweep(default=10, bounds=[1, 100], doc="Y value parameter")
19
+
20
+ # Categorical input parameters - each with 2 conditions
21
+ pattern_type = bch.StringSweep(["linear", "exponential"], doc="Pattern relationship")
22
+ symmetry_type = bch.StringSweep(["symmetric", "asymmetric"], doc="Pattern symmetry")
23
+ feature_type = bch.StringSweep(["smooth", "ridged"], doc="Surface features")
24
+
25
+ # Output metrics
26
+ response_a = bch.ResultVar(units="units", doc="Response variable A")
27
+ response_b = bch.ResultVar(units="units", doc="Response variable B")
28
+
29
+ def __call__(self, **kwargs) -> dict:
30
+ """Generate responses with distinctly different patterns based on categorical inputs."""
31
+ self.update_params_from_kwargs(**kwargs)
32
+
33
+ # Normalize inputs to [0,1]
34
+ x = self.x_value / 100
35
+ y = self.y_value / 100
36
+
37
+ # Set base patterns based on pattern_type
38
+ if self.pattern_type == "linear":
39
+ base_a = 2 * x + 3 * y
40
+ base_b = 3 * x - y
41
+ else: # exponential
42
+ base_a = math.exp(2 * x) * math.exp(y) / math.exp(3)
43
+ base_b = math.exp(x) * math.exp(2 * y) / math.exp(3)
44
+
45
+ # Apply symmetry effect
46
+ if self.symmetry_type == "symmetric":
47
+ sym_a = (x + y) ** 2
48
+ sym_b = (x + y) * abs(x - y)
49
+ else: # asymmetric
50
+ sym_a = x**2 * y
51
+ sym_b = x * y**2
52
+
53
+ # Apply surface features
54
+ if self.feature_type == "smooth":
55
+ feat_a = math.sin(3 * math.pi * x) * math.sin(3 * math.pi * y)
56
+ feat_b = math.cos(3 * math.pi * x) * math.cos(3 * math.pi * y)
57
+ else: # ridged
58
+ feat_a = math.sin(8 * math.pi * x) ** 2 * math.sin(8 * math.pi * y) ** 2
59
+ feat_b = abs(math.sin(10 * math.pi * x * y))
60
+
61
+ # Combine patterns with weights that vary by condition combination
62
+ # Each combination produces a visually distinct surface shape
63
+ weights = {
64
+ "linear": {
65
+ "symmetric": {
66
+ "smooth": ([1, 2, 0.5], [1, 1.5, 0.3]), # Valley pattern
67
+ "ridged": ([1, 1.5, 1.8], [1, 1, 2]), # Diagonal ridges
68
+ },
69
+ "asymmetric": {
70
+ "smooth": ([1, 1.8, 0.7], [1, 1.2, 0.9]), # Tilted plane with waves
71
+ "ridged": ([1, 1, 2.2], [1, 0.8, 2.5]), # Grid pattern
72
+ },
73
+ },
74
+ "exponential": {
75
+ "symmetric": {
76
+ "smooth": ([1, 1, 0.3], [1, 0.8, 0.4]), # Corner peak with ripples
77
+ "ridged": ([1, 0.7, 1.5], [1, 0.5, 1.8]), # Corner peak with ridges
78
+ },
79
+ "asymmetric": {
80
+ "smooth": ([1, 1.5, 0.4], [1, 1.8, 0.2]), # Curved gradient
81
+ "ridged": ([1, 1.2, 1.2], [1, 1.4, 1.4]), # Extreme corner peak
82
+ },
83
+ },
84
+ }
85
+
86
+ # Get the weights for the current combination
87
+ w_a, w_b = weights[self.pattern_type][self.symmetry_type][self.feature_type]
88
+
89
+ # Calculate final responses with weights
90
+ if self.pattern_type == "linear":
91
+ self.response_a = w_a[0] * base_a + w_a[1] * sym_a + w_a[2] * feat_a
92
+ self.response_b = w_b[0] * base_b + w_b[1] * sym_b + w_b[2] * feat_b
93
+ else: # exponential - multiplicative relationship
94
+ self.response_a = base_a * (1 + w_a[1] * sym_a) * (1 + w_a[2] * feat_a)
95
+ self.response_b = base_b * (1 + w_b[1] * sym_b) * (1 + w_b[2] * feat_b)
96
+
97
+ # Add minimal randomness (to maintain pattern visibility)
98
+ random_factor = random.uniform(0.98, 1.02)
99
+ self.response_a *= random_factor
100
+ self.response_b *= random_factor
101
+
102
+ return super().__call__(**kwargs)
103
+
104
+
105
+ def example_2_float_3_cat_in_2_out(
106
+ run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None
107
+ ) -> bch.Bench:
108
+ """Benchmark demonstrating visually distinct patterns based on categorical settings.
109
+
110
+ Args:
111
+ run_cfg: Configuration for the benchmark run
112
+ report: Report to append the results to
113
+
114
+ Returns:
115
+ bch.Bench: The benchmark object
116
+ """
117
+ if run_cfg is None:
118
+ run_cfg = bch.BenchRunCfg()
119
+ run_cfg.repeats = 3 # Fewer repeats for a quicker benchmark
120
+
121
+ bench = PatternBenchmark().to_bench(run_cfg, report)
122
+ bench.plot_sweep(
123
+ title="Pattern Visualization (2 Float, 3 Categorical Variables)",
124
+ description="Response patterns with distinctive shapes based on categorical settings",
125
+ post_description="""
126
+ Pattern Type: Linear (diagonal gradients) vs Exponential (corner-concentrated)
127
+ Symmetry Type: Symmetric (x/y similarity) vs Asymmetric (x/y difference)
128
+ Feature Type: Smooth (gradual transitions) vs Ridged (sharp features)
129
+
130
+ Each combination produces a unique pattern shape that remains visually distinctive
131
+ even with auto-scaling of the color maps.
132
+ """,
133
+ )
134
+ return bench
135
+
136
+
137
+ if __name__ == "__main__":
138
+ example_2_float_3_cat_in_2_out().report.show()
@@ -0,0 +1,111 @@
1
+ """Demonstration of benchmarking with 3 float inputs and no categorical inputs.
2
+
3
+ This example shows a 3D parameter space with consistent mathematical pattern generation.
4
+ """
5
+
6
+ import random
7
+ import math
8
+ import bencher as bch
9
+ import holoviews as hv
10
+
11
+ random.seed(0)
12
+
13
+
14
+ class Pattern3DModel0Cat(bch.ParametrizedSweep):
15
+ """Benchmark demonstrating 3D patterns without categorical settings."""
16
+
17
+ # Float input parameters
18
+ x_value = bch.FloatSweep(default=50, bounds=[0, 100], doc="X value parameter")
19
+ y_value = bch.FloatSweep(default=50, bounds=[0, 100], doc="Y value parameter")
20
+ z_value = bch.FloatSweep(default=50, bounds=[0, 100], doc="Z value parameter")
21
+
22
+ # No categorical inputs - all parameters are fixed
23
+
24
+ # Output metrics
25
+ contrast = bch.ResultVar(units="ratio", doc="Secondary contrast measure")
26
+ intensity = bch.ResultVar(units="units", doc="Primary response intensity")
27
+
28
+ def __call__(self, **kwargs) -> dict:
29
+ """Generate 3D responses with consistent pattern generation."""
30
+ self.update_params_from_kwargs(**kwargs)
31
+
32
+ # Normalize inputs to [0,1]
33
+ x = self.x_value / 100
34
+ y = self.y_value / 100
35
+ z = self.z_value / 100
36
+
37
+ # Fixed to spherical geometry
38
+ # Spherical geometry creates radial patterns from center
39
+ r = math.sqrt(x**2 + y**2 + z**2) / math.sqrt(3)
40
+ theta = math.atan2(y, x) / (2 * math.pi) + 0.5 # normalized [0,1]
41
+ phi = math.acos(z / max(0.001, math.sqrt(x**2 + y**2 + z**2))) / math.pi
42
+
43
+ # Fixed to linear scaling
44
+ # Linear scaling creates more uniform patterns
45
+ scale_factor = 1.5 * r + 0.8 * phi + 0.5 * theta
46
+ scale_factor2 = 0.7 * r + 1.2 * phi + 0.9 * theta
47
+
48
+ # Create wave patterns
49
+ wave1 = math.sin(5 * math.pi * r) * math.cos(4 * math.pi * theta)
50
+ wave2 = math.sin(3 * math.pi * phi) * math.sin(6 * math.pi * r * theta)
51
+
52
+ # Create interference patterns
53
+ pattern1 = math.sin(7 * math.pi * (x + y + z) / 3)
54
+ pattern2 = math.cos(9 * math.pi * x * y * z)
55
+
56
+ # Fixed to additive composition
57
+ # Additive creates smoother transitions
58
+ self.intensity = 0.6 * scale_factor + 0.3 * wave1 + 0.2 * pattern1 + 0.5
59
+ self.contrast = 0.4 * scale_factor2 + 0.5 * wave2 + 0.3 * pattern2 + 0.3
60
+
61
+ # Add minimal randomness (to maintain pattern visibility)
62
+ random_factor = random.uniform(0.98, 1.02)
63
+ self.intensity *= random_factor
64
+ self.contrast *= random_factor
65
+
66
+ # Keep values in a reasonable range
67
+ self.intensity = max(0.1, min(3.0, self.intensity))
68
+ self.contrast = max(0.1, min(3.0, self.contrast))
69
+
70
+ return super().__call__(**kwargs)
71
+
72
+
73
+ def example_3_float_0_cat_in_2_out(
74
+ run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None
75
+ ) -> bch.Bench:
76
+ """Benchmark demonstrating 3D visual patterns with no categorical settings.
77
+
78
+ Args:
79
+ run_cfg: Configuration for the benchmark run
80
+ report: Report to append the results to
81
+
82
+ Returns:
83
+ bch.Bench: The benchmark object
84
+ """
85
+ if run_cfg is None:
86
+ run_cfg = bch.BenchRunCfg()
87
+ run_cfg.level = 5
88
+ run_cfg.repeats = 1 # Fewer repeats for a quicker benchmark
89
+
90
+ hv.opts.defaults(hv.opts.HeatMap(cmap="plasma", width=300, height=300, colorbar=True))
91
+
92
+ bench = Pattern3DModel0Cat().to_bench(run_cfg, report)
93
+ bench.plot_sweep(
94
+ title="3D Pattern Visualization (3 Float Variables, No Categorical Variables)",
95
+ description="Response patterns based purely on 3D coordinates with no categorical settings",
96
+ post_description="""
97
+ This example uses fixed parameters for all categorical settings:
98
+ - Spherical geometry (radial patterns from center)
99
+ - Linear scaling (uniform effects)
100
+ - Additive composition (smooth transitions)
101
+
102
+ 2D slices of the 3D space show how the input coordinates affect the pattern generation.
103
+ The intensity and contrast measures reveal different aspects of the underlying mathematical model.
104
+ """,
105
+ )
106
+
107
+ return bench
108
+
109
+
110
+ if __name__ == "__main__":
111
+ example_3_float_0_cat_in_2_out().report.show()
@@ -0,0 +1,117 @@
1
+ """Demonstration of benchmarking with 3 float and 1 categorical input producing visually distinct patterns.
2
+
3
+ The categorical input has 2 conditions that create distinctly different surface shapes in 3D space.
4
+ """
5
+
6
+ import random
7
+ import math
8
+ import bencher as bch
9
+ import holoviews as hv
10
+
11
+ random.seed(0)
12
+
13
+
14
+ class Pattern3DModel1Cat(bch.ParametrizedSweep):
15
+ """Benchmark demonstrating 3D patterns with distinctive shapes based on 1 categorical setting."""
16
+
17
+ # Float input parameters
18
+ x_value = bch.FloatSweep(default=50, bounds=[0, 100], doc="X value parameter")
19
+ y_value = bch.FloatSweep(default=50, bounds=[0, 100], doc="Y value parameter")
20
+ z_value = bch.FloatSweep(default=50, bounds=[0, 100], doc="Z value parameter")
21
+
22
+ # Categorical input parameter - with 2 conditions
23
+ geometry_type = bch.StringSweep(["spherical", "cylindrical"], doc="Geometry model")
24
+ # Removed scaling_type and composition_type categoricals
25
+
26
+ # Output metrics
27
+ contrast = bch.ResultVar(units="ratio", doc="Secondary contrast measure")
28
+ intensity = bch.ResultVar(units="units", doc="Primary response intensity")
29
+
30
+ def __call__(self, **kwargs) -> dict:
31
+ """Generate 3D responses with distinctly different patterns based on the geometry categorical input."""
32
+ self.update_params_from_kwargs(**kwargs)
33
+
34
+ # Normalize inputs to [0,1]
35
+ x = self.x_value / 100
36
+ y = self.y_value / 100
37
+ z = self.z_value / 100
38
+
39
+ # Calculate radial components based on geometry_type
40
+ if self.geometry_type == "spherical":
41
+ # Spherical geometry creates radial patterns from center
42
+ r = math.sqrt(x**2 + y**2 + z**2) / math.sqrt(3)
43
+ theta = math.atan2(y, x) / (2 * math.pi) + 0.5 # normalized [0,1]
44
+ phi = math.acos(z / max(0.001, math.sqrt(x**2 + y**2 + z**2))) / math.pi
45
+ else: # cylindrical
46
+ # Cylindrical geometry creates patterns based on distance from z-axis
47
+ r = math.sqrt(x**2 + y**2) / math.sqrt(2)
48
+ theta = math.atan2(y, x) / (2 * math.pi) + 0.5
49
+ phi = z # z directly affects the height
50
+
51
+ # Fixed to linear scaling (removed scaling_type categorical)
52
+ # Linear scaling creates more uniform patterns
53
+ scale_factor = 1.5 * r + 0.8 * phi + 0.5 * theta
54
+ scale_factor2 = 0.7 * r + 1.2 * phi + 0.9 * theta
55
+
56
+ # Create wave patterns
57
+ wave1 = math.sin(5 * math.pi * r) * math.cos(4 * math.pi * theta)
58
+ wave2 = math.sin(3 * math.pi * phi) * math.sin(6 * math.pi * r * theta)
59
+
60
+ # Create interference patterns
61
+ pattern1 = math.sin(7 * math.pi * (x + y + z) / 3)
62
+ pattern2 = math.cos(9 * math.pi * x * y * z)
63
+
64
+ # Fixed to additive composition (removed composition_type categorical)
65
+ # Additive creates smoother transitions
66
+ self.intensity = 0.6 * scale_factor + 0.3 * wave1 + 0.2 * pattern1 + 0.5
67
+ self.contrast = 0.4 * scale_factor2 + 0.5 * wave2 + 0.3 * pattern2 + 0.3
68
+
69
+ # Add minimal randomness (to maintain pattern visibility)
70
+ random_factor = random.uniform(0.98, 1.02)
71
+ self.intensity *= random_factor
72
+ self.contrast *= random_factor
73
+
74
+ # Keep values in a reasonable range
75
+ self.intensity = max(0.1, min(3.0, self.intensity))
76
+ self.contrast = max(0.1, min(3.0, self.contrast))
77
+
78
+ return super().__call__(**kwargs)
79
+
80
+
81
+ def example_3_float_1_cat_in_2_out(
82
+ run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None
83
+ ) -> bch.Bench:
84
+ """Benchmark demonstrating 3D visual patterns based on 1 categorical setting.
85
+
86
+ Args:
87
+ run_cfg: Configuration for the benchmark run
88
+ report: Report to append the results to
89
+
90
+ Returns:
91
+ bch.Bench: The benchmark object
92
+ """
93
+ if run_cfg is None:
94
+ run_cfg = bch.BenchRunCfg()
95
+ run_cfg.level = 5
96
+ run_cfg.repeats = 1 # Fewer repeats for a quicker benchmark
97
+
98
+ hv.opts.defaults(hv.opts.HeatMap(cmap="plasma", width=300, height=300, colorbar=True))
99
+
100
+ bench = Pattern3DModel1Cat().to_bench(run_cfg, report)
101
+ bench.plot_sweep(
102
+ title="3D Pattern Visualization (3 Float, 1 Categorical Variable)",
103
+ description="Response patterns with distinctive shapes based on 3D coordinates and 1 categorical setting",
104
+ post_description="""
105
+ Geometry Type: Spherical (radial from center) vs Cylindrical (distance from z-axis)
106
+
107
+ This example uses linear scaling and additive composition for pattern generation (fixed parameters).
108
+ 2D slices of the 3D space show visually distinctive patterns that vary based on the geometry setting.
109
+ The intensity and contrast measures reveal different aspects of the underlying mathematical model.
110
+ """,
111
+ )
112
+
113
+ return bench
114
+
115
+
116
+ if __name__ == "__main__":
117
+ example_3_float_1_cat_in_2_out().report.show()
@@ -0,0 +1,124 @@
1
+ """Demonstration of benchmarking with 3 float and 2 categorical inputs producing visually distinct patterns.
2
+
3
+ Each categorical input has 2 conditions that create distinctly different surface shapes in 3D space.
4
+ """
5
+
6
+ import random
7
+ import math
8
+ import bencher as bch
9
+ import holoviews as hv
10
+
11
+ random.seed(0)
12
+
13
+
14
+ class Pattern3DModel2Cat(bch.ParametrizedSweep):
15
+ """Benchmark demonstrating 3D patterns with distinctive shapes based on 2 categorical settings."""
16
+
17
+ # Float input parameters
18
+ x_value = bch.FloatSweep(default=50, bounds=[0, 100], doc="X value parameter")
19
+ y_value = bch.FloatSweep(default=50, bounds=[0, 100], doc="Y value parameter")
20
+ z_value = bch.FloatSweep(default=50, bounds=[0, 100], doc="Z value parameter")
21
+
22
+ # Categorical input parameters - each with 2 conditions
23
+ geometry_type = bch.StringSweep(["spherical", "cylindrical"], doc="Geometry model")
24
+ scaling_type = bch.StringSweep(["linear", "quadratic"], doc="Scaling behavior")
25
+ # Removed composition_type categorical
26
+
27
+ # Output metrics
28
+ contrast = bch.ResultVar(units="ratio", doc="Secondary contrast measure")
29
+ intensity = bch.ResultVar(units="units", doc="Primary response intensity")
30
+
31
+ def __call__(self, **kwargs) -> dict:
32
+ """Generate 3D responses with distinctly different patterns based on categorical inputs."""
33
+ self.update_params_from_kwargs(**kwargs)
34
+
35
+ # Normalize inputs to [0,1]
36
+ x = self.x_value / 100
37
+ y = self.y_value / 100
38
+ z = self.z_value / 100
39
+
40
+ # Calculate radial components based on geometry_type
41
+ if self.geometry_type == "spherical":
42
+ # Spherical geometry creates radial patterns from center
43
+ r = math.sqrt(x**2 + y**2 + z**2) / math.sqrt(3)
44
+ theta = math.atan2(y, x) / (2 * math.pi) + 0.5 # normalized [0,1]
45
+ phi = math.acos(z / max(0.001, math.sqrt(x**2 + y**2 + z**2))) / math.pi
46
+ else: # cylindrical
47
+ # Cylindrical geometry creates patterns based on distance from z-axis
48
+ r = math.sqrt(x**2 + y**2) / math.sqrt(2)
49
+ theta = math.atan2(y, x) / (2 * math.pi) + 0.5
50
+ phi = z # z directly affects the height
51
+
52
+ # Apply scaling function
53
+ if self.scaling_type == "linear":
54
+ # Linear scaling creates more uniform patterns
55
+ scale_factor = 1.5 * r + 0.8 * phi + 0.5 * theta
56
+ scale_factor2 = 0.7 * r + 1.2 * phi + 0.9 * theta
57
+ else: # quadratic
58
+ # Quadratic scaling creates more concentrated effects
59
+ scale_factor = 1.5 * r**2 + 0.8 * phi**2 + 0.5 * theta
60
+ scale_factor2 = 0.7 * r**2 + 1.2 * phi**2 + 0.9 * theta
61
+
62
+ # Create wave patterns
63
+ wave1 = math.sin(5 * math.pi * r) * math.cos(4 * math.pi * theta)
64
+ wave2 = math.sin(3 * math.pi * phi) * math.sin(6 * math.pi * r * theta)
65
+
66
+ # Create interference patterns
67
+ pattern1 = math.sin(7 * math.pi * (x + y + z) / 3)
68
+ pattern2 = math.cos(9 * math.pi * x * y * z)
69
+
70
+ # Fixed to additive composition (removed composition_type categorical)
71
+ # Additive creates smoother transitions
72
+ self.intensity = 0.6 * scale_factor + 0.3 * wave1 + 0.2 * pattern1 + 0.5
73
+ self.contrast = 0.4 * scale_factor2 + 0.5 * wave2 + 0.3 * pattern2 + 0.3
74
+
75
+ # Add minimal randomness (to maintain pattern visibility)
76
+ random_factor = random.uniform(0.98, 1.02)
77
+ self.intensity *= random_factor
78
+ self.contrast *= random_factor
79
+
80
+ # Keep values in a reasonable range
81
+ self.intensity = max(0.1, min(3.0, self.intensity))
82
+ self.contrast = max(0.1, min(3.0, self.contrast))
83
+
84
+ return super().__call__(**kwargs)
85
+
86
+
87
+ def example_3_float_2_cat_in_2_out(
88
+ run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None
89
+ ) -> bch.Bench:
90
+ """Benchmark demonstrating 3D visual patterns based on 2 categorical settings.
91
+
92
+ Args:
93
+ run_cfg: Configuration for the benchmark run
94
+ report: Report to append the results to
95
+
96
+ Returns:
97
+ bch.Bench: The benchmark object
98
+ """
99
+ if run_cfg is None:
100
+ run_cfg = bch.BenchRunCfg()
101
+ run_cfg.level = 5
102
+ run_cfg.repeats = 1 # Fewer repeats for a quicker benchmark
103
+
104
+ hv.opts.defaults(hv.opts.HeatMap(cmap="plasma", width=300, height=300, colorbar=True))
105
+
106
+ bench = Pattern3DModel2Cat().to_bench(run_cfg, report)
107
+ bench.plot_sweep(
108
+ title="3D Pattern Visualization (3 Float, 2 Categorical Variables)",
109
+ description="Response patterns with distinctive shapes based on 3D coordinates and 2 categorical settings",
110
+ post_description="""
111
+ Geometry Type: Spherical (radial from center) vs Cylindrical (distance from z-axis)
112
+ Scaling Type: Linear (uniform effects) vs Quadratic (concentrated effects)
113
+
114
+ This example uses additive composition for pattern generation (fixed parameter).
115
+ 2D slices of the 3D space show visually distinctive patterns that vary based on categorical settings.
116
+ The intensity and contrast measures reveal different aspects of the underlying mathematical model.
117
+ """,
118
+ )
119
+
120
+ return bench
121
+
122
+
123
+ if __name__ == "__main__":
124
+ example_3_float_2_cat_in_2_out().report.show()
@@ -0,0 +1,129 @@
1
+ """Demonstration of benchmarking with 3 float and 3 categorical inputs producing visually distinct patterns.
2
+
3
+ Each categorical input has 2 conditions that create distinctly different surface shapes in 3D space.
4
+ """
5
+
6
+ import random
7
+ import math
8
+ import bencher as bch
9
+ import holoviews as hv
10
+
11
+ random.seed(0)
12
+
13
+
14
+ class Pattern3DModel(bch.ParametrizedSweep):
15
+ """Benchmark demonstrating 3D patterns with distinctive shapes based on categorical settings."""
16
+
17
+ # Float input parameters
18
+ x_value = bch.FloatSweep(default=50, bounds=[0, 100], doc="X value parameter")
19
+ y_value = bch.FloatSweep(default=50, bounds=[0, 100], doc="Y value parameter")
20
+ z_value = bch.FloatSweep(default=50, bounds=[0, 100], doc="Z value parameter")
21
+
22
+ # Categorical input parameters - each with 2 conditions
23
+ geometry_type = bch.StringSweep(["spherical", "cylindrical"], doc="Geometry model")
24
+ scaling_type = bch.StringSweep(["linear", "quadratic"], doc="Scaling behavior")
25
+ composition_type = bch.StringSweep(["additive", "multiplicative"], doc="How components combine")
26
+
27
+ # Output metrics
28
+ contrast = bch.ResultVar(units="ratio", doc="Secondary contrast measure")
29
+ intensity = bch.ResultVar(units="units", doc="Primary response intensity")
30
+
31
+ def __call__(self, **kwargs) -> dict:
32
+ """Generate 3D responses with distinctly different patterns based on categorical inputs."""
33
+ self.update_params_from_kwargs(**kwargs)
34
+
35
+ # Normalize inputs to [0,1]
36
+ x = self.x_value / 100
37
+ y = self.y_value / 100
38
+ z = self.z_value / 100
39
+
40
+ # Calculate radial components based on geometry_type
41
+ if self.geometry_type == "spherical":
42
+ # Spherical geometry creates radial patterns from center
43
+ r = math.sqrt(x**2 + y**2 + z**2) / math.sqrt(3)
44
+ theta = math.atan2(y, x) / (2 * math.pi) + 0.5 # normalized [0,1]
45
+ phi = math.acos(z / max(0.001, math.sqrt(x**2 + y**2 + z**2))) / math.pi
46
+ else: # cylindrical
47
+ # Cylindrical geometry creates patterns based on distance from z-axis
48
+ r = math.sqrt(x**2 + y**2) / math.sqrt(2)
49
+ theta = math.atan2(y, x) / (2 * math.pi) + 0.5
50
+ phi = z # z directly affects the height
51
+
52
+ # Apply scaling function
53
+ if self.scaling_type == "linear":
54
+ # Linear scaling creates more uniform patterns
55
+ scale_factor = 1.5 * r + 0.8 * phi + 0.5 * theta
56
+ scale_factor2 = 0.7 * r + 1.2 * phi + 0.9 * theta
57
+ else: # quadratic
58
+ # Quadratic scaling creates more concentrated effects
59
+ scale_factor = 1.5 * r**2 + 0.8 * phi**2 + 0.5 * theta
60
+ scale_factor2 = 0.7 * r**2 + 1.2 * phi**2 + 0.9 * theta
61
+
62
+ # Create wave patterns
63
+ wave1 = math.sin(5 * math.pi * r) * math.cos(4 * math.pi * theta)
64
+ wave2 = math.sin(3 * math.pi * phi) * math.sin(6 * math.pi * r * theta)
65
+
66
+ # Create interference patterns
67
+ pattern1 = math.sin(7 * math.pi * (x + y + z) / 3)
68
+ pattern2 = math.cos(9 * math.pi * x * y * z)
69
+
70
+ # Combine components based on composition_type
71
+ if self.composition_type == "additive":
72
+ # Additive creates smoother transitions
73
+ self.intensity = 0.6 * scale_factor + 0.3 * wave1 + 0.2 * pattern1 + 0.5
74
+ self.contrast = 0.4 * scale_factor2 + 0.5 * wave2 + 0.3 * pattern2 + 0.3
75
+ else: # multiplicative
76
+ # Multiplicative creates sharper boundaries
77
+ self.intensity = 0.6 * scale_factor * (1 + 0.6 * wave1) * (1 + 0.4 * pattern1)
78
+ self.contrast = 0.4 * scale_factor2 * (1 + 0.8 * wave2) * (1 + 0.5 * pattern2)
79
+
80
+ # Add minimal randomness (to maintain pattern visibility)
81
+ random_factor = random.uniform(0.98, 1.02)
82
+ self.intensity *= random_factor
83
+ self.contrast *= random_factor
84
+
85
+ # Keep values in a reasonable range
86
+ self.intensity = max(0.1, min(3.0, self.intensity))
87
+ self.contrast = max(0.1, min(3.0, self.contrast))
88
+
89
+ return super().__call__(**kwargs)
90
+
91
+
92
+ def example_3_float_3_cat_in_2_out(
93
+ run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None
94
+ ) -> bch.Bench:
95
+ """Benchmark demonstrating 3D visual patterns based on categorical settings.
96
+
97
+ Args:
98
+ run_cfg: Configuration for the benchmark run
99
+ report: Report to append the results to
100
+
101
+ Returns:
102
+ bch.Bench: The benchmark object
103
+ """
104
+ if run_cfg is None:
105
+ run_cfg = bch.BenchRunCfg()
106
+ run_cfg.level = 5
107
+ run_cfg.repeats = 1 # Fewer repeats for a quicker benchmark
108
+
109
+ hv.opts.defaults(hv.opts.HeatMap(cmap="plasma", width=300, height=300, colorbar=True))
110
+
111
+ bench = Pattern3DModel().to_bench(run_cfg, report)
112
+ bench.plot_sweep(
113
+ title="3D Pattern Visualization (3 Float, 3 Categorical Variables)",
114
+ description="Response patterns with distinctive shapes based on 3D coordinates and categorical settings",
115
+ post_description="""
116
+ Geometry Type: Spherical (radial from center) vs Cylindrical (distance from z-axis)
117
+ Scaling Type: Linear (uniform effects) vs Quadratic (concentrated effects)
118
+ Composition Type: Additive (smooth transitions) vs Multiplicative (sharp boundaries)
119
+
120
+ 2D slices of the 3D space show visually distinctive patterns that vary based on categorical settings.
121
+ The intensity and contrast measures reveal different aspects of the underlying mathematical model.
122
+ """,
123
+ )
124
+
125
+ return bench
126
+
127
+
128
+ if __name__ == "__main__":
129
+ example_3_float_3_cat_in_2_out().report.show()