Skip to content

Preserve minimum signed integers during hard thresholding - #889

Open
AHMETHAKANBEZIR1 wants to merge 1 commit into
PyWavelets:mainfrom
AHMETHAKANBEZIR1:fix/hard-threshold-signed-minimum
Open

AHMETHAKANBEZIR1 wants to merge 1 commit into
PyWavelets:mainfrom
AHMETHAKANBEZIR1:fix/hard-threshold-signed-minimum

Conversation

@AHMETHAKANBEZIR1

@AHMETHAKANBEZIR1 AHMETHAKANBEZIR1 commented Oct 13, 2026 •

Copy link
Copy Markdown

Hard thresholding silently discards the minimum signed integer because abs wraps in the original dtype. For example, threshold(np.array([-128,-127,0,127], dtype=np.int8), 64, mode='hard') returns [0,-127,0,127], although the magnitude of -128 is 128 and that sample should be preserved.

View signed integer absolute values as the corresponding unsigned dtype before comparison. Ordinary absolute values retain the same bits, while the wrapped minimum becomes its exact positive magnitude. This adds no floating-point conversion or magnitude-array copy, and the returned data still uses the existing np.where path.

Validation:

  • Thirty-four new cases cover int8/int16/int32/int64, default/custom substitutes, thresholds equal to and above the minimum's magnitude, scalar inputs, large int64 comparison controls, byte orders, and Python/NumPy scalar/zero-dimensional thresholds. Reference decisions use Python integer arithmetic. Unmodified main wheel: 20 failures and 14 passing controls.
  • Rebuilt the Windows MSVC/Cython wheel and checked that its source and test files match the final working tree. Full installed package tests on NumPy 2.5.4: 1,086 passed, 2 skipped.
  • Thresholding tests on NumPy 2.0.2: 38 passed. The older NumPy was loaded from an isolated target rather than replacing the main validation environment.
  • Real-input example: the built-in camera image centered by subtracting128 and cast to int8, hard threshold64. Its one -128 pixel is incorrectly removed on main; the fixed output has zero differences from an int16 magnitude reference and retains int8 output. This is a locally constructed preprocessing workflow, not a claimed production incident.
  • Applicable configured prek hooks and git diff --check pass.

CI follow-up: the AppVeyor Python 3.13 job also completed the full suite with 1,086 passed and 2 skipped. The Python 3.12 job log stops immediately after NumPy installation with process exit -1073740791, before building or testing PyWavelets. Its underlying cause has not been established; no workflow or check was weakened. Local Python 3.12 validation above passed.

Other threshold modes and other platforms were not tested for minimum-integer behavior. Codex investigated and validated this AI-assisted contribution autonomously; no independent human review is claimed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant