Skip to content
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

split_at for Array #94

Merged
merged 6 commits into from
Feb 29, 2016
Merged

split_at for Array #94

merged 6 commits into from
Feb 29, 2016

Conversation

vbarrielle
Copy link
Contributor

This PR introduces a split_atlike family of functions for arrays. This is currently work in progress.

Status:

  • axis_split_at
  • axis_split_at_mut
  • tests

@bluss
Copy link
Member

bluss commented Feb 28, 2016

I think I prefer if we only provide axis split (not outer split, since it's a simple special case, isn't it?)


let mut dim_left = self.dim.clone();
dim_left.slice_mut()[axis] = index;
let left = ArrayView {
Copy link
Member

Choose a reason for hiding this comment

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

You can use ArrayView::new_ here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

right, that's less boilerplate

@vbarrielle
Copy link
Contributor Author

Indeed it's just a special case, but I was wondering if we didn't want to have some symmetry with the outer_iter, axis_iter methods?

@bluss
Copy link
Member

bluss commented Feb 28, 2016

The most flexible API is not the easiest to use. Again a view based self -> (Self, Self) function may be the easiest.

Consider a function like this:

fn divide_and_conquer<'a, A>(array: ArrayView<'a, A, Ix>) { }

The only way to pass on a view with the same lifetime 'a is the self based methods I think. We want to be able to split an array view without tying the split result to the stack frame where the split happens.

This is the same way .into_iter() for an array view works, it is lifetime preserving unlike .iter(). So if you examine this problem, you find that maybe you want into_inner_iter() etc methods for array views too. (Lifetime-preserving iterator constructors). It's all quite complicated.

@bluss
Copy link
Member

bluss commented Feb 28, 2016

Consistency is good, but we need to stem the rising tide of a million methods too. Maybe I shouldn't have added OuterIter either.

@vbarrielle
Copy link
Contributor Author

Yes I see your point with the lifetimes issue. I wanted to mimick the slice's API but I guess there is some special treatment to slices here.

One (probably ugly) way I found to circumvent that problem in other crates (sprs) was to have additional methods defined only on views which would return views based on the lifetime of the data, not the lifetime of self in the method call. I wish there were some sort of "lifetime specialization" to overcome this issue. Not sure I'm really clear here, my thoughts are a bit blurry and I think I lack the proper vocabulary to express them.

@bluss
Copy link
Member

bluss commented Feb 28, 2016

Yes! Slices are dsts, so they implement methods on the type [T]. If you look closely, you'll find lots of traces of this issue where it would be cool if an ArrayView could be a custom DST like that.

I think that ArrayView::axis_split_at(self) and ArrayViewMut::axis_split_at(self) is what we want here. We have to solve view methods not showing up in the docs, though.

@vbarrielle
Copy link
Contributor Author

We have to solve view methods not showing up in the docs, though.

If I remember correctly, I've had a similar issue in sprs, and the solution was to define the impl block on the full type, not the alias type. That was quite some time ago but it might be worth a try.

@bluss
Copy link
Member

bluss commented Feb 28, 2016

Yes, that will work

@bluss
Copy link
Member

bluss commented Feb 28, 2016

The for loop doesn't seem right.

Is this right: consider a 3 x 4 x 5 array (3 pages, 4 rows, 5 columns)

Split on axis = 2, index = 2 should produce two views of shapes
3 x 4 x 2 and 3 x 4 x 3

@vbarrielle
Copy link
Contributor Author

I'm not sure I got your point here, that for loop is only supposed to help find the correct pointer offset, but the resulting shapes should be what you said.
However it's getting late here so it's quite probable I'm too sleepy to see the issue.

@bluss
Copy link
Member

bluss commented Feb 28, 2016

I'll review it more carefully. Some pen and paper doodling (that's when you know you're actually thinking..).

@vbarrielle
Copy link
Contributor Author

I've switched to the view-by-value pattern and added some tests. I'll probably add a macro to factor out the code once again, and I need to test more complicated cases.

@bluss
Copy link
Member

bluss commented Feb 28, 2016

Awesome

*ind = index;
}
}
let offset = self.dim.stride_offset_checked(&self.strides,
Copy link
Member

Choose a reason for hiding this comment

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

There's the stride_offset method which does this without bounds checking.

Copy link
Member

Choose a reason for hiding this comment

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

On a closer look, we can just skip the whole for loop, can't we? Using stride * index directly (function stride_offset in dimension for example).

@vbarrielle vbarrielle changed the title WIP: split_at for Array split_at for Array Feb 29, 2016
@vbarrielle
Copy link
Contributor Author

I've fixed the formatting issue, replaced the for loop by an appropriate call to dimension::stride_offset, and added more tests.

I'm no longer sure I should try and factor both impls in a macro, they're quite short now. As you wish :)

@bluss
Copy link
Member

bluss commented Feb 29, 2016

Awesome, this is good. I'll merge the Axis PR too.

bluss added a commit that referenced this pull request Feb 29, 2016
@bluss bluss merged commit ca61280 into rust-ndarray:master Feb 29, 2016
@bluss
Copy link
Member

bluss commented Feb 29, 2016

Before I release this, what do you think of renaming the methods to split_at?

pub fn axis_split_at(self, axis: Axis, index: Ix)

versus

pub fn split_at(self, axis: Axis, index: Ix)

I bring this up since split_at seems nice an unambiguous too.

@vbarrielle
Copy link
Contributor Author

Yes split_at seems nice and unambiguous, I don't think we could ever have a split_at taht does not require an axis argument.

@vbarrielle vbarrielle deleted the splitAt branch February 29, 2016 13:33
@bluss
Copy link
Member

bluss commented Feb 29, 2016

Done.

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