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

shape operator[] and index() members #18

Closed
3 tasks done
psiha opened this issue May 3, 2022 · 38 comments · Fixed by #31
Closed
3 tasks done

shape operator[] and index() members #18

psiha opened this issue May 3, 2022 · 38 comments · Fixed by #31
Labels
enhancement New feature or request

Comments

@psiha
Copy link
Contributor

psiha commented May 3, 2022

hi @jfalcou, finally back to trying to integrate kiwaku ;)
missing some interfaces, would it be possible to add:

  • the ability to access values of individual shape dimensions with constexpr operator[] instead of/in addition to with the get<>() template member function - so that it works for runtime/dynamic and static arguments

  • add an index() or offset() member function that returns a linear/flattened index or offset for a given set of coordinates, i.e. generalized equivalent of
    `std::uint32_t Dimensions::index( shape_t const dim0, shape_t const dim1, shape_t const dim2, shape_t const dim3 ) const noexcept
    {
    BOOST_ASSERT( dim0 < (*this)[ 0 ] );
    BOOST_ASSERT( dim1 < (*this)[ 1 ] );
    BOOST_ASSERT( dim2 < (*this)[ 2 ] );
    BOOST_ASSERT( dim3 < (*this)[ 3 ] );

    std::uint32_t const result( ( ( dim0 * (*this)[ 1 ] + dim1 ) * (*this)[ 2 ] + dim2 ) * (*this)[ 3 ] + dim3 );
    BOOST_ASSERT( result < count() );
    return result;
    }`

  • also 🙈 maybe behind a 'EIGEN_INTEROP' define
    // implicit conversion to Eigen Tensor dimensions w/o Eigen includes
    constexpr operator std::array< int, 4 >() const noexcept;

------------ [EDIT JFALCOU]
Other element has been put in their own issues:

@psiha psiha added the enhancement New feature or request label May 3, 2022
@jfalcou
Copy link
Owner

jfalcou commented May 3, 2022

The first point is complicated. The shape interface is meant to have a tuple cause we can't have people write silly things like:

auto s = of_size(4_c, 8);
s[0] = 7; 

We can maybe have a read-only operator[] but mutable [] is a bit meh.

The second point, I don't get what you're computing, can you clarify? Is it the computation of a linear index from an nD position and a shape ?

@jfalcou
Copy link
Owner

jfalcou commented May 3, 2022

Also note we're still hammering out the API, so can't really make any binding promise before v0.1

@psiha
Copy link
Contributor Author

psiha commented May 4, 2022

yes, read-only is perfectly fine! :)

second point - yes that's what i need

@jfalcou
Copy link
Owner

jfalcou commented May 4, 2022

Ok for 1.
For 2. We re going to need some position class to do just that so the index(...) is coming.
If you need it, we will add it soon.

@psiha
Copy link
Contributor Author

psiha commented May 4, 2022

yes, i need it, soon ;D
but you don't 'need' a position class - you can make index a variadic template and/or accept an initializer list and/or an array...

@jfalcou
Copy link
Owner

jfalcou commented May 4, 2022

Sorry typing from phone. I mean we need such a function for our position thing. We can add the other variadic interface too.

@psiha
Copy link
Contributor Author

psiha commented May 4, 2022

also nice to have would be the inverse of index() -> coordinates_from_index()

@jfalcou
Copy link
Owner

jfalcou commented May 4, 2022

Smell like modulos :p

@psiha
Copy link
Contributor Author

psiha commented May 4, 2022

oh yes...modulos...more powerful than qovid (loss of smell) :D

@psiha
Copy link
Contributor Author

psiha commented May 5, 2022

  • also a generalized numel() that counts the volume of a slice - taking start_axis and end_axis parameters

@psiha
Copy link
Contributor Author

psiha commented May 5, 2022

  • also 🙈 maybe behind a 'EIGEN_INTEROP' define
    // implicit conversion to Eigen Tensor dimensions w/o Eigen includes
    constexpr operator std::array< int, 4 >() const noexcept;

@jfalcou
Copy link
Owner

jfalcou commented May 5, 2022

also a generalized numel() that counts the volume of a slice - taking start_axis and end_axis parameters

This will be part of the slicing interface.

@jfalcou
Copy link
Owner

jfalcou commented May 5, 2022

also 🙈 maybe behind a 'EIGEN_INTEROP' define // implicit conversion to Eigen Tensor dimensions w/o Eigen includes constexpr operator std::array< int, 4 >() const noexcept;

Not a fan of implicit conversion to low semantic type.
A as_array member is doable.

@psiha
Copy link
Contributor Author

psiha commented May 5, 2022

also 🙈 maybe behind a 'EIGEN_INTEROP' define // implicit conversion to Eigen Tensor dimensions w/o Eigen includes constexpr operator std::array< int, 4 >() const noexcept;

Not a fan of implicit conversion to low semantic type. A as_array member is doable.

not a fan of 'explicit interop' ;P
oh well minor issue now...

@psiha
Copy link
Contributor Author

psiha commented May 5, 2022

Also something more exotic like fits_static_constraints - a function that compares a 'less static' (dynamic_shape) with a 'more static' (reference_shape) shape by comparing/verifying that corresponding dimensions from dynamic_shape are equal to the corresponding statically defined/fixed dimensions from reference_shape...
for example
dynamic_shape = extent()()()()
reference_shape = extent()[100]200

bool fits_static_constraints() { return ( dynamic_shape[1] == reference_shape[1] ) && ( dynamic_shape[2] == reference_shape[2] ); }

