Skip to content

Fix #464: crash of Pauli-flow finding algorithm due to incorrect numba signatures.#465

Merged
matulni merged 10 commits intoTeamGraphix:masterfrom
matulni:fix464
Mar 11, 2026
Merged

Fix #464: crash of Pauli-flow finding algorithm due to incorrect numba signatures.#465
matulni merged 10 commits intoTeamGraphix:masterfrom
matulni:fix464

Conversation

@matulni
Copy link
Contributor

@matulni matulni commented Mar 9, 2026

This commit proposes a fix to issue #464. The example triggering the crash is added to the test suit.

Detailed explanation

To improve the efficiency of just-in-time compiled functions in the graphix._linalg module, we indicate the memory layout of the array parameters. In particular, we write u8[:,::1] to indicate that we expect C_CONTIGUOUS arrays which is numpy's default. If we pass an F_CONTIGUOUS array to these functions, numba will crash as in the reported bug.

Computing the transpose of a C_CONTIGUOUS array with numpy.transpose only changes the metadata flags of the array to avoid unnecessary copying:

>>> import numpy as np
>>> a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
>>> print(a.flags)
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : True
  WRITEABLE : True
  ALIGNED : True
  WRITEBACKIFCOPY : False
>>> print(a.transpose().flags)
  C_CONTIGUOUS : False
  F_CONTIGUOUS : True
  OWNDATA : False
  WRITEABLE : True
  ALIGNED : True
  WRITEBACKIFCOPY : False

This transformation occurred inadvertently in :func: graphix.flow._find_gpflow._compute_correction_matrix_general_case:

# Steps 5, 6 and 7
ker_flow_demand_matrix = flow_demand_matrix.null_space().transpose()

Why did all the tests pass ?

Very often, the kernel of the flow demand matrix is a one-row or one-column matrix. In this case, the corresponding numpy array is both C_CONTIGUOUS and F_CONTIGUOUS, so computing the transpose does not invalidate the numba decorator signature:

>>> import numpy as np
>>> a = np.array([[1, 2, 3]])
>>> print(a.flags)
  C_CONTIGUOUS : True
  F_CONTIGUOUS : True
  OWNDATA : True
  WRITEABLE : True
  ALIGNED : True
  WRITEBACKIFCOPY : False
>>> print(a.transpose().flags)
  C_CONTIGUOUS : True
  F_CONTIGUOUS : True
  OWNDATA : False
  WRITEABLE : True
  ALIGNED : True
  WRITEBACKIFCOPY : False

What is the fix?

The function numpy.ascontiguousarray allows to reexpress an F_CONTIGUOUS array as C_CONTIGUOUS. Note that if the original array is C_CONTIGUOUS in the first place, calling numpy.ascontiguousarray does not incur in an extra coyping:

import numpy as np
import timeit

a = np.eye(100)
at = a.transpose()

assert a.flags["C_CONTIGUOUS"]
assert at.flags["F_CONTIGUOUS"]

# Original matrix
assert np.ascontiguousarray(a).flags["C_CONTIGUOUS"]
assert a is np.ascontiguousarray(a)
t = timeit.Timer(lambda: np.ascontiguousarray(a))  
print(t.timeit(1_000_000))  # 0.06663083399871539

# Transpose 
assert np.ascontiguousarray(at).flags["C_CONTIGUOUS"]
assert a is not np.ascontiguousarray(at)
t = timeit.Timer(lambda: np.ascontiguousarray(at))  
print(t.timeit(1_000_000))  # 6.021290332999342

@codecov
Copy link

codecov bot commented Mar 9, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 88.95%. Comparing base (d5343cf) to head (3649af5).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #465   +/-   ##
=======================================
  Coverage   88.95%   88.95%           
=======================================
  Files          44       44           
  Lines        6530     6530           
=======================================
  Hits         5809     5809           
  Misses        721      721           

☔ 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.

@matulni matulni requested a review from emlynsg March 9, 2026 16:33
@thierry-martinez
Copy link
Collaborator

It is a bit disappointing that functions in _linalg.py make assumptions about array layouts, especially since we don't document this. Are you sure these assumptions impact performance? Do benchmarks degrade if we use the signature @nb.njit("uint8[:,:](uint8[:,:], uint8[:,:])", parallel=True) instead?

@matulni
Copy link
Contributor Author

matulni commented Mar 10, 2026

Commit 5cf616c ensures that all numba-jitted functions called from graphix._linalg.py receive c-contiguous functions. New tests at the level of _linalg.py are added.

Further, initialisation of graphix._linalg.MatGF2 preserves the memory layout of the original data now, instead of generating C_CONTIGUOUS arrays which was an unreported bug.

Copy link
Collaborator

@thierry-martinez thierry-martinez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice! Just a small suggestion, but I approve already.

matulni and others added 3 commits March 10, 2026 17:51
Co-authored-by: thierry-martinez <thierry.martinez@inria.fr>
Co-authored-by: thierry-martinez <thierry.martinez@inria.fr>
@thierry-martinez
Copy link
Collaborator

LGTM! Thanks!

@matulni matulni merged commit e2686c6 into TeamGraphix:master Mar 11, 2026
24 checks passed
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.

3 participants