`ValueError: operands could not be broadcast together` when using `custom_iac` in `stumpy.fluss` (v1.13.0)
Closed this issue · 1 comments
Hello and thank you for your excellent package.
When providing a pre-computed Inverse Average Complexity (IAC) profile via the custom_iac parameter to stumpy.fluss, a ValueError related to shape incompatibility is raised within the internal _cac function. This occurs even when the custom_iac array is confirmed to have the correct expected shape (len(I) - L + 1,).
According to the documentation and intended use, stumpy.fluss should accept custom_iac of shape (len(I) - L + 1,) and use it directly in the CAC calculation.
Steps to Reproduce
- Import necessary libraries.
- Create a synthetic time series
I. - Define window size
Land the number of regimesn_regimes. - Calculate the expected profile length
profile_len = len(I) - L + 1. - Create a simple
custom_iacarray of shape(profile_len,). - Call
stumpy.flusspassing thecustom_iac.
import numpy as np
import stumpy
import matplotlib.pyplot as plt # Included in case plotting code is run afterwards
# 1. Create a synthetic time series (I) with different regimes
ts_len1 = 200
ts_len2 = 200
ts_len3 = 200
I = np.concatenate([
5 * np.sin(np.linspace(0, 10 * np.pi, ts_len1)),
10 + 0.5 * np.random.randn(ts_len2),
5 * np.random.randn(ts_len3)
])
N = len(I) # N = 600
# 2. Define window size (L) and number of regimes to find
L = 50
n_regimes = 3
# 3. Calculate the required length of the profile (N - L + 1)
profile_len = N - L + 1 # profile_len = 600 - 50 + 1 = 551
# 4. Create a SIMPLE custom_iac profile of the correct shape
# Using a simple constant IAC to eliminate complexity in IAC creation logic as the cause
custom_iac = np.ones(profile_len) * 0.5 # Should be shape (551,)
# Add print statements to verify shapes immediately before the call
print(f"Shape of original time series I: {I.shape}")
print(f"Calculated expected profile length (N - L + 1): {profile_len}")
print(f"Shape of the created custom_iac: {custom_iac.shape}") # Expected: (551,)
# 5. Run stumpy.fluss with the custom_iac
try:
# Note: stumpy.fluss returns (regimes, iac, cac) in v1.13.0
regimes, iac_output, cac = stumpy.fluss(I, L, n_regimes, custom_iac=custom_iac)
print("stumpy.fluss completed successfully (unexpected based on error seen before).")
print(f"Identified regime change points (indices in I): {regimes}")
# Optional: Add plotting code here if it runs without the error
except ValueError as e:
print(f"\nA ValueError occurred: {e}")
print("This error occurred inside stumpy.floss._cac during the CAC calculation.")
# Re-print actual shape just in case something changed (highly unlikely)
print(f"Actual custom_iac shape *after* error caught: {custom_iac.shape}")Observed Behavior
When running the code above, the following output and traceback are observed:
STUMPY version: 1.13.0
Shape of original time series I: (600,)
Calculated expected profile length (N - L + 1): 551
Shape of the created custom_iac: (551,)
A ValueError occurred: operands could not be broadcast together with shapes (600,) (551,)
This error occurred inside stumpy.floss._cac during the CAC calculation.
Actual custom_iac shape *after* error caught: (551,)
Followed by a traceback similar to this (line numbers might vary slightly but the core error location is within stumpy.floss._cac):
ValueError Traceback (most recent call last)
File "<ipython-input-...>", line XX, in <module>
regimes, iac_output, cac = stumpy.fluss(I, L, n_regimes, custom_iac=custom_iac)
File "~/miniconda3/envs/stumpy_env/lib/python3.12/site-packages/stumpy/floss.py", line 300, in fluss
cac = _cac(I, L, bidirectional=True, excl_factor=excl_factor, custom_iac=custom_iac)
File "~/miniconda3/envs/stumpy_env/lib/python3.12/site-packages/stumpy/floss.py", line 174, in _cac
CAC[:] = AC / IAC
ValueError: operands could not be broadcast together with shapes (600,) (551,)
The error occurs at CAC[:] = AC / IAC within _cac. The error message indicates shapes (600,) and (551,). Since CAC and AC are internally computed based on N and L, they are expected to have shape (551,). The presence of (600,) suggests that the variable representing the IAC profile within _cac is incorrectly inheriting the shape of the original time series I (600) instead of using the provided custom_iac which has the correct shape (551). This contradicts the print statements verifying the custom_iac shape before the function call.
Expected Behavior
The stumpy.fluss function should successfully run when provided with a custom_iac array that has the shape (len(I) - L + 1,), without raising a ValueError. The custom_iac should be used directly in the calculation CAC = AC / IAC where AC, IAC, and CAC all have the shape (len(I) - L + 1,).
Regards
snvv
@snvv Thank you for your question and welcome to the STUMPY community.
Create a synthetic time series I.
So, throughout the STUMPY documentation, we generally reserve T to represent our time series and, instead, I would represent the the resultant matrix profile indices. Note that the length of T is often denoted by n = len(T) and the window size is represented as m. Thus, the length of I (the matrix profile indices) would be n - m + 1.
Thus, this should work:
import numpy as np
import stumpy
import matplotlib.pyplot as plt # Included in case plotting code is run afterwards
ts_len1 = 200
ts_len2 = 200
ts_len3 = 200
T = np.concatenate([
5 * np.sin(np.linspace(0, 10 * np.pi, ts_len1)),
10 + 0.5 * np.random.randn(ts_len2),
5 * np.random.randn(ts_len3)
])
n = len(T) # N = 600
L = 50
n_regimes = 3
mp = stumpy.stump(T, L)
I = mp.I_ # This is the same as `I = mp[:, 1]`
profile_len = len(I) # This is `n - L + 1`
custom_iac = np.ones(profile_len) * 0.5 # Should be shape (551,)
cac, regimes = stumpy.fluss(I, L, n_regimes, custom_iac=custom_iac)
Note: stumpy.fluss returns (regimes, iac, cac) in v1.13.0
I don't think this statement is true according to the fluss documentation for v1.13.0
Please feel free to ask any follow up questions or let me know if there's anything else that I could clarify.