I'm in the middle of building the xtensor example "structures that embed shape and strides", to use it for an image class with its own header information. I have got as far as this:
#include <xtensor/xadapt.hpp>
#include <xtensor/xstrides.hpp>
// see https://github.com/xtensor-stack/xtensor/blob/master/docs/source/external-structures.rst
template <class T>
struct raw_tensor {
using container_type = std::vector<T>;
using shape_type = std::vector<std::size_t>;
container_type
m_data;
shape_type
m_shape,
m_strides,
m_backstrides;
static constexpr xt::layout_type
layout = xt::layout_type::dynamic;
};
template <class T>
class raw_tensor_adaptor;
template <class T>
struct xt::xcontainer_inner_types<raw_tensor_adaptor<T>> {
using container_type = typename raw_tensor<T>::container_type;
using inner_shape_type = typename raw_tensor<T>::shape_type;
using inner_strides_type = inner_shape_type;
using inner_backstrides_type = inner_shape_type;
using shape_type = inner_shape_type;
using strides_type = inner_shape_type;
using backstrides_type = inner_shape_type;
static constexpr layout_type layout = raw_tensor<T>::layout;
};
template <class T>
struct xt::xiterable_inner_types<raw_tensor_adaptor<T>>
: xcontainer_iterable_types<raw_tensor_adaptor<T>> {
};
template <class T>
class raw_tensor_adaptor : public xt::xcontainer<raw_tensor_adaptor<T>>,
public xt::xcontainer_semantic<raw_tensor_adaptor<T>> {
public:
using self_type = raw_tensor_adaptor<T>;
using base_type = xt::xcontainer<self_type>;
using semantic_base = xt::xcontainer_semantic<self_type>;
raw_tensor_adaptor(const raw_tensor_adaptor&) = default;
raw_tensor_adaptor& operator=(const raw_tensor_adaptor&) = default;
raw_tensor_adaptor(raw_tensor_adaptor&&) = default;
raw_tensor_adaptor& operator=(raw_tensor_adaptor&&) = default;
template <class E>
raw_tensor_adaptor(const xt::xexpression<E>& e) : base_type() {
semantic_base::assign(e);
}
template <class E>
self_type& operator=(const xt::xexpression<E>& e) {
return semantic_base::operator=(e);
}
};
int main() {
raw_tensor<double> i,j,k; // this works
using tensor_type = raw_tensor_adaptor<double>;
// tensor_type a, b, c; // but not this if un-commented
// .... init a, b, c
// tensor_type d = a + b - c; raw_tensor < int > a;
return 0;
}
With a main()
function that just declares objects of class raw_tensor<double>
, compilation finishes without errors.
On linux (with gcc-11) I can (re-)run this example by doing:
$ cd /tmp && mkdir -p xtensor-test && cd xtensor-test
$ git clone https://github.com/xtensor-stack/xtensor.git
$ git clone https://github.com/xtensor-stack/xtl.git
$ vi xtensor-test.cpp # insert the code block above and save
$ g++ -o xtensor-test xtensor-test.cpp -Ixtensor/include -Ixtl/include
However, I cannot do these things:
resize()
or accessor methods: when I add the resize()
functions (without template parameter T
) inside the class, this does not work because inner types and members shape_type
, m_shape
etc. are unknown. But this is the only place to overload resize()
, right?using tensor_type = raw_tensor_adaptor<double>;
tensor_type a, b, c;
When I declare these adaptors, the a, b, c
line generates these errors:
include/xtensor/xiterable.hpp:288:19: error: no type named 'xexpression_type' in 'struct xt::xcontainer_inner_types<raw_tensor_adaptor<double> >’
include/xtensor/xaccessible.hpp:35:15: error: no type named 'reference' in 'struct xt::xcontainer_inner_types<raw_tensor_adaptor<double> >’
include/xtensor/xaccessible.hpp:36:15: error: no type named 'const_reference' in 'struct xt::xcontainer_inner_types<raw_tensor_adaptor<double> >’
include/xtensor/xaccessible.hpp:37:15: error: no type named 'size_type' in 'struct xt::xcontainer_inner_types<raw_tensor_adaptor<double> >’
include/xtensor/xaccessible.hpp:47:48: error: no type named 'const_reference' in 'struct xt::xcontainer_inner_types<raw_tensor_adaptor<double> >’
include/xtensor/xaccessible.hpp:111:26: error: 'at' has not been declared in 'using base_type = class
include/xtensor/xaccessible.hpp:112:35: error: 'operator[]' has not been declared in 'using base_type = class xt::xconst_accessible<raw_tensor_adaptor<double> >’ {aka ‘class xt::xconst_accessible<raw_tensor_adaptor<double> >’}
include/xtensor/xaccessible.hpp:113:26: error: 'back' has not been declared in 'using base_type = class xt::xconst_accessible<raw_tensor_adaptor<double> >’ {aka ‘class xt::xconst_accessible<raw_tensor_adaptor<double> >’}
include/xtensor/xaccessible.hpp:114:26: error: 'front' has not been declared in 'using base_type = class xt::xconst_accessible<raw_tensor_adaptor<double> >’ {aka ‘class xt::xconst_accessible<raw_tensor_adaptor<double> >’}
include/xtensor/xaccessible.hpp:115:26: error: 'periodic' has not been declared in 'using base_type = class xt::xconst_accessible<raw_tensor_adaptor<double> >’ {aka ‘class xt::xconst_accessible<raw_tensor_adaptor<double> >’}
include/xtensor/xcontainer.hpp:79:15: error: no type named 'storage_type' in 'struct xt::xcontainer_inner_types<raw_tensor_adaptor<double> >'
include/xtensor/xcontainer.hpp:80:15: error: no type named 'storage_type' in 'struct xt::xcontainer_inner_types<raw_tensor_adaptor<double> >'
include/xtensor/xcontainer.hpp:82:15: error: no type named 'reference' in 'struct xt::xcontainer_inner_types<raw_tensor_adaptor<double> >'
include/xtensor/xcontainer.hpp:83:15: error: no type named 'const_reference' in 'struct xt::xcontainer_inner_types<raw_tensor_adaptor<double> >'
include/xtensor/xcontainer.hpp:86:15: error: no type named 'size_type' in 'struct xt::xcontainer_inner_types<raw_tensor_adaptor<double> >'
include/xtensor/xcontainer.hpp:88:15: error: no type named 'storage_type' in 'struct xt::xcontainer_inner_types<raw_tensor_adaptor<double> >'
include/xtensor/xcontainer.hpp:89:15: error: no type named 'storage_type' in 'struct xt::xcontainer_inner_types<raw_tensor_adaptor<double> >'
include/xtensor/xcontainer.hpp:107:15: error: no type named 'storage_type' in 'struct xt::xcontainer_inner_types<raw_tensor_adaptor<double> >'
include/xtensor/xcontainer.hpp:108:15: error: no type named 'storage_type' in 'struct xt::xcontainer_inner_types<raw_tensor_adaptor<double> >'
include/xtensor/xcontainer.hpp:140:32: error: 'at' has not been declared in 'using accessible_base = class xt::xaccessible<raw_tensor_adaptor<double> >’ {aka ‘class xt::xaccessible<raw_tensor_adaptor<double> >’}
include/xtensor/xcontainer.hpp:141:32: error: 'shape' has not been declared in 'using accessible_base = class xt::xaccessible<raw_tensor_adaptor<double> >’ {aka ‘class xt::xaccessible<raw_tensor_adaptor<double> >’}
include/xtensor/xcontainer.hpp:142:41: error: 'operator[]' has not been declared in 'using accessible_base = class xt::xaccessible<raw_tensor_adaptor<double> >’ {aka ‘class xt::xaccessible<raw_tensor_adaptor<double> >’}
include/xtensor/xcontainer.hpp:143:32: error: 'back' has not been declared in 'using accessible_base = class xt::xaccessible<raw_tensor_adaptor<double> >’ {aka ‘class xt::xaccessible<raw_tensor_adaptor<double> >’}
include/xtensor/xcontainer.hpp:144:32: error: 'front' has not been declared in 'using accessible_base = class xt::xaccessible<raw_tensor_adaptor<double> >’ {aka ‘class xt::xaccessible<raw_tensor_adaptor<double> >’}
include/xtensor/xcontainer.hpp:146:32: error: 'periodic' has not been declared in 'using accessible_base = class xt::xaccessible<raw_tensor_adaptor<double> >’ {aka ‘class xt::xaccessible<raw_tensor_adaptor<double> >’}
include/xtensor/xcontainer.hpp:182:15: error: no type named 'storage_type' in 'struct
include/xtensor/xsemantic.hpp:64:15: error: no type named 'temporary_type' in 'struct xt::xcontainer_inner_types<raw_tensor_adaptor<double> >’
from the xtensor
headers and
xtensor-test.cpp:70:13: error: no matching function for call to ‘raw_tensor_adaptor<double>::raw_tensor_adaptor()’
tensor_type a, b, c; // but not this if un-commented
^
xtensor-test.cpp:55:5: note: candidate: ‘template<class E> raw_tensor_adaptor<T>::raw_tensor_adaptor(const xt::xexpression<E>&)’
raw_tensor_adaptor(const xt::xexpression<E>& e) : base_type() {
^~~~~~~~~~~~~~~~~~
xtensor-test.cpp:55:5: note: template argument deduction/substitution failed:
xtensor-test.cpp:70:13: note: candidate expects 1 argument, 0 provided
tensor_type a, b, c; // but not this if un-commented
^
xtensor-test.cpp:51:5: note: candidate: ‘raw_tensor_adaptor<T>::raw_tensor_adaptor(raw_tensor_adaptor<T>&&) [with T = double]’
raw_tensor_adaptor(raw_tensor_adaptor&&) = default;
^~~~~~~~~~~~~~~~~~
xtensor-test.cpp:51:5: note: candidate expects 1 argument, 0 provided
xtensor-test.cpp:49:5: note: candidate: ‘raw_tensor_adaptor<T>::raw_tensor_adaptor(const raw_tensor_adaptor<T>&) [with T = double]’
raw_tensor_adaptor(const raw_tensor_adaptor&) = default;
^~~~~~~~~~~~~~~~~~
xtensor-test.cpp:49:5: note: candidate expects 1 argument, 0 provided
xtensor-test.cpp:49:5: note: candidate: ‘raw_tensor_adaptor<T>::raw_tensor_adaptor(const raw_tensor_adaptor<T>&) [with T = double]’
raw_tensor_adaptor(const raw_tensor_adaptor&) = default;
^~~~~~~~~~~~~~~~~~
from the .cpp
file
The web page says to define the semantics and implement the methods and functions that are specific to the raw_tensor struct. But I have the feeling that I'm doing that in the wrong place.
Has anyone got this example to work with an instance of raw_tensor_adaptor? Many thanks!
I wanted to use this example to make a class for NIfTI images, of brain scans that can be 2D, 3D or 4D (the data type allows up to 7D). Information about spatial orientation etc. is given in a header, and it looked to me that a class with all the functionality of xtensor, but also with the header information still atached, would be ideal.
Looking at the default Python way of accessing these files (with nibabel) made me realise that it is more useful to have a class that has both the header and the pixel data as separate properties, and mathematical operations are better done on the pixel data (as an xtensor object) outside of the nifti object. This class does not inherit from xtensor, which keeps many things a lot simpler for everyone.