2929@pytest .mark .skipif (not HAS_NUMBA , reason = "Numba not available" )
3030class TestOptimizedHistogram :
3131 """Test the optimized histogram implementation."""
32-
32+
3333 def test_correctness_uniform (self ):
3434 """Test correctness with uniform distribution."""
3535 np .random .seed (42 )
3636 data = np .random .uniform (0 , 15 , 10000 ).astype (np .float64 )
37-
37+
3838 np_hist , np_edges = np .histogram (data , bins = 75 , range = (0.0 , 15.0 ))
39- opt_hist , opt_edges = optimized_histogram (data , bins = 75 , range = (0.0 , 15.0 ))
40-
39+ opt_hist , opt_edges = optimized_histogram (
40+ data , bins = 75 , range = (0.0 , 15.0 )
41+ )
42+
4143 assert_allclose (np_hist , opt_hist , rtol = 1e-14 , atol = 1 )
4244 assert_allclose (np_edges , opt_edges , rtol = 1e-14 )
43-
45+
4446 def test_correctness_normal (self ):
4547 """Test correctness with normal distribution."""
4648 np .random .seed (42 )
4749 data = np .random .normal (7.5 , 2 , 10000 ).clip (0 , 15 ).astype (np .float64 )
48-
50+
4951 np_hist , np_edges = np .histogram (data , bins = 75 , range = (0.0 , 15.0 ))
50- opt_hist , opt_edges = optimized_histogram (data , bins = 75 , range = (0.0 , 15.0 ))
51-
52+ opt_hist , opt_edges = optimized_histogram (
53+ data , bins = 75 , range = (0.0 , 15.0 )
54+ )
55+
5256 assert_allclose (np_hist , opt_hist , rtol = 1e-14 , atol = 1 )
5357 assert_allclose (np_edges , opt_edges , rtol = 1e-14 )
54-
58+
5559 def test_edge_cases_zeros (self ):
5660 """Test with all zeros."""
5761 data = np .zeros (1000 , dtype = np .float64 )
58-
62+
5963 np_hist , np_edges = np .histogram (data , bins = 75 , range = (0.0 , 15.0 ))
60- opt_hist , opt_edges = optimized_histogram (data , bins = 75 , range = (0.0 , 15.0 ))
61-
64+ opt_hist , opt_edges = optimized_histogram (
65+ data , bins = 75 , range = (0.0 , 15.0 )
66+ )
67+
6268 assert_allclose (np_hist , opt_hist , rtol = 1e-14 , atol = 1 )
6369 assert_allclose (np_edges , opt_edges , rtol = 1e-14 )
64-
70+
6571 def test_edge_cases_max_values (self ):
6672 """Test with values at maximum range."""
6773 data = np .ones (1000 , dtype = np .float64 ) * 14.999
68-
74+
6975 np_hist , np_edges = np .histogram (data , bins = 75 , range = (0.0 , 15.0 ))
70- opt_hist , opt_edges = optimized_histogram (data , bins = 75 , range = (0.0 , 15.0 ))
71-
76+ opt_hist , opt_edges = optimized_histogram (
77+ data , bins = 75 , range = (0.0 , 15.0 )
78+ )
79+
7280 assert_allclose (np_hist , opt_hist , rtol = 1e-14 , atol = 1 )
7381 assert_allclose (np_edges , opt_edges , rtol = 1e-14 )
74-
82+
7583 def test_boundary_values (self ):
7684 """Test with boundary values."""
7785 data = np .array ([0.0 , 14.999 , 15.0 , 7.5 ] * 250 , dtype = np .float64 )
78-
86+
7987 np_hist , np_edges = np .histogram (data , bins = 75 , range = (0.0 , 15.0 ))
80- opt_hist , opt_edges = optimized_histogram (data , bins = 75 , range = (0.0 , 15.0 ))
81-
88+ opt_hist , opt_edges = optimized_histogram (
89+ data , bins = 75 , range = (0.0 , 15.0 )
90+ )
91+
8292 # Allow for small differences at boundaries due to floating point precision
8393 assert_allclose (np_hist , opt_hist , rtol = 1e-14 , atol = 1 )
8494 assert_allclose (np_edges , opt_edges , rtol = 1e-14 )
85-
95+
8696 def test_bin_edges_values (self ):
8797 """Test with values exactly at bin edges."""
8898 data = np .linspace (0 , 15 , 1001 , dtype = np .float64 )
89-
99+
90100 np_hist , np_edges = np .histogram (data , bins = 75 , range = (0.0 , 15.0 ))
91- opt_hist , opt_edges = optimized_histogram (data , bins = 75 , range = (0.0 , 15.0 ))
92-
101+ opt_hist , opt_edges = optimized_histogram (
102+ data , bins = 75 , range = (0.0 , 15.0 )
103+ )
104+
93105 # Allow for small differences at boundaries due to floating point precision
94106 assert_allclose (np_hist , opt_hist , rtol = 1e-14 , atol = 1 )
95107 assert_allclose (np_edges , opt_edges , rtol = 1e-14 )
96-
108+
97109 def test_serial_parallel_consistency (self ):
98110 """Test that serial and parallel versions produce identical results."""
99111 np .random .seed (42 )
100112 data = np .random .random (100000 ).astype (np .float64 ) * 15.0
101-
113+
102114 hist_serial , edges_serial = optimized_histogram (
103115 data , bins = 75 , range = (0.0 , 15.0 ), use_parallel = False
104116 )
105117 hist_parallel , edges_parallel = optimized_histogram (
106118 data , bins = 75 , range = (0.0 , 15.0 ), use_parallel = True
107119 )
108-
120+
109121 assert_allclose (hist_serial , hist_parallel , rtol = 1e-14 , atol = 1 )
110122 assert_array_equal (edges_serial , edges_parallel )
111-
123+
112124 def test_different_bin_counts (self ):
113125 """Test with different bin counts."""
114126 np .random .seed (42 )
115127 data = np .random .random (10000 ).astype (np .float64 ) * 15.0
116-
128+
117129 for bins in [10 , 50 , 100 , 200 ]:
118- np_hist , np_edges = np .histogram (data , bins = bins , range = (0.0 , 15.0 ))
119- opt_hist , opt_edges = optimized_histogram (data , bins = bins , range = (0.0 , 15.0 ))
120-
121- assert_allclose (np_hist , opt_hist , rtol = 1e-14 , atol = 1 ,
122- err_msg = f"Failed for bins={ bins } " )
123- assert_allclose (np_edges , opt_edges , rtol = 1e-14 ,
124- err_msg = f"Failed for bins={ bins } " )
125-
130+ np_hist , np_edges = np .histogram (
131+ data , bins = bins , range = (0.0 , 15.0 )
132+ )
133+ opt_hist , opt_edges = optimized_histogram (
134+ data , bins = bins , range = (0.0 , 15.0 )
135+ )
136+
137+ assert_allclose (
138+ np_hist ,
139+ opt_hist ,
140+ rtol = 1e-14 ,
141+ atol = 1 ,
142+ err_msg = f"Failed for bins={ bins } " ,
143+ )
144+ assert_allclose (
145+ np_edges ,
146+ opt_edges ,
147+ rtol = 1e-14 ,
148+ err_msg = f"Failed for bins={ bins } " ,
149+ )
150+
126151 def test_different_ranges (self ):
127152 """Test with different histogram ranges."""
128153 np .random .seed (42 )
129154 data = np .random .random (10000 ).astype (np .float64 ) * 20.0
130-
155+
131156 for range_val in [(0.0 , 10.0 ), (0.0 , 20.0 ), (5.0 , 15.0 )]:
132157 np_hist , np_edges = np .histogram (data , bins = 75 , range = range_val )
133- opt_hist , opt_edges = optimized_histogram (data , bins = 75 , range = range_val )
134-
135- assert_allclose (np_hist , opt_hist , rtol = 1e-14 , atol = 1 ,
136- err_msg = f"Failed for range={ range_val } " )
137- assert_allclose (np_edges , opt_edges , rtol = 1e-14 ,
138- err_msg = f"Failed for range={ range_val } " )
139-
158+ opt_hist , opt_edges = optimized_histogram (
159+ data , bins = 75 , range = range_val
160+ )
161+
162+ assert_allclose (
163+ np_hist ,
164+ opt_hist ,
165+ rtol = 1e-14 ,
166+ atol = 1 ,
167+ err_msg = f"Failed for range={ range_val } " ,
168+ )
169+ assert_allclose (
170+ np_edges ,
171+ opt_edges ,
172+ rtol = 1e-14 ,
173+ err_msg = f"Failed for range={ range_val } " ,
174+ )
175+
140176 def test_non_contiguous_array (self ):
141177 """Test with non-contiguous array."""
142178 np .random .seed (42 )
143179 # Create a non-contiguous array by slicing
144180 data = np .random .random (20000 ).astype (np .float64 ) * 15.0
145181 data_non_contig = data [::2 ] # Every other element
146-
147- assert not data_non_contig .flags ['C_CONTIGUOUS' ]
148-
149- np_hist , np_edges = np .histogram (data_non_contig , bins = 75 , range = (0.0 , 15.0 ))
150- opt_hist , opt_edges = optimized_histogram (data_non_contig , bins = 75 , range = (0.0 , 15.0 ))
151-
182+
183+ assert not data_non_contig .flags ["C_CONTIGUOUS" ]
184+
185+ np_hist , np_edges = np .histogram (
186+ data_non_contig , bins = 75 , range = (0.0 , 15.0 )
187+ )
188+ opt_hist , opt_edges = optimized_histogram (
189+ data_non_contig , bins = 75 , range = (0.0 , 15.0 )
190+ )
191+
152192 assert_allclose (np_hist , opt_hist , rtol = 1e-14 , atol = 1 )
153193 assert_allclose (np_edges , opt_edges , rtol = 1e-14 )
154-
194+
155195 @pytest .mark .parametrize ("size" , [100 , 1000 , 10000 , 100000 ])
156196 def test_scaling (self , size ):
157197 """Test correctness at different scales."""
158198 np .random .seed (42 )
159199 data = np .random .random (size ).astype (np .float64 ) * 15.0
160-
200+
161201 np_hist , np_edges = np .histogram (data , bins = 75 , range = (0.0 , 15.0 ))
162- opt_hist , opt_edges = optimized_histogram (data , bins = 75 , range = (0.0 , 15.0 ))
163-
164- assert_allclose (np_hist , opt_hist , rtol = 1e-14 , atol = 1 ,
165- err_msg = f"Failed for size={ size } " )
166- assert_allclose (np_edges , opt_edges , rtol = 1e-14 ,
167- err_msg = f"Failed for size={ size } " )
202+ opt_hist , opt_edges = optimized_histogram (
203+ data , bins = 75 , range = (0.0 , 15.0 )
204+ )
205+
206+ assert_allclose (
207+ np_hist ,
208+ opt_hist ,
209+ rtol = 1e-14 ,
210+ atol = 1 ,
211+ err_msg = f"Failed for size={ size } " ,
212+ )
213+ assert_allclose (
214+ np_edges , opt_edges , rtol = 1e-14 , err_msg = f"Failed for size={ size } "
215+ )
168216
169217
170- @pytest .mark .skipif (HAS_NUMBA , reason = "Testing fallback when Numba not available" )
218+ @pytest .mark .skipif (
219+ HAS_NUMBA , reason = "Testing fallback when Numba not available"
220+ )
171221class TestHistogramFallback :
172222 """Test that the module falls back gracefully when Numba is not available."""
173-
223+
174224 def test_import_without_numba (self ):
175225 """Test that import works without Numba."""
176226 # This test will only run if Numba is not installed
177227 # The import should still work but HAS_NUMBA should be False
178228 from MDAnalysis .lib import histogram_opt
179- assert not histogram_opt .HAS_NUMBA
229+
230+ assert not histogram_opt .HAS_NUMBA
0 commit comments