Skip to content

Sparse echelon form over QQ is mutable and shared with the cache (#10543 was fixed for dense only) #42531

Description

@cxzhong

Steps To Reproduce

This is #10543 ("Echelon form over QQ is mutable"), which was fixed for dense rational matrices only. Matrix_rational_sparse was never updated and still has the bug — with the extra consequence, not present in the original report, that the mutable result is shared with the cache, so modifying it corrupts the source matrix.

Matrix_rational_sparse.echelon_form caches its result and returns it mutable. The caller can therefore modify the matrix that the cache hands out, and every later call returns the corrupted object:

sage: A = matrix(QQ, [[1, 2], [3, 4]], sparse=True)
sage: E = A.echelon_form()
sage: E.is_mutable()
True
sage: E[0, 0] = 0
sage: A.echelon_form()
[0 0]
[0 1]          # not the echelon form of A

The dense class does not have this problem, because it calls set_immutable() on the result before caching it:

sage: matrix(QQ, [[1, 2], [3, 4]]).echelon_form().is_mutable()
False

Expected Behavior

echelon_form() should return an immutable matrix, as it does for dense matrices over QQ (since #10543) and for matrices over ZZ. A caller who wants to modify the result should have to copy it.

Actual Behavior

The sparse result is mutable and shared with the cache, so mutating it silently corrupts the source matrix's cached echelon form (and its cached pivots).

Additional Information

In src/sage/matrix/matrix_rational_sparse.pyx, echelon_form ends with

        E, pivots = self._echelon_form_multimodular(height_guess, proof=proof)

        self.cache(label, E)
        self.cache('pivots', pivots)
        return E

with no E.set_immutable(), whereas Matrix_rational_dense.echelon_form does call it.

There is a second, related leak of the same invariant a few lines up: when self is already in echelon form, the sparse method returns self — which may be mutable — instead of an immutable copy.

Found while working on #42417 (multimodular echelon form over QQ); this bug is independent of that PR and develop behaves the same way, so it is filed separately rather than fixed there.

Environment

  • OS: Linux (Ubuntu, WSL2)
  • Sage Version: 10.10.beta5

Checklist

  • I have searched the existing issues for a bug report that matches the one I want to file, without success.
  • I have verified the problem exists in the latest development version.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions