@@ -115,15 +115,54 @@ def test_calculate_squared_distance():
115115 npt .assert_almost_equal (ref , comp , decimal = 14 )
116116
117117
118- def test_snippets ():
118+ @pytest .mark .filterwarnings ("ignore" , category = NumbaPerformanceWarning )
119+ @patch ("stumpy.config.STUMPY_THREADS_PER_BLOCK" , TEST_THREADS_PER_BLOCK )
120+ def test_distance_symmetry_property_in_gpu ():
121+ if not cuda .is_available (): # pragma: no cover
122+ pytest .skip ("Skipping Tests No GPUs Available" )
123+
124+ # This test function raises an error if the distance between a subsequence
125+ # and another one does not satisfy the symmetry property.
126+ seed = 332
127+ np .random .seed (seed )
128+ T = np .random .uniform (- 1000.0 , 1000.0 , [64 ])
129+ m = 3
130+
131+ i , j = 2 , 10
132+ # M_T, Σ_T = core.compute_mean_std(T, m)
133+ # Σ_T[i] is `650.912209452633`
134+ # Σ_T[j] is `722.0717285148525`
135+
136+ # This test raises an error if arithmetic operation in ...
137+ # ... `gpu_stump._compute_and_update_PI_kernel` does not
138+ # generates the same result if values of variable for mean and std
139+ # are swapped.
140+
141+ T_A = T [i : i + m ]
142+ T_B = T [j : j + m ]
143+
144+ mp_AB = stumpy .gpu_stump (T_A , m , T_B )
145+ mp_BA = stumpy .gpu_stump (T_B , m , T_A )
146+
147+ d_ij = mp_AB [0 , 0 ]
148+ d_ji = mp_BA [0 , 0 ]
149+
150+ comp = d_ij - d_ji
151+ ref = 0.0
152+
153+ npt .assert_almost_equal (comp , ref , decimal = 15 )
154+
155+
156+ def test_snippets_rare_case_1 ():
119157 # This test function raises an error if there is a considerable loss of precision
120158 # that violates the symmetry property of a distance measure.
159+ seed = 332
160+ np .random .seed (seed )
161+ T = np .random .uniform (- 1000.0 , 1000.0 , 64 )
162+
121163 m = 10
122164 k = 3
123165 s = 3
124- seed = 332
125- np .random .seed (seed )
126- T = np .random .uniform (- 1000.0 , 1000.0 , [64 ])
127166
128167 isconstant_custom_func = functools .partial (
129168 naive .isconstant_func_stddev_threshold , quantile_threshold = 0.05
@@ -190,39 +229,158 @@ def test_snippets():
190229 cache ._recompile ()
191230
192231
193- @ pytest . mark . filterwarnings ( "ignore" , category = NumbaPerformanceWarning )
194- @ patch ( "stumpy.config.STUMPY_THREADS_PER_BLOCK" , TEST_THREADS_PER_BLOCK )
195- def test_distance_symmetry_property_in_gpu ():
196- if not cuda . is_available (): # pragma: no cover
197- pytest . skip ( "Skipping Tests No GPUs Available" )
232+ def test_snippets_rare_case_2 ():
233+ # This test fails when the naive implementation of snippet,
234+ # i.e. `naive.mpdist_snippets`, uses `np.sum` instead of
235+ # math.fsum when calculating the sum of many small
236+ # floating point numbers. For more details, see issue #1061
198237
199- # This test function raises an error if the distance between a subsequence
200- # and another one does not satisfy the symmetry property.
201- seed = 332
238+ seed = 1615
202239 np .random .seed (seed )
203- T = np .random .uniform (- 1000.0 , 1000.0 , [64 ])
204- m = 3
240+ T = np .random .uniform (- 1000.0 , 1000.0 , 64 )
205241
206- i , j = 2 , 10
207- # M_T, Σ_T = core.compute_mean_std(T, m)
208- # Σ_T[i] is `650.912209452633`
209- # Σ_T[j] is `722.0717285148525`
242+ m = 10
243+ s = 3
244+ k = 3
210245
211- # This test raises an error if arithmetic operation in ...
212- # ... `gpu_stump._compute_and_update_PI_kernel` does not
213- # generates the same result if values of variable for mean and std
214- # are swapped.
246+ isconstant_custom_func = functools .partial (
247+ naive .isconstant_func_stddev_threshold , quantile_threshold = 0.05
248+ )
249+ (
250+ ref_snippets ,
251+ ref_indices ,
252+ ref_profiles ,
253+ ref_fractions ,
254+ ref_areas ,
255+ ref_regimes ,
256+ ) = naive .mpdist_snippets (
257+ T , m , k , s = s , mpdist_T_subseq_isconstant = isconstant_custom_func
258+ )
215259
216- T_A = T [i : i + m ]
217- T_B = T [j : j + m ]
260+ (
261+ cmp_snippets ,
262+ cmp_indices ,
263+ cmp_profiles ,
264+ cmp_fractions ,
265+ cmp_areas ,
266+ cmp_regimes ,
267+ ) = stumpy .snippets (T , m , k , s = s , mpdist_T_subseq_isconstant = isconstant_custom_func )
218268
219- mp_AB = stumpy .gpu_stump (T_A , m , T_B )
220- mp_BA = stumpy .gpu_stump (T_B , m , T_A )
269+ if (
270+ not np .allclose (ref_snippets , cmp_snippets ) and not numba .config .DISABLE_JIT
271+ ): # pragma: no cover
272+ # Revise fastmath flags by removing reassoc (to improve precision),
273+ # recompile njit functions, and re-compute snippets.
274+ fastmath ._set (
275+ "core" , "_calculate_squared_distance" , {"nsz" , "arcp" , "contract" , "afn" }
276+ )
277+ cache ._recompile ()
221278
222- d_ij = mp_AB [0 , 0 ]
223- d_ji = mp_BA [0 , 0 ]
279+ (
280+ cmp_snippets ,
281+ cmp_indices ,
282+ cmp_profiles ,
283+ cmp_fractions ,
284+ cmp_areas ,
285+ cmp_regimes ,
286+ ) = stumpy .snippets (
287+ T , m , k , s = s , mpdist_T_subseq_isconstant = isconstant_custom_func
288+ )
224289
225- comp = d_ij - d_ji
226- ref = 0.0
290+ npt .assert_almost_equal (
291+ ref_snippets , cmp_snippets , decimal = config .STUMPY_TEST_PRECISION
292+ )
293+ npt .assert_almost_equal (
294+ ref_indices , cmp_indices , decimal = config .STUMPY_TEST_PRECISION
295+ )
296+ npt .assert_almost_equal (
297+ ref_profiles , cmp_profiles , decimal = config .STUMPY_TEST_PRECISION
298+ )
299+ npt .assert_almost_equal (
300+ ref_fractions , cmp_fractions , decimal = config .STUMPY_TEST_PRECISION
301+ )
302+ npt .assert_almost_equal (ref_areas , cmp_areas , decimal = config .STUMPY_TEST_PRECISION )
303+ npt .assert_almost_equal (ref_regimes , cmp_regimes )
227304
228- npt .assert_almost_equal (comp , ref , decimal = 15 )
305+ if not numba .config .DISABLE_JIT : # pragma: no cover
306+ # Revert fastmath flag back to their default values
307+ fastmath ._reset ("core" , "_calculate_squared_distance" )
308+ cache ._recompile ()
309+
310+
311+ def test_snippets_rare_case_3 ():
312+ # This test fails when the naive implementation of snippet,
313+ # i.e. `naive.mpdist_snippets`, uses `np.sum` instead of
314+ # math.fsum when calculating the sum of many small
315+ # floating point numbers. For more details, see issue #1061
316+
317+ seed = 2636
318+ np .random .seed (seed )
319+ T = np .random .uniform (- 1000.0 , 1000.0 , 64 )
320+ m = 9
321+ s = 3
322+ k = 3
323+
324+ isconstant_custom_func = functools .partial (
325+ naive .isconstant_func_stddev_threshold , quantile_threshold = 0.05
326+ )
327+ (
328+ ref_snippets ,
329+ ref_indices ,
330+ ref_profiles ,
331+ ref_fractions ,
332+ ref_areas ,
333+ ref_regimes ,
334+ ) = naive .mpdist_snippets (
335+ T , m , k , s = s , mpdist_T_subseq_isconstant = isconstant_custom_func
336+ )
337+
338+ (
339+ cmp_snippets ,
340+ cmp_indices ,
341+ cmp_profiles ,
342+ cmp_fractions ,
343+ cmp_areas ,
344+ cmp_regimes ,
345+ ) = stumpy .snippets (T , m , k , s = s , mpdist_T_subseq_isconstant = isconstant_custom_func )
346+
347+ if (
348+ not np .allclose (ref_snippets , cmp_snippets ) and not numba .config .DISABLE_JIT
349+ ): # pragma: no cover
350+ # Revise fastmath flags by removing reassoc (to improve precision),
351+ # recompile njit functions, and re-compute snippets.
352+ fastmath ._set (
353+ "core" , "_calculate_squared_distance" , {"nsz" , "arcp" , "contract" , "afn" }
354+ )
355+ cache ._recompile ()
356+
357+ (
358+ cmp_snippets ,
359+ cmp_indices ,
360+ cmp_profiles ,
361+ cmp_fractions ,
362+ cmp_areas ,
363+ cmp_regimes ,
364+ ) = stumpy .snippets (
365+ T , m , k , s = s , mpdist_T_subseq_isconstant = isconstant_custom_func
366+ )
367+
368+ npt .assert_almost_equal (
369+ ref_snippets , cmp_snippets , decimal = config .STUMPY_TEST_PRECISION
370+ )
371+ npt .assert_almost_equal (
372+ ref_indices , cmp_indices , decimal = config .STUMPY_TEST_PRECISION
373+ )
374+ npt .assert_almost_equal (
375+ ref_profiles , cmp_profiles , decimal = config .STUMPY_TEST_PRECISION
376+ )
377+ npt .assert_almost_equal (
378+ ref_fractions , cmp_fractions , decimal = config .STUMPY_TEST_PRECISION
379+ )
380+ npt .assert_almost_equal (ref_areas , cmp_areas , decimal = config .STUMPY_TEST_PRECISION )
381+ npt .assert_almost_equal (ref_regimes , cmp_regimes )
382+
383+ if not numba .config .DISABLE_JIT : # pragma: no cover
384+ # Revert fastmath flag back to their default values
385+ fastmath ._reset ("core" , "_calculate_squared_distance" )
386+ cache ._recompile ()
0 commit comments