This would be used in __builtin_assume() statements to tell the optimizer what it can assume about a given dynamic shape. For this to work (without compiler warnings about 'lost sideeffects') the function has to be marked with attribute(( const )) (or attribute(( pure )) for member functions, due to the access of this)...In general it would be helpful if you could make it a practice to slap those attributes on all appropriate functions (at least constexpr ones should be no brainers)..

@jfalcou
Copy link
Owner

jfalcou commented May 5, 2022

This can be done by extending the contains and strictly contains member. Wonder if slapping the attribute on the == operator is enough.

@psiha
Copy link
Contributor Author

psiha commented May 5, 2022

operator== would compare all the dimensions while i want only the static ones used to verify the corresponding dynamic ones...
(regardless of that, a member operator== is a classic candidate for the pure attribute)

@psiha
Copy link
Contributor Author

psiha commented May 6, 2022

as an aside - pure and const attributes in general help the optimizer with things like subexpr elimination - for example it should be smart enough to see that shape::nbdims() can be hoisted outside a loop if the shape isn't modified but explicitly marking it so ensures it and speeds up that compilation pass (i.e. it can skip this analysis)

@psiha
Copy link
Contributor Author

psiha commented May 9, 2022

hm - speaking of read-only operator[] - how do you currently change a shape (i.e. the value/size of one of the dimensions)?

@jfalcou
Copy link
Owner

jfalcou commented May 9, 2022

you currently dont. I am looking at how to make that proper.

Longer answer with a proper keyboard:

  • is changing one piece of shape out context meaningful or should we have modifier functions/operators
  • what to do when Bobby Tables try to change a fixed elements ? assert ?

@psiha
Copy link
Contributor Author

psiha commented May 9, 2022

  • is changing one piece of shape out context meaningful or should we have modifier functions/operators

well it is certainly something 'people are used to doing' with other frameworks - but i can try and see how far can i get trying to make our code not rely on that (treating the entire shape as a single value that has to be changed when you want a resize)

  • what to do when Bobby Tables try to change a fixed elements ? assert ?

well as always - not having the ability to do it in the first place (function removed by concepts) is the best, static assert is next and runtime assert the fallback solution..
(and throwing an exception if being compiled by committee members :trollface: )

@jfalcou
Copy link
Owner

jfalcou commented May 9, 2022

  1. Yes I know but I wanted to see how far we can go before bowing to peer pressure. If it is required for usability, let's do it.

  2. well concept removal for get is doable, I was thinking of the runtime [].

@psiha
Copy link
Contributor Author

psiha commented May 9, 2022

hm - back to index() - do i see correctly that the stride class provides that - so converting a shape to stride and calling index would get me what i want?

@jfalcou
Copy link
Owner

jfalcou commented May 9, 2022

yup, and to convert a shape to a stride, use shape::as_stride()
I still think the index() thing is warranted.

@psiha
Copy link
Contributor Author

psiha commented May 9, 2022

ok thanks, any documentation/video on explaining the stride thing - how it differs from/constructs from/complements shape?

@jfalcou
Copy link
Owner

jfalcou commented May 9, 2022

@jfalcou
Copy link
Owner

jfalcou commented May 9, 2022

Note that the strides also simplify extraction of subviews and storage order handling
https://youtu.be/IwBG_JjfcIA?list=PLyvPkeRjsYco_sUGIupgEu65igFNVu72k&t=5157

@psiha
Copy link
Contributor Author

psiha commented May 10, 2022

I still think the index() thing is warranted.

yes - including the position class - or using a shape instance as a position

I think I explain it there:

thanks joel!

Note that the strides also simplify extraction of subviews and storage order handling

yes i saw that, it's great - however is it finished/operational? saw some commented-out code related to slicing..?

@jfalcou
Copy link
Owner

jfalcou commented May 10, 2022

We are going to revamp the slicer API. the PoC worked so it's a matter of clean up. It is also related to the "waht is the shape when I took this shape and slice it ?" I think having slicing API on everything solves the thing properly.

Number of element in the slice of smade of all the rows and 1 over 2 columns ? s(all, by(2)).numel()

@jfalcou
Copy link
Owner

jfalcou commented May 15, 2022

shape::as_array in #27

@jfalcou
Copy link
Owner

jfalcou commented May 15, 2022

shape::operator[] in #28

@jfalcou
Copy link
Owner

jfalcou commented May 15, 2022

Found a way to make get and operator[] works for mutating values when possible and to assert/static_assert if not.
This should fix the "how do I change shape" scenario

@psiha
Copy link
Contributor Author

psiha commented May 16, 2022

Found a way to make get and operator[] works for mutating values when possible and to assert/static_assert if not. This should fix the "how do I change shape" scenario

great, however this (mutable access) is not something you've added yet (as it does not work yet)?

@jfalcou
Copy link
Owner

jfalcou commented May 16, 2022

The PR is running atm

@jfalcou
Copy link
Owner

jfalcou commented May 16, 2022

#29

@jfalcou
Copy link
Owner

jfalcou commented May 16, 2022

now it's merged ;)

@jfalcou
Copy link
Owner

jfalcou commented May 16, 2022

linear_index is landing in #31
So any comments are welcome. It includes API for a variadic pack, tuple, and range of indexes.
When base_index and layout order land later, I'll amend it to support those.

@jfalcou
Copy link
Owner

jfalcou commented May 17, 2022

Closing this for its initial purpose.
Remaining features moved to specific issues.

@jfalcou jfalcou closed this as completed May 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants