I know discrete convolutions are supposed to be associative. So if I have some array, x, then x * (x * (x * x)) should equal (x * x) * (x * x). But there are some situations where that doesn't happen.
Here is code that exercises that formula with four examples:
[1, 1] # Works
[-54298238, 5998425] # Works
[-95.3720828588315, 52.6296402253613] # Works
[-94.25133703348938, 90.41999267567854] # Broken
import numpy as np
def main():
int_ok = np.array([1, 1], dtype=np.int)
int_larger = np.array(
[-54298238,5998425], dtype=np.int
)
float_ok = np.array(
[-95.3720828588315, 52.6296402253613], dtype=np.float
)
float_broken = np.array(
[-94.25133703348938, 90.41999267567854], dtype=np.float
)
fixtures = [int_ok, int_larger, float_ok, float_broken]
for fixture in fixtures:
reference = np.convolve(
fixture,
np.convolve(
fixture,
np.convolve(
fixture,
fixture
)
)
)
tmp = np.convolve(fixture, fixture)
test = np.convolve(tmp, tmp)
print('input', fixture)
print('reference output', reference)
print('output', test)
all_equal = all(reference == test)
print('all equal', all_equal)
if not all_equal:
print('error', np.abs(reference - test))
if __name__ == '__main__':
main()
I assume this is due to some kind of numerical instability, but I can't quite figure out what's going on.
Does anyone have any ideas?
Thanks.
Inspired by this comment Why does numpy.convolve not behave associatively? by Mark Dickinson, I reworked my original code so that I'm no longer assuming the results are strictly the same, but rather using numpy.allclose.
Here is the modified code:
import numpy as np
def main():
int_ok = np.array([1, 1], dtype=np.int)
int_larger = np.array(
[-54298238,5998425], dtype=np.int
)
float_ok = np.array(
[-95.3720828588315, 52.6296402253613], dtype=np.float
)
float_broken = np.array(
[-94.25133703348938, 90.41999267567854], dtype=np.float
)
fixtures = [int_ok, int_larger, float_ok, float_broken]
for fixture in fixtures:
reference = np.convolve(
fixture,
np.convolve(
fixture,
np.convolve(
fixture,
fixture
)
)
)
tmp = np.convolve(fixture, fixture)
test = np.convolve(tmp, tmp)
if np.allclose(reference, test):
print('OK', fixture)
else:
print('FAIL', fixture)
if __name__ == '__main__':
main()
numpy.allclose
is returning True
, so I think this is the best solution I'm going to get.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.