
# The xtensor library

Today's [assignment](https://classroom.github.com/a/H7L0WMgn).

## Introduction

So hopefully you've seen from my previous linear_algebra -> C++ class that it is
possible to write quite nice looking code dealing with vectors and matrices in
C++. But you've probably also noticed that while it's fairly easy to use
`vector` and `matrix`, it's much less straightforward to implement those classes
(which I've only partially done).

It's generally nice if one can use other people's code, rather than having to
write one's own. So in this class, I will use the
[xtensor](https://xtensor.readthedocs.io/en/latest/) library going forward,
which provides one- and multi-dimensional arrays in C++. It's a pretty
feature-rich library, which gives C++ python/numpy-style arrays, though we'll
probably only use some fraction of its capabilities.

[Note: xtensor is one of many libraries that add multi-d support to C++ -- it's
a bit unfortunate that there isn't **one** way to do multi-d arrays in C++, but many
different ones. That's a consequence of C++ not providing support for multi-d
arrays natively. C++23 introduced `std::mdspan`, which partially starts to
address this issue.]

I did the work in what ends up your assignment repo, so you should see my commits in your
repo after you sign up. But I'm also linking my work here, with some additional context on what I've done.

In a nutshell, I've added the necessary cmake build stuff to get
xtensor into the linear algebra example, and then used it to pretty much replace
my home-grown vector and matrix classes. You can see that it allowed me to
remove a bunch of code that I had written myself, to end up with something that
can do the same -- and much more.

### Using xtensor to implement `vector` and `matrix`

* The starting point is the linear algebra code after Tuesday's homework: [b39e981](https://github.com/UNH-HPC-2026/unh-hpc-2026-class-12-xtensor-class-12/commit/b39e98146b590be62e79e1015cff70cb9eac861e)

* In [165dde](https://github.com/UNH-HPC-2026/unh-hpc-2026-class-12-xtensor-class-12/commit/165ddecf387a9f35004cf4c6fb604b7ca157d3fa), I turned my linear algebra library into what's called a "header only library". This is a common way to distribute C++ libraries, and it means that the library consists of just header files, and no separate compilation is needed. As with everything, this has its good and bad parts. It definitely avoids some hassles associated with compiled libraries, where one needs to make sure that the compiled binaries are compatible with whatever C++ compiler is later used to compile the code that is using the library. It also kinda goes against the spirit of C/C++ libraries, where part of the idea is that it's already ready made for use (in particular, compiled), and one just needs to link to it, speedings things up as one doesn't need to recompile the library every time. In any case, it's frequently done in modern C++, as its more or less the only way to distribute template libraries, which need to be compiled according to how they are used. 

  Another maybe more minor drawback of header only libraries is that the class definition and implementation are not separated, which can make it a bit harder to read. This can be mitigated, though, of one cares for it.

* [43bacb8](https://github.com/UNH-HPC-2026/unh-hpc-2026-class-12-xtensor-class-12/commit/43bacb809fbd11d36b2aecdda0a4b508affeb2c3) then shows the reason why I made the library header only -- I changed the `vector` class to be templated by the value type. That is another useful feature in C++ -- one may want to not only store vectors made up of double precision numbers, but also single precision, or even integers. By making the class templated, we can use the same code to create vectors of any type. However, this also means that the implementation of the class needs to be available at the time of compilation, which is why I put it all in the header. It means we know have to use `vector<double>` instead of just `vector`, but that's not too bad.

* In [a121c3](https://github.com/UNH-HPC-2026/unh-hpc-2026-class-12-xtensor-class-12/commit/a121c3a5a681aa286f87bd62f6bce3053b000dd4), I did the same thing for the `matrix` class.

* In [a4df6ec](https://github.com/UNH-HPC-2026/unh-hpc-2026-class-12-xtensor-class-12/commit/a4df6ec5c2ba05772d4d91804df6d82823f9ed38), we're finally getting ready for using xtensor, but we're still not quite there. I added the necessary cmake code to download and build xtensor as needed, but I haven't yet changed the `vector` and `matrix` classes to use xtensor.

  As with pulling in googletest, instead of using cmake's built-in capabilities directly to deal with downloading
stuff on demand, I've used a little project called
[CPM](https://github.com/cpm-cmake/CPM.cmake) that makes life a bit easier. It
does require downloading the `cmake/CPM.cmake` file and including it within the
repository, which I've already done.


* At long last, in [c478cb9](https://github.com/UNH-HPC-2026/unh-hpc-2026-class-12-xtensor-class-12/commit/c478cb9e0bdb765da2223c9422ed549139f5393a), I'm starting to actually use xtensor. I changed the `vector` class to just be a type alias for `xt::xtensor<T, 1>`, which is the xtensor type for 1-d arrays. For the most part, the rest of the code remained unchanged, with the exception of the construction of the `vector` objects, which is a bit different with xtensor. I used to have, e.g., `vector<double> x(3);` to mean construct a vector of length 3, but with xtensor, this would actually give me a vector of length 1, with its single element being 3. Instead, I now use `vector<double> x(xt::shape({3}));`, where I'm explicitly telling xtensor that "3" is the shape (dimension) of the vector, not its values.

* I then again did the same thing for the `matrix` class in [fe3d3c5](https://github.com/UNH-HPC-2026/unh-hpc-2026-class-12-xtensor-class-12/commit/fe3d3c5475dfd03c7d414e6b956ef339b68e3372). While it would have been fine to do this switch of `vector` and `matrix` to xtensor at the same time, I wanted to do it in two steps, so that it's easier to see what changed for each of them.

* After a little clean-up, in [7985222](https://github.com/UNH-HPC-2026/unh-hpc-2026-class-12-xtensor-class-12/commit/7985222bb757c585e42d922ecc840b81c77ed382) I took advantage of xtensor allowing me to concisely create and initialize vectors and matrices, which allowed me to remove a bunch of code that I had written myself to do the same thing. This definitely makes the testing code much more concise and readable.

* Of course, there's a lot more that xtensor can do. As a small example, I used `xt::sum` in [b28b69d](https://github.com/UNH-HPC-2026/unh-hpc-2026-class-12-xtensor-class-12/commit/b28b69d50d013f41de2b338986fa309cbf14679d) to simplify the (vector) dot product code.


I kept my own implementations for the various `dot` implementations. That's because xtensor itself is a multi-d array package, not
  really a linear algebra package, and so its core doesn't include this kind of linear algebra operations. However, I could have gone and used
  [xtensor-blas](https://xtensor-blas.readthedocs.io/en/latest/) which adds on
  linear algebra capabilities. For the most part, for the rest of the class
  we'll primarily need multi-d arrays, not necessarily much linear algebra, so
  xtensor is what I do care about at this point, and I didn't want to pull in
  yet more external dependencies.

#### Your turn

- Code up and run the four examples from
  [xtensor's Getting Started](https://xtensor.readthedocs.io/en/latest/getting_started.html).

As you do this, keep track (copy & paste) of the output and write notes into
your Feedback github pull request. Also make commits for each example (each
should be a separate source file / executable).

The "Getting Started" page does tell you how to build with cmake, however that
assumes that xtensor and xtl are already installed on the machine you're using
(and that cmake can find it). As described above, I've already set up the assignment repo to download xtensor and xtl, so you can use xtensor by just linking to it, e.g.,

```
target_link_libraries(my_example PUBLIC
    xtensor
)
```

So for this work, you can just add the examples from the xtensor documentation
to a new subdirectory in your repository and make your own `CMakeLists.txt` following the above.

**Note**: The `xtensor` instructions say to add `xtensor::optimize` and
`xtensor::use_xsimd` to `link_libraries()`. This doesn't quite work the same way
if using a cmake-downloaded `xtensor`, but it's not important for those tests
to be that optimized, either, so you can just disregard these options. The MSVC
specific stuff can also be skipped.

## Homework

- Finish adding the four xtensor examples to the repo, test them, and write
  notes about how they worked and what you learned from it.
- Optionally, see if you can get `xsimd` and/or `xtensor-blas` working in your repo and make use of them.
