Skip to content

fix(sparse): floor() returns a copy instead of mutating its input (#740)#894

Open
SaguaroDev wants to merge 1 commit into
casact:mainfrom
SaguaroDev:740-sparse-floor-copy
Open

fix(sparse): floor() returns a copy instead of mutating its input (#740)#894
SaguaroDev wants to merge 1 commit into
casact:mainfrom
SaguaroDev:740-sparse-floor-copy

Conversation

@SaguaroDev
Copy link
Copy Markdown
Contributor

@SaguaroDev SaguaroDev commented May 31, 2026

Closes #740.

chainladder.utils.sparse.floor(x) reassigned x.data in place, mutating the caller's COO array as a side effect:

def floor(x):
    x.data = np.floor(x.data)
    return x

Since np.floor() returns a copy, this makes floor() match that contract by copying before flooring, using the same .copy() idiom already present in nan_to_num() in the same module:

def floor(x):
    x = x.copy()
    x.data = np.floor(x.data)
    return x

Behavior now matches the issue's expectation:

a = array([1.2, 2.7, -0.3])
floor(a)
a.todense()        # array([ 1.2,  2.7, -0.3])  (unchanged)

a = floor(a)
a.todense()        # array([ 1.,  2., -1.])

The only internal caller (chainladder/core/correlation.py) already consumes the return value (m = xp.floor((n - 1) / 2)), so the change is behavior-preserving there.

Updated test_floor_mutates_in_place (which asserted result is a) to test_floor_returns_copy, asserting the result is a new object and the input is left unmodified. test_sparse.py and test_correlation.py pass (12 passed).


Note

Low Risk
Small API-contract fix in a utility helper with a single internal caller that already uses the return value; tests cover the new behavior.

Overview
chainladder.utils.sparse.floor no longer mutates the input COO array: it copies first (same pattern as nan_to_num), then floors x.data, aligning with np.floor’s non-mutating contract (issue #740).

Tests were renamed/updated from asserting in-place mutation (result is a) to asserting a new object and an unchanged input.

correlation.py already uses the return value only, so call sites are unchanged in practice.

Reviewed by Cursor Bugbot for commit 55c55e8. Bugbot is set up for automated code reviews on this repo. Configure here.

…sact#740)

chainladder.utils.sparse.floor(x) reassigned x.data in place, mutating
the caller's COO array. np.floor() returns a copy, so floor() should too.

Copy the array before flooring its data, mirroring the existing
nan_to_num() idiom in the same module. The one internal caller
(core/correlation.py) already uses the return value, so behavior is
preserved.

Updated the test that asserted in-place mutation to assert the new copy
semantics: the result is a new object and the input is left unchanged.

Closes casact#740.
@codecov
Copy link
Copy Markdown

codecov Bot commented May 31, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.90%. Comparing base (8a9a46e) to head (55c55e8).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #894   +/-   ##
=======================================
  Coverage   86.90%   86.90%           
=======================================
  Files          87       87           
  Lines        4932     4933    +1     
  Branches      624      624           
=======================================
+ Hits         4286     4287    +1     
  Misses        456      456           
  Partials      190      190           
Flag Coverage Δ
unittests 86.90% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@henrydingliu
Copy link
Copy Markdown
Collaborator

since we are already touching this function, may I please trouble you to add type hinting for the input and output?

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.

[ENH] Update chainladder.utils.sparse.floor(x) to return a copy of x

2 participants