Skip to content

Add unchecked swap method (uswap) #364

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 1 commit into from
Oct 10, 2017
Merged

Conversation

jturner314
Copy link
Member

@jturner314 jturner314 commented Sep 29, 2017

This adds an unchecked swap method, which is necessary for performing in-place transposition of square matrices (i.e. actually moving the data around) without bounds checking. (Using uget_mut doesn't work for this case ::std::mem::swap(unsafe { a.uget_mut((i, j)) }, unsafe{ a.uget_mut((j, i)) }) because it would require the array to be mutably borrowed twice.)

@bluss
Copy link
Member

bluss commented Sep 29, 2017

Looks good. I've implemented divide and conquer square transposition at some point, it might be useful to you? It didn't need this method at least, maybe using more deviant tricks (we can get the raw pointer directly, too).

looking now, yes, one can use uget_mut if we cast the result to raw pointer (the borrow is gone that way).

#[inline(never)]
fn trans_base_case<A, O>(m: Ix, mut v: ArrayViewMut<A, Ix2>)
    where O: Order,
{
    for i in 0..m - 1 {
        if O::inner_contig() {
            unsafe {
                let mut ptr1: *mut _ = v.uget_mut((i, i + 1));
                for j in i + 1..m {
                    let ptr2: *mut _ = v.uget_mut((j, i));
                    mem::swap(&mut *ptr1, &mut *ptr2);
                    ptr1 = ptr1.offset(1);
                }
            }
        } else {
            unsafe {
                for j in i + 1..m {
                    let ptr1: *mut _ = v.uget_mut((i, j));
                    let ptr2: *mut _ = v.uget_mut((j, i));
                    mem::swap(&mut *ptr1, &mut *ptr2);
                }
            }
        }
    }
}

@jturner314
Copy link
Member Author

I've implemented divide and conquer square transposition at some point, it might be useful to you?

Yeah, if you still have the code lying around somewhere, it would be helpful. I'm working on adding some functionality to ndarray-linalg, and I need to be able to convert from arbitrary ndarray layouts to column-major layout for passing to the Fortran LAPACK routines. For most matrices, the simplest thing to do is to allocate a new array and copy all the elements, but when possible for row-major square matrices, it would be nice to transpose the data in-place.

one can use uget_mut if we cast the result to raw pointer (the borrow is gone that way)

Good point; I didn't think of bypassing the borrow checker that way. I need to reread the Rust book at some point. :) Since using pointers is an option, I don't think it's necessarily worth merging this PR.

@bluss
Copy link
Member

bluss commented Sep 30, 2017

I think this is a worthwhile feature

@bluss
Copy link
Member

bluss commented Oct 6, 2017

Hey, sorry for forgetting about this. This is the transpose code which is MIT/Apache-2.0 (c) bluss as usual and use as you wish. What's blocking putting it in ndarray itself is that it's only implementing square transpose (the easy part!) and of course the usual doubts if it's efficient enough.. but I think it is. https://gist.github.com/bluss/8221102b3a3941bb68deb07cbd96d9cc

@bluss
Copy link
Member

bluss commented Oct 10, 2017

Thank you for a well written PR!

@bluss bluss merged commit f838639 into rust-ndarray:master Oct 10, 2017
@jturner314 jturner314 deleted the add-uswap branch October 10, 2017 22:38
@jturner314
Copy link
Member Author

You're welcome! Thank for providing the gist for the cache-friendly in-place transpose.

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