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.
Files changed (93) hide show
  1. CHANGELOG.md +10 -0
  2. bencher/__init__.py +20 -2
  3. bencher/bench_cfg.py +265 -61
  4. bencher/bench_report.py +2 -2
  5. bencher/bench_runner.py +96 -10
  6. bencher/bencher.py +421 -89
  7. bencher/caching.py +1 -4
  8. bencher/class_enum.py +70 -7
  9. bencher/example/example_composable_container_image.py +60 -0
  10. bencher/example/example_composable_container_video.py +49 -0
  11. bencher/example/example_dataframe.py +2 -2
  12. bencher/example/example_image.py +17 -21
  13. bencher/example/example_image1.py +16 -20
  14. bencher/example/example_levels.py +17 -173
  15. bencher/example/example_pareto.py +107 -31
  16. bencher/example/example_rerun2.py +1 -1
  17. bencher/example/example_simple_bool.py +2 -2
  18. bencher/example/example_simple_float2d.py +6 -1
  19. bencher/example/example_video.py +35 -17
  20. bencher/example/experimental/example_hvplot_explorer.py +3 -4
  21. bencher/example/inputs_0D/example_0_in_1_out.py +25 -15
  22. bencher/example/inputs_0D/example_0_in_2_out.py +12 -3
  23. bencher/example/inputs_0_float/example_0_cat_in_2_out.py +88 -0
  24. bencher/example/inputs_0_float/example_1_cat_in_2_out.py +98 -0
  25. bencher/example/inputs_0_float/example_2_cat_in_2_out.py +107 -0
  26. bencher/example/inputs_0_float/example_3_cat_in_2_out.py +111 -0
  27. bencher/example/inputs_1D/example1d_common.py +48 -12
  28. bencher/example/inputs_1D/example_0_float_1_cat.py +33 -0
  29. bencher/example/inputs_1D/example_1_cat_in_2_out_repeats.py +68 -0
  30. bencher/example/inputs_1D/example_1_float_2_cat_repeats.py +15 -0
  31. bencher/example/inputs_1D/example_1_int_in_1_out.py +98 -0
  32. bencher/example/inputs_1D/example_1_int_in_2_out.py +101 -0
  33. bencher/example/inputs_1D/example_1_int_in_2_out_repeats.py +99 -0
  34. bencher/example/inputs_1_float/example_1_float_0_cat_in_2_out.py +117 -0
  35. bencher/example/inputs_1_float/example_1_float_1_cat_in_2_out.py +124 -0
  36. bencher/example/inputs_1_float/example_1_float_2_cat_in_2_out.py +132 -0
  37. bencher/example/inputs_1_float/example_1_float_3_cat_in_2_out.py +140 -0
  38. bencher/example/inputs_2D/example_2_cat_in_4_out_repeats.py +104 -0
  39. bencher/example/inputs_2_float/example_2_float_0_cat_in_2_out.py +98 -0
  40. bencher/example/inputs_2_float/example_2_float_1_cat_in_2_out.py +112 -0
  41. bencher/example/inputs_2_float/example_2_float_2_cat_in_2_out.py +122 -0
  42. bencher/example/inputs_2_float/example_2_float_3_cat_in_2_out.py +138 -0
  43. bencher/example/inputs_3_float/example_3_float_0_cat_in_2_out.py +111 -0
  44. bencher/example/inputs_3_float/example_3_float_1_cat_in_2_out.py +117 -0
  45. bencher/example/inputs_3_float/example_3_float_2_cat_in_2_out.py +124 -0
  46. bencher/example/inputs_3_float/example_3_float_3_cat_in_2_out.py +129 -0
  47. bencher/example/meta/generate_examples.py +124 -7
  48. bencher/example/meta/generate_meta.py +88 -40
  49. bencher/job.py +175 -12
  50. bencher/plotting/plot_filter.py +52 -17
  51. bencher/results/bench_result.py +119 -26
  52. bencher/results/bench_result_base.py +119 -10
  53. bencher/results/composable_container/composable_container_video.py +39 -12
  54. bencher/results/dataset_result.py +6 -200
  55. bencher/results/explorer_result.py +23 -0
  56. bencher/results/{hvplot_result.py → histogram_result.py} +3 -18
  57. bencher/results/holoview_results/__init__.py +0 -0
  58. bencher/results/holoview_results/bar_result.py +79 -0
  59. bencher/results/holoview_results/curve_result.py +110 -0
  60. bencher/results/holoview_results/distribution_result/__init__.py +0 -0
  61. bencher/results/holoview_results/distribution_result/box_whisker_result.py +73 -0
  62. bencher/results/holoview_results/distribution_result/distribution_result.py +109 -0
  63. bencher/results/holoview_results/distribution_result/scatter_jitter_result.py +92 -0
  64. bencher/results/holoview_results/distribution_result/violin_result.py +70 -0
  65. bencher/results/holoview_results/heatmap_result.py +319 -0
  66. bencher/results/holoview_results/holoview_result.py +346 -0
  67. bencher/results/holoview_results/line_result.py +240 -0
  68. bencher/results/holoview_results/scatter_result.py +107 -0
  69. bencher/results/holoview_results/surface_result.py +158 -0
  70. bencher/results/holoview_results/table_result.py +14 -0
  71. bencher/results/holoview_results/tabulator_result.py +20 -0
  72. bencher/results/laxtex_result.py +42 -35
  73. bencher/results/optuna_result.py +30 -115
  74. bencher/results/video_controls.py +38 -0
  75. bencher/results/video_result.py +39 -36
  76. bencher/results/video_summary.py +2 -2
  77. bencher/results/{plotly_result.py → volume_result.py} +29 -8
  78. bencher/utils.py +176 -30
  79. bencher/variables/inputs.py +122 -15
  80. bencher/video_writer.py +38 -2
  81. bencher/worker_job.py +34 -7
  82. {holobench-1.40.1.dist-info → holobench-1.42.0.dist-info}/METADATA +21 -25
  83. holobench-1.42.0.dist-info/RECORD +147 -0
  84. bencher/example/example_composable_container.py +0 -106
  85. bencher/example/example_levels2.py +0 -37
  86. bencher/example/inputs_1D/example_1_in_1_out.py +0 -62
  87. bencher/example/inputs_1D/example_1_in_2_out.py +0 -63
  88. bencher/example/inputs_1D/example_1_in_2_out_repeats.py +0 -61
  89. bencher/results/holoview_result.py +0 -787
  90. bencher/results/panel_result.py +0 -41
  91. holobench-1.40.1.dist-info/RECORD +0 -111
  92. {holobench-1.40.1.dist-info → holobench-1.42.0.dist-info}/WHEEL +0 -0
  93. {holobench-1.40.1.dist-info → holobench-1.42.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,104 @@
1
+ """This file demonstrates benchmarking with categorical inputs and multiple outputs with repeats.
2
+
3
+ It simulates comparing programming languages and development environments, measuring
4
+ performance and developer productivity metrics.
5
+ """
6
+
7
+ import random
8
+ import bencher as bch
9
+
10
+ random.seed(42) # Fixed seed for reproducibility
11
+
12
+
13
+ class ProgrammingBenchmark(bch.ParametrizedSweep):
14
+ """Benchmark class comparing programming languages and development environments."""
15
+
16
+ language = bch.StringSweep(
17
+ ["Python", "JavaScript", "Rust", "Go"], doc="Programming language being benchmarked"
18
+ )
19
+ environment = bch.StringSweep(
20
+ ["Development", "Testing", "Production"], doc="Environment configuration"
21
+ )
22
+
23
+ execution_time = bch.ResultVar(units="ms", doc="Execution time in milliseconds")
24
+ memory_usage = bch.ResultVar(units="MB", doc="Memory usage in megabytes")
25
+
26
+ def __call__(self, **kwargs) -> dict:
27
+ """Execute the parameter sweep for the given inputs.
28
+
29
+ Args:
30
+ **kwargs: Additional parameters to update before executing
31
+
32
+ Returns:
33
+ dict: Dictionary containing the outputs of the parameter sweep
34
+ """
35
+ self.update_params_from_kwargs(**kwargs)
36
+
37
+ # Base values that will be modified by language and environment
38
+ base_execution = 0
39
+ base_memory = 0
40
+
41
+ # Different languages have different performance characteristics
42
+ if self.language == "Python":
43
+ base_execution = 150
44
+ base_memory = 80
45
+ elif self.language == "JavaScript":
46
+ base_execution = 100
47
+ base_memory = 60
48
+ elif self.language == "Rust":
49
+ base_execution = 20
50
+ base_memory = 15
51
+ elif self.language == "Go":
52
+ base_execution = 40
53
+ base_memory = 30
54
+
55
+ # Environment affects performance
56
+ if self.environment == "Development":
57
+ # Dev environments have debugging overhead
58
+ env_exec_modifier = 1.5
59
+ env_mem_modifier = 1.3
60
+ elif self.environment == "Testing":
61
+ # Testing has moderate overhead
62
+ env_exec_modifier = 1.2
63
+ env_mem_modifier = 1.1
64
+ else: # Production
65
+ # Production is optimized
66
+ env_exec_modifier = 1.0
67
+ env_mem_modifier = 1.0
68
+
69
+ # Calculate final values with some randomness
70
+ self.execution_time = base_execution * env_exec_modifier * random.uniform(0.9, 1.1)
71
+ self.memory_usage = base_memory * env_mem_modifier * random.uniform(0.95, 1.05)
72
+
73
+ return super().__call__(**kwargs)
74
+
75
+
76
+ def example_2_cat_in_4_out_repeats(
77
+ run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None
78
+ ) -> bch.Bench:
79
+ """This example compares performance metrics across programming languages and environments.
80
+
81
+ It demonstrates how to sample categorical variables with multiple repeats
82
+ and plot the results of two output variables.
83
+
84
+ Args:
85
+ run_cfg: Configuration for the benchmark run
86
+ report: Report to append the results to
87
+
88
+ Returns:
89
+ bch.Bench: The benchmark object
90
+ """
91
+
92
+ if run_cfg is None:
93
+ run_cfg = bch.BenchRunCfg()
94
+ run_cfg.repeats = 15 # Run multiple times to get statistical significance
95
+ bench = ProgrammingBenchmark().to_bench(run_cfg, report)
96
+ bench.plot_sweep(
97
+ title="Programming Language and Environment Performance Metrics",
98
+ description="Comparing execution time and memory usage across different programming languages and environments",
99
+ )
100
+ return bench
101
+
102
+
103
+ if __name__ == "__main__":
104
+ example_2_cat_in_4_out_repeats().report.show()
@@ -0,0 +1,98 @@
1
+ """Demonstration of benchmarking with 2 float inputs and 0 categorical inputs producing a distinct pattern.
2
+
3
+ The two float inputs create a visually distinctive surface shape.
4
+ """
5
+
6
+ import random
7
+ import math
8
+ import bencher as bch
9
+
10
+ random.seed(0)
11
+
12
+
13
+ class Pattern0CatBenchmark(bch.ParametrizedSweep):
14
+ """Benchmark demonstrating patterns with two float inputs and no categorical variables."""
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
+ # No categorical input parameters
21
+
22
+ # Output metrics
23
+ response_a = bch.ResultVar(units="units", doc="Response variable A")
24
+ response_b = bch.ResultVar(units="units", doc="Response variable B")
25
+
26
+ def __call__(self, **kwargs) -> dict:
27
+ """Generate responses with a distinctive pattern based on x and y values."""
28
+ self.update_params_from_kwargs(**kwargs)
29
+
30
+ # Normalize inputs to [0,1]
31
+ x = self.x_value / 100
32
+ y = self.y_value / 100
33
+
34
+ # Using fixed "linear" pattern type
35
+ base_a = 2 * x + 3 * y
36
+ base_b = 3 * x - y
37
+
38
+ # Using fixed "symmetric" symmetry type
39
+ sym_a = (x + y) ** 2
40
+ sym_b = (x + y) * abs(x - y)
41
+
42
+ # Using fixed "smooth" feature type
43
+ feat_a = math.sin(3 * math.pi * x) * math.sin(3 * math.pi * y)
44
+ feat_b = math.cos(3 * math.pi * x) * math.cos(3 * math.pi * y)
45
+
46
+ # Fixed weights for valley pattern
47
+ w_a = [1, 2, 0.5]
48
+ w_b = [1, 1.5, 0.3]
49
+
50
+ # Calculate final responses with weights
51
+ self.response_a = w_a[0] * base_a + w_a[1] * sym_a + w_a[2] * feat_a
52
+ self.response_b = w_b[0] * base_b + w_b[1] * sym_b + w_b[2] * feat_b
53
+
54
+ # Add minimal randomness (to maintain pattern visibility)
55
+ random_factor = random.uniform(0.98, 1.02)
56
+ self.response_a *= random_factor
57
+ self.response_b *= random_factor
58
+
59
+ return super().__call__(**kwargs)
60
+
61
+
62
+ def example_2_float_0_cat_in_2_out(
63
+ run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None
64
+ ) -> bch.Bench:
65
+ """Benchmark demonstrating a surface pattern based solely on float parameters.
66
+
67
+ This example is simplified from the 1-category version by fixing all categorical
68
+ settings to create a valley pattern.
69
+
70
+ Args:
71
+ run_cfg: Configuration for the benchmark run
72
+ report: Report to append the results to
73
+
74
+ Returns:
75
+ bch.Bench: The benchmark object
76
+ """
77
+ if run_cfg is None:
78
+ run_cfg = bch.BenchRunCfg()
79
+ run_cfg.repeats = 3 # Fewer repeats for a quicker benchmark
80
+
81
+ bench = Pattern0CatBenchmark().to_bench(run_cfg, report)
82
+ bench.plot_sweep(
83
+ title="Pattern Visualization (2 Float, 0 Categorical Variables)",
84
+ description="Response pattern with a valley shape based on x and y values",
85
+ post_description="""
86
+ This example demonstrates a surface pattern created using only two float inputs
87
+ (x_value and y_value) with no categorical variables.
88
+
89
+ The pattern showcases a 'valley' shape that exhibits different characteristics
90
+ across the range of x and y values. This simplified example uses fixed settings
91
+ equivalent to a linear pattern with symmetric properties and smooth features.
92
+ """,
93
+ )
94
+ return bench
95
+
96
+
97
+ if __name__ == "__main__":
98
+ example_2_float_0_cat_in_2_out().report.show()
@@ -0,0 +1,112 @@
1
+ """Demonstration of benchmarking with 2 float and 1 categorical input producing visually distinct patterns.
2
+
3
+ The 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 Pattern1CatBenchmark(bch.ParametrizedSweep):
14
+ """Benchmark demonstrating patterns with distinctive shapes based on pattern type."""
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 parameter - with 2 conditions
21
+ pattern_type = bch.StringSweep(["linear", "exponential"], doc="Pattern relationship")
22
+ # symmetry_type and feature_type removed
23
+
24
+ # Output metrics
25
+ response_a = bch.ResultVar(units="units", doc="Response variable A")
26
+ response_b = bch.ResultVar(units="units", doc="Response variable B")
27
+
28
+ def __call__(self, **kwargs) -> dict:
29
+ """Generate responses with distinctly different patterns based on pattern type."""
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
+
36
+ # Set base patterns based on pattern_type
37
+ if self.pattern_type == "linear":
38
+ base_a = 2 * x + 3 * y
39
+ base_b = 3 * x - y
40
+ else: # exponential
41
+ base_a = math.exp(2 * x) * math.exp(y) / math.exp(3)
42
+ base_b = math.exp(x) * math.exp(2 * y) / math.exp(3)
43
+
44
+ # Using fixed "symmetric" symmetry type
45
+ sym_a = (x + y) ** 2
46
+ sym_b = (x + y) * abs(x - y)
47
+
48
+ # Using fixed "smooth" feature type
49
+ feat_a = math.sin(3 * math.pi * x) * math.sin(3 * math.pi * y)
50
+ feat_b = math.cos(3 * math.pi * x) * math.cos(3 * math.pi * y)
51
+
52
+ # Simplified weights dictionary for 1 categorical variable
53
+ weights = {
54
+ "linear": ([1, 2, 0.5], [1, 1.5, 0.3]), # Valley pattern
55
+ "exponential": ([1, 1, 0.3], [1, 0.8, 0.4]), # Corner peak with ripples
56
+ }
57
+
58
+ # Get the weights for the current pattern type
59
+ w_a, w_b = weights[self.pattern_type]
60
+
61
+ # Calculate final responses with weights
62
+ if self.pattern_type == "linear":
63
+ self.response_a = w_a[0] * base_a + w_a[1] * sym_a + w_a[2] * feat_a
64
+ self.response_b = w_b[0] * base_b + w_b[1] * sym_b + w_b[2] * feat_b
65
+ else: # exponential - multiplicative relationship
66
+ self.response_a = base_a * (1 + w_a[1] * sym_a) * (1 + w_a[2] * feat_a)
67
+ self.response_b = base_b * (1 + w_b[1] * sym_b) * (1 + w_b[2] * feat_b)
68
+
69
+ # Add minimal randomness (to maintain pattern visibility)
70
+ random_factor = random.uniform(0.98, 1.02)
71
+ self.response_a *= random_factor
72
+ self.response_b *= random_factor
73
+
74
+ return super().__call__(**kwargs)
75
+
76
+
77
+ def example_2_float_1_cat_in_2_out(
78
+ run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None
79
+ ) -> bch.Bench:
80
+ """Benchmark demonstrating visually distinct patterns based on pattern type.
81
+
82
+ This example is simplified from the 2-category version by fixing the symmetry_type
83
+ to "symmetric" and feature_type to "smooth".
84
+
85
+ Args:
86
+ run_cfg: Configuration for the benchmark run
87
+ report: Report to append the results to
88
+
89
+ Returns:
90
+ bch.Bench: The benchmark object
91
+ """
92
+ if run_cfg is None:
93
+ run_cfg = bch.BenchRunCfg()
94
+ run_cfg.repeats = 3 # Fewer repeats for a quicker benchmark
95
+
96
+ bench = Pattern1CatBenchmark().to_bench(run_cfg, report)
97
+ bench.plot_sweep(
98
+ title="Pattern Visualization (2 Float, 1 Categorical Variable)",
99
+ description="Response patterns with distinctive shapes based on pattern type",
100
+ post_description="""
101
+ Pattern Type: Linear (diagonal gradients) vs Exponential (corner-concentrated)
102
+
103
+ Each pattern type produces a unique surface shape that remains visually distinctive
104
+ even with auto-scaling of the color maps. This example uses fixed "symmetric" symmetry
105
+ and "smooth" feature settings.
106
+ """,
107
+ )
108
+ return bench
109
+
110
+
111
+ if __name__ == "__main__":
112
+ example_2_float_1_cat_in_2_out().report.show()
@@ -0,0 +1,122 @@
1
+ """Demonstration of benchmarking with 2 float and 2 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 Pattern2CatBenchmark(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 removed
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
+ # Using fixed "smooth" feature type
54
+ feat_a = math.sin(3 * math.pi * x) * math.sin(3 * math.pi * y)
55
+ feat_b = math.cos(3 * math.pi * x) * math.cos(3 * math.pi * y)
56
+
57
+ # Simplified weights dictionary for 2 categorical variables
58
+ weights = {
59
+ "linear": {
60
+ "symmetric": ([1, 2, 0.5], [1, 1.5, 0.3]), # Valley pattern
61
+ "asymmetric": ([1, 1.8, 0.7], [1, 1.2, 0.9]), # Tilted plane with waves
62
+ },
63
+ "exponential": {
64
+ "symmetric": ([1, 1, 0.3], [1, 0.8, 0.4]), # Corner peak with ripples
65
+ "asymmetric": ([1, 1.5, 0.4], [1, 1.8, 0.2]), # Curved gradient
66
+ },
67
+ }
68
+
69
+ # Get the weights for the current combination
70
+ w_a, w_b = weights[self.pattern_type][self.symmetry_type]
71
+
72
+ # Calculate final responses with weights
73
+ if self.pattern_type == "linear":
74
+ self.response_a = w_a[0] * base_a + w_a[1] * sym_a + w_a[2] * feat_a
75
+ self.response_b = w_b[0] * base_b + w_b[1] * sym_b + w_b[2] * feat_b
76
+ else: # exponential - multiplicative relationship
77
+ self.response_a = base_a * (1 + w_a[1] * sym_a) * (1 + w_a[2] * feat_a)
78
+ self.response_b = base_b * (1 + w_b[1] * sym_b) * (1 + w_b[2] * feat_b)
79
+
80
+ # Add minimal randomness (to maintain pattern visibility)
81
+ random_factor = random.uniform(0.98, 1.02)
82
+ self.response_a *= random_factor
83
+ self.response_b *= random_factor
84
+
85
+ return super().__call__(**kwargs)
86
+
87
+
88
+ def example_2_float_2_cat_in_2_out(
89
+ run_cfg: bch.BenchRunCfg = None, report: bch.BenchReport = None
90
+ ) -> bch.Bench:
91
+ """Benchmark demonstrating visually distinct patterns based on 2 categorical settings.
92
+
93
+ This example is simplified from the 3-category version by fixing the feature_type to "smooth".
94
+
95
+ Args:
96
+ run_cfg: Configuration for the benchmark run
97
+ report: Report to append the results to
98
+
99
+ Returns:
100
+ bch.Bench: The benchmark object
101
+ """
102
+ if run_cfg is None:
103
+ run_cfg = bch.BenchRunCfg()
104
+ run_cfg.repeats = 3 # Fewer repeats for a quicker benchmark
105
+
106
+ bench = Pattern2CatBenchmark().to_bench(run_cfg, report)
107
+ bench.plot_sweep(
108
+ title="Pattern Visualization (2 Float, 2 Categorical Variables)",
109
+ description="Response patterns with distinctive shapes based on pattern and symmetry types",
110
+ post_description="""
111
+ Pattern Type: Linear (diagonal gradients) vs Exponential (corner-concentrated)
112
+ Symmetry Type: Symmetric (x/y similarity) vs Asymmetric (x/y difference)
113
+
114
+ Each combination produces a unique pattern shape that remains visually distinctive
115
+ even with auto-scaling of the color maps. Feature type is fixed to "smooth" in this example.
116
+ """,
117
+ )
118
+ return bench
119
+
120
+
121
+ if __name__ == "__main__":
122
+ example_2_float_2_cat_in_2_out().report.show()
@@ -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()