xtensor-stack / xtensor-python

Python bindings for xtensor
BSD 3-Clause "New" or "Revised" License
345 stars 58 forks source link

Can't reshape pyarray with shape of different input type #144

Closed iamthebot closed 6 years ago

iamthebot commented 6 years ago

Looks like #120 still isn't fixed as of latest xtensor-python master (w/ xtensor 0.15.9).

Taking the result of xt::pyarray<float>.shape() and calling reshape(<that value>) on another array produces the following error

In file included from ?
warning: narrowing conversion of '((const xt::xcontainer<xt::pyarray<float> >*)(& x))->xt::xcontainer<xt::pyarray<float> >::size()' from 'xt::xcontainer<xt::pyarray<float> >::size_type {aka long unsigned int}' to 'double' inside { } [-Wnarrowing]
           auto out = xt::pyarray<double>({x.size()});
                      ^~~~~
warning: narrowing conversion of '((const xt::xcontainer<xt::pyarray<float> >*)(& x))->xt::xcontainer<xt::pyarray<float> >::size()' from 'xt::xcontainer<xt::pyarray<float> >::size_type {aka long unsigned int}' to 'double' inside { } [-Wnarrowing]
 #define BH_TT xt::pyarray
           auto out = xt::pyarray<double>({x.size()});
                      ^~~~~
...
.../xtensor-python/include/xtensor-python/pycontainer.hpp:345:30: error: reinterpret_cast from type 'xt::detail::xbuffer_storage<long unsigned int*, std::allocator<long unsigned int> >::const_pointer {aka const long unsigned int*}' to type 'npy_intp* {aka long int*}' casts away qualifiers
         PyArray_Dims dims = {reinterpret_cast<npy_intp*>(shape.data()), static_cast<int>(shape.size())};

I'm using GCC7.

Similarly, instantiating a new pyarray using the shape of another array fails with the following error:

error: no matching function for call to 'xt::pyarray<double>::pyarray(const inner_shape_type&)'
wolfv commented 6 years ago

Hi @iamthebot

this is actually a corner-case with the initializer lists that we have. Initialization from initializer list is used to create the array, e.g. xt::pyarray<double> a({{1,2,3}, {4,5,6}}); will create a pyarray with shape {2, 3} and the values inside. To easily use initializer lists for the shape to create xarrays etc, we have added the named constructor as follows: auto a = xt::pyarray<double>::from_shape({3, 3}); which returns the array with correct shape. As the syntax is a little verbose, we have also added the xt::empty({3,3}); function which will come in xtensor 0.16 (however, in this case it would actually return a xtensor, as it can infer that {3, 3} has 2 dimensions at compile time.

You can also force the shape-overload by constructing a shape type in the constructor call pyarray<double> a(std::vector<std::size_t>{1,2,3,4}); should work.

And your last error ... we actually have "two" shape types in xtensor python: one "inner" which wraps the numpy shape, and one "outer" which is the std::vector. Currently we only have a constructor from the std::vector shape type. If you use the from_shape overload it should be fine.


It looks like we haven't added the from_shape static constructors to pyarray / pytensor yet! Sorry about that!! I'm filing a bug for that, it should land in the next release for sure! So the current workaround is probably

xt::pyarray<double> a; a.reshape(b.shape());