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

Overloaded Indexing Operations #490

Merged
merged 4 commits into from Dec 29, 2018

Conversation

Projects
None yet
2 participants
@jswrenn
Copy link
Member

jswrenn commented Dec 2, 2018

This P.R. overloads matrix indexing in the same manner that the standard library overloads slice indexing.

Modes of Indexing

Matrices can be indexed in three ways, each with different safety guarantees:

  • get produces Some reference to the element(s) at the index, or None if the index is out of bounds
  • index produces a reference to the element(s) at the index, or panics if the index is out of bounds
  • get_unchecked produces a reference to the element(s) at the index, without bounds checking

Each of these has a corresponding _mut counterpart that produces a mutable reference to the element(s) at the given location.

Types of Indices

Matrices can be indexed by a usize, or with any pair of usize, Range<usize>, RangeFrom<usize>, RangeFull, RangeInclusive<usize>, RangeTo<usize>, and RangeToInclusive<usize>.

Indexing by usize and (usize, usize) produces a reference to the element at that location. All other two-dimensional indices produce a MatrixSlice.

Some examples:

Indices to Individual Elements

Two-Dimensional Indices

let matrix = Matrix2::new(0, 2,
                          1, 3);

assert_eq!(matrix.index((0, 0)), &0);
assert_eq!(matrix.index((1, 0)), &1);
assert_eq!(matrix.index((0, 1)), &2);
assert_eq!(matrix.index((1, 1)), &3);

Linear Address Indexing

let matrix = Matrix2::new(0, 2,
                          1, 3);

assert_eq!(matrix.get(0), Some(&0));
assert_eq!(matrix.get(1), Some(&1));
assert_eq!(matrix.get(2), Some(&2));
assert_eq!(matrix.get(3), Some(&3));

Indices to Individual Rows and Columns

Index to a Row

let matrix = Matrix2::new(0, 2,
                          1, 3);

assert!(matrix.index((0, ..))
    .eq(&Matrix1x2::new(0, 2)));

Index to a Column

let matrix = Matrix2::new(0, 2,
                          1, 3);

assert!(matrix.index((.., 0))
    .eq(&Matrix2x1::new(0,
                        1)));

Indices to Parts of Individual Rows and Columns

Index to a Partial Row

let matrix = Matrix3::new(0, 3, 6,
                          1, 4, 7,
                          2, 5, 8);

assert!(matrix.index((0, ..2))
    .eq(&Matrix1x2::new(0, 3)));

Index to a Partial Column

let matrix = Matrix3::new(0, 3, 6,
                          1, 4, 7,
                          2, 5, 8);

assert!(matrix.index((..2, 0))
    .eq(&Matrix2x1::new(0,
                        1)));

Indices to Ranges of Rows and Columns

Index to a Range of Rows

let matrix = Matrix3::new(0, 3, 6,
                          1, 4, 7,
                          2, 5, 8);

assert!(matrix.index((1..3, ..))
    .eq(&Matrix2x3::new(1, 4, 7,
                        2, 5, 8)));

Index to a Range of Columns

let matrix = Matrix3::new(0, 3, 6,
                          1, 4, 7,
                          2, 5, 8);

assert!(matrix.index((.., 1..3))
    .eq(&Matrix3x2::new(3, 6,
                        4, 7,
                        5, 8)));

Future Work

This PR can be extended in a non-breaking way to permit:

  • Overloaded linear address indexing.
  • Further overloading two-dimensional indexing whereby the row and column components are ranges of Dim (and thus the output can be a MatrixSlice of size known at compile-time). This just requires some tricky code-generation work that the current macros can't handle.
@sebcrozet

This comment has been minimized.

Copy link
Member

sebcrozet commented Dec 3, 2018

This is amazing! I will take a closer look and get back to you this week.

@jswrenn

This comment has been minimized.

Copy link
Member

jswrenn commented Dec 3, 2018

9f9e575 implements the groundwork for indexing with typenums and adds a proof-of-concept MatrixIndex implementation for index pairs where one of the components is a ops::RangeFrom<impl DimName>.

To support the other range types, we're going to need to do some work to surface more of typenum's type-level operators as Dim operators (namely IsLess). This seems like a significant undertaking, and I don't think I'll get to it in this PR.

@sebcrozet
Copy link
Member

sebcrozet left a comment

Great PR overall!
The macro for generating the MatrixIndex{Mut} trait for all pairs of range type is very interesting!
I agree that indexing with ranges based on DimName types can be left to another PR. Also it seems impossible to use type-lever integers as bounds of Range because both ends of a..b must have the same type.

The only requested change is about a typo for indices instead of indices.

Show resolved Hide resolved src/base/indexing.rs Outdated

@sebcrozet sebcrozet added this to the v0.17 milestone Dec 9, 2018

@sebcrozet sebcrozet merged commit 5a9a1eb into rustsim:master Dec 29, 2018

1 check passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details
@sebcrozet

This comment has been minimized.

Copy link
Member

sebcrozet commented Dec 29, 2018

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment