Skip to content

Make is_contiguous check common #3083

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 28, 2025
Merged

Make is_contiguous check common #3083

merged 5 commits into from
Apr 28, 2025

Conversation

laggui
Copy link
Member

@laggui laggui commented Apr 25, 2025

Checklist

  • Confirmed that run-checks all script has been executed.

Related Issues/PRs

Following this comment in #3077

Changes

Migrated is_contiguous to common (including minor fix).

Testing

Also added a unit test for shape [3, 1] and strides [1, 1] which would previously be marked as not contiguous.

/// such that the strides are in non-increasing order, and the stride at position
/// `k` is equal to the product of the shapes of all dimensions greater than `k`.
/// Axes with a shape of 1 are ignored.
pub fn is_contiguous(shape: &[usize], strides: &[usize]) -> bool {
Copy link
Member Author

Choose a reason for hiding this comment

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

I also think the check could be simplified to

pub fn is_contiguous(shape: &[usize], strides: &[usize]) -> bool {
    if shape.is_empty() {
        return true;
    }

    let mut expected_stride = 1;

    for (&shape, &stride) in shape.iter().zip(strides).rev() {
        if shape == 1 {
            continue;
        }

        if stride != expected_stride {
            return false;
        }

        expected_stride *= shape;
    }

    true
}

But leaving this here as a note and not a required change.

Copy link
Member

Choose a reason for hiding this comment

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

I would prefer that strategy actually, we could even create a function that could be used to create the strides AND be used for the checks:

pub fn contiguous_strides(shape: &[usize]) -> impl Iterator<Item = usize> {
    let mut current = 1;
    shape
            .iter()
            .rev()
            .map(|val| {
                current *= val;
                current
            })
            .rev()
}
pub fn is_contiguous(shape: &[usize], strides: &[usize]) -> bool { 
    if shape.is_empty() {
         return true;
     }
     
     for (i, expected) in contiguous_strides(shape).enumerate() {
         if expected != strides[i] {
             return false;
         }
     }
     
     true

Copy link
Member Author

@laggui laggui Apr 28, 2025

Choose a reason for hiding this comment

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

The double .rev() cancel out for lazy iterator operations. Also, the first computed stride value should be 1.

I changed the suggested contiguous_strides implementation to match these criteria.

Copy link

codecov bot commented Apr 25, 2025

Codecov Report

Attention: Patch coverage is 96.42857% with 1 line in your changes missing coverage. Please review.

Project coverage is 81.09%. Comparing base (e096b0c) to head (efa2a5d).
Report is 9 commits behind head on main.

Files with missing lines Patch % Lines
crates/burn-common/src/lib.rs 95.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3083      +/-   ##
==========================================
- Coverage   81.16%   81.09%   -0.08%     
==========================================
  Files         815      817       +2     
  Lines      117201   117320     +119     
==========================================
+ Hits        95121    95135      +14     
- Misses      22080    22185     +105     

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

@laggui laggui marked this pull request as ready for review April 28, 2025 11:51
@laggui laggui requested a review from nathanielsimard April 28, 2025 11:51
/// such that the strides are in non-increasing order, and the stride at position
/// `k` is equal to the product of the shapes of all dimensions greater than `k`.
/// Axes with a shape of 1 are ignored.
pub fn is_contiguous(shape: &[usize], strides: &[usize]) -> bool {
Copy link
Member

Choose a reason for hiding this comment

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

I would prefer that strategy actually, we could even create a function that could be used to create the strides AND be used for the checks:

pub fn contiguous_strides(shape: &[usize]) -> impl Iterator<Item = usize> {
    let mut current = 1;
    shape
            .iter()
            .rev()
            .map(|val| {
                current *= val;
                current
            })
            .rev()
}
pub fn is_contiguous(shape: &[usize], strides: &[usize]) -> bool { 
    if shape.is_empty() {
         return true;
     }
     
     for (i, expected) in contiguous_strides(shape).enumerate() {
         if expected != strides[i] {
             return false;
         }
     }
     
     true

@laggui laggui requested a review from nathanielsimard April 28, 2025 15:18
@nathanielsimard nathanielsimard merged commit 26e0f8c into main Apr 28, 2025
11 checks passed
@nathanielsimard nathanielsimard deleted the common/is-contiguous branch April 28, 2025 21:26
laggui added a commit that referenced this pull request Jun 2, 2025
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.

2 participants