-
Notifications
You must be signed in to change notification settings - Fork 0
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
Add utility method to iterate a shape by column #21
Conversation
Sometimes it is required that we iterate over the same elements of different arrays. An example of this is pointwise operations where the views of the two operands might be different, and we can't simply use the same index on the underlying storages.
mathoxide-lib/src/utils.rs
Outdated
fn next(&mut self) -> Option<Self::Item> { | ||
if self.current >= self.numel { | ||
None | ||
} else { | ||
let v = inverse_translate(self.current, &self.shape); | ||
self.current += 1; | ||
Some(v) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fn next(&mut self) -> Option<Self::Item> { | |
if self.current >= self.numel { | |
None | |
} else { | |
let v = inverse_translate(self.current, &self.shape); | |
self.current += 1; | |
Some(v) | |
} | |
} | |
fn next(&mut self) -> Option<Self::Item> { | |
let ndim = self.shape.len(); | |
let mut carry: usize = 1; | |
let mut pointer: usize = 0; | |
while carry == 1 && pointer < ndim { | |
self.current[ndim - pointer - 1] += carry; | |
carry = self.current[ndim - pointer - 1] / self.shape[ndim - pointer - 1]; | |
self.current[ndim - pointer - 1] %= self.shape[ndim - pointer - 1]; | |
pointer += 1; | |
} | |
if carry == 1 { | |
None | |
} | |
else { | |
Some(self.current.clone()) | |
} | |
} |
This is another way to do it. self.current
here is also a Vec and numel
is not required. Keep whichever you think is easier to read/more idiomatic for rust. Disclaimer: the code above is not tested
mathoxide-lib/src/utils.rs
Outdated
fn inverse_translate<Shape: AsRef<[usize]>>(idx: usize, shape: Shape) -> Vec<usize> { | ||
shape.as_ref().iter().rev().scan((1, 0), |(divisor, remainder), e| { | ||
let prev_div = *divisor; | ||
*divisor *= e; | ||
let res = ((idx - *remainder) % *divisor) / prev_div; | ||
*remainder += res; | ||
Some(res) | ||
}).collect() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I were to keep the current approach I would precompute the the products of the shape during the construction of the iterator e.g if shape=[1,2,3]
, precompute suffix_product=[6,6,3]
. Then you don't actually need to iterate here in reverse once you have the suffix_product
precomputed
mathoxide-lib/src/utils.rs
Outdated
} | ||
|
||
|
||
pub fn iterate_by_column<Shape: AsRef<[usize]>>(shape: &Shape) -> ByRowIterator { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the name could be iterate_row_major
. By column could be confused as going over the whole columns one by one in a column major order
mathoxide-lib/src/utils.rs
Outdated
} | ||
} | ||
|
||
pub fn by_column<Shape>(shape: &'a Shape) -> Self |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps use new in this method
Sometimes it is required that we iterate over the same elements of different
arrays. An example of this is pointwise operations where the views of
the two operands might be different, and we can't simply use the same index
on the underlying storages.
This PR is needed to resolve #2