Search code examples
c++stlstdvectorxtensoradaptor

Is it possible to resize an xarray adaptor of a vector?


After seeing the example of xtensor matrix adaptors of 1D containers, I was wondering if it is also possible to have a resizeable adaptor of STL containers like vectors.

In the process, I would like to also find out and use the type of such an adaptor, instead of using auto.

Starting with the C-style array adaptor and compute() function --which multiplies the 2x1 row vector with a 2x1 column and returns the xarray as a 2x2 matrix-- I got as far as

#include <cstddef>
#include <xtensor/xarray.hpp>
#include <xtensor/xadapt.hpp>

template <class A>
void compute ( A& a ) {
    xt::xarray<double> b {1., 2.};
    b.reshape({2, 1});
    a = a * b; // size has changed, shape is now { 2, 2 }
}

int main() {
    std::size_t size = 2;

    ////////////////////////////////////////////////////////////////
    double* datavx = new double [ size ];
    
    for ( unsigned i = 0; i < size; i++ )
        datavx [ i ] = i;
    
    std::vector<std::size_t>   shapevx = { size };
    std::vector<std::size_t> stridesvx = { 1 };
    
    auto vx = xt::adapt ( datavx, size, xt::acquire_ownership(), shapevx, stridesvx );
    
    std::cout << "\nbefore reshape\n";
    for ( unsigned i = 0; i < size; i++ )
        std::cout << datavx [ i ] << " ";
    compute ( vx );
    std::cout << "\nafter reshape\n";
    for ( unsigned i = 0; i < size * size; i++ )
        std::cout << datavx [ i ] << " ";

    ////////////////////////////////////////////////////////////////
    std::vector<double> datav (size);
    for (unsigned i = 0; i < size; i++)
        datav[i] = i;

    std::vector<std::size_t> shapev = shapevx;
    std::vector<std::size_t> stridesv = stridesvx;

    using shape_type = std::vector<size_t>;
    using adaptor_typev = xt::xarray_adaptor<xt::xbuffer_adaptor<double*, xt::acquire_ownership>, xt::layout_type::dynamic, shape_type >;
    adaptor_typev my_adaptorv = xt::adapt(datav.data(), size, xt::acquire_ownership(), shapev, stridesv);
    std::cout << "\n";
    
    std::cout << "\nbefore reshape\n";
    for (unsigned i = 0; i < size; i++)
        std::cout << datav[i] << " ";
    compute(my_adaptorv);
    std::cout << "\nafter reshape\n";
    for (unsigned i = 0; i < size * size; i++)
        std::cout << datav[i] << " ";

    std::cout << std::endl;
    // prints 0 1 0 2

}

The output that I get from the C-style xarray_adaptor (from the xtensor website) and the std:vector xarray_adaptor, respectively, is:

before reshape
0 1
after reshape
0 1 0 2

before reshape
0 1
after reshape
0 1 nan -5.11336e-311

==== Program exited with exit code: 3221226356 ====
Time elapsed: 000:00.016 (MM:SS.MS)

The last two values suggest that the resize has not happened, and the non-zero exit code shows all is not well. If I run it in the debugger, it exits with a SIGTRAP at the end of main(). The top of the call stack says ntdll!RtllsZeroMemory.

Does that mean that to resize an xarray adaptor of an std::vector, I need to resize the vector separately? Or is there a way to do it without trying to become owner of the vector's data (that does not sound right to begin with)?


Solution

  • The comments by @JaMit and @IgorTandetnik helped me in the right direction -- I did need an adaptor of a vector not a C-style array.

    But the examples with vector adaptors all used auto declarations and I still wanted to know the type of the adaptor.

    An old answer on StackOverflow allowed me to combine the two: this bit of code shows the type of the adaptor, which I then used to do the declaration 'manually'.