Hypercube with multidimensional vectors - c++

I'm trying to implement a hypercubeclass, that is, multidimensional vectors.
I have a problem generalizing it. I'm able to make one for a three dimensional hypercube, but as mentioned, the problem is generalizing it. Could anyone help me? You should be able to write hypercube<4> w(5) to get 4 dimensions and 5 elements in each vector that is 5*5*5*5 elements in total.
Here is the code I have for the three dimensional version:
#include <vector>
using std::vector;
using namespace std;
template <int b>
class Hypercube {
public:
Hypercube(int a) : intvec(a){
for (int i = 0; i<a;i++) {
intvec[i].resize(a);
for (int j = 0;j<a;j++) {
intvec[i][j].resize(a);
}
}
}
vector<vector<int> >& operator[](int i) {
return intvec[i];
}
vector<vector<vector<int> > > intvec;
};

For this to work, you need recursive inheritence to provide the correct vector type and the initialization function. Both work recursively, for which I created a little helper struct called hcube_info:
// hypercube.h
#include <vector>
template<unsigned N>
struct hcube_info;
template<>
struct hcube_info<1>
{ // base version
typedef std::vector<int> type;
static type init(unsigned innerdim, int value = 0){
return type(innerdim, value);
}
};
template<unsigned N>
struct hcube_info
{ // recursive definition, N dimensions
private:
typedef hcube_info<N-1> base;
typedef typename base::type btype;
public:
typedef std::vector<btype> type;
static type init(unsigned innerdim, int value = 0){
return type(innerdim, base::init(innerdim, value));
}
};
As you can see, recursion all the way to the one dimensional base case. We also need to recursively initialize the vector to pass the inner dimension all the way through.
And now the real class, a nice interface around the hcube_info:
template<unsigned N>
struct hypercube
{
private:
typedef hcube_info<N> info;
typedef typename info::type vec_type;
public:
typedef typename vec_type::value_type value_type;
typedef typename vec_type::size_type size_type;
explicit hypercube(unsigned innerdim, unsigned value = 0)
: c(info::init(innerdim, value))
{
}
value_type& operator[](unsigned i){
return c[i];
}
size_type size() const{ return c.size(); }
private:
vec_type c;
};
Test program:
#include "hypercube.h"
#include <iostream>
int main(){
hypercube<4> c(5);
unsigned s = c.size() * // dim 1
c[0].size() * // dim 2
c[0][0].size() * // dim 3
c[0][0][0].size(); // dim 4
std::cout << s << '\n'; // outputs: 625 -> 5 * 5 * 5 * 5 -> 5^4
}

I would suggest something along those lines:
template <typename T, unsigned dim> class HQ {
std::vector<HQ<T,(dim-1)> > vector;
public:
HQ(unsigned size) : vector(size,HQ<T,(dim-1)>(size)) {}
};
template <typename T> class HQ<T,1> {
std::vector<T> vector;
public:
HQ(unsigned size) : vector(size,T()) {}
};
template <typename T> class HQ<T,0> {};
You can then implement your accessors for the first both templates as you wish. You can also make things a bit more simple and robust by allowing zero-dimensional matrices:
template <typename T, unsigned dim> class HQ {
std::vector<HQ<T,(dim-1)> > vector;
public:
HQ(unsigned size) : vector(size,HQ<T,(dim-1)>(size)) {}
};
template <typename T> class HQ<T,0> {
T data;
public:
HQ(unsigned size) : data() {}
};
I imagine an access operator would look something like this:
template <typename T, unsigned dim> HQ<T,(dim-1)>& HQ<T,dim>::operator[](unsigned i) {
return vector[i];
}
template <typename T, unsigned dim> HQ<T,(dim-1)> const& HQ<T,dim>::operator[](unsigned i) const {
return vector[i];
}
such that you can write
HQ<int,4> hq(5);
hq[1][4][2][0] = 77;

Related

How to build an efficient named array?

I want to have a type that both has named members and also is iterable, so one should be able to refer to the members by index, by label or from a for-each loop. One way to realise this would be to use std::unordered_map<std::string,T> with some helper data for the indices. Clearly this would be horribly inefficient as for each member access you need to hash a std::string.
My current attempt looks like this:
// named-array.h
#pragma once
#include <array>
#include <cstddef>
#define NamedArray_KeyDecl(Name, ...) enum class Name : std::size_t { __VA_ARGS__, NUM }
namespace util {
template <typename K, typename T>
struct NamedArray {
static constexpr std::size_t cast(K k) {
return static_cast<std::size_t>(k);
}
std::array<T,cast(K::NUM)> array;
NamedArray(std::array<T,cast(K::NUM)> a) : array(a) {
}
constexpr T& operator[](K k) {
return array[cast(k)];
}
constexpr T const& operator[](K k) const {
return array[cast(k)];
}
};
}
Which can be used like so:
struct Gadget {
int i;
Gadget(int i) : i(i) {}
void operator()() const {
std::cout << "Gadget(" << i << ")\n";
}
};
NamedArray_KeyDecl(Test1, a,b,c,d);
util::NamedArray<Test1,Gadget> gadgets {{0,1,2,3}};
// for each works:
for (auto const& gadget: gadgets.array) {
gadget();
}
// named access works:
gadgets[Test1::b]();
// access by index works:
gadgets.array[1]();
Exposing the array member could be avoided by forwarding all interface functions of std::array.
However, an obvious drawback is that
gadgets[Test1::b] is not as pretty as something along the lines of gadgets.member().b and
there is an exposed #define in a c++ header file (which is extremely smelly)
Is there a way to have a named array with the same performance as an std::array?
Minimalistic example of how it could be done:
#include <array>
#include <type_traits>
template<class Tag, class...Tags>
struct position {
};
template<class Tag, class...Tags>
struct position<Tag, Tag, Tags...> {
constexpr static unsigned value = 0;
};
template<class Tag, class First, class...Tags>
struct position<Tag, First, Tags...> {
constexpr static unsigned value = 1 + position<Tag, Tags...>::value;
};
template<class T, class...Tags>
class NamedArray {
public:
template<class U>
constexpr T& operator[](U tag) {
return array_[position<U, Tags...>::value];
}
constexpr T& operator[](unsigned val) {
return array_[val];
}
template<class U>
constexpr T& member(U u = U{}) {
return (*this)[u];
}
private:
std::array<T, sizeof...(Tags)> array_;
};
struct tag1{};
struct tag2{};
int main() {
NamedArray<int, tag1, tag2> a;
a[tag1{}];
a[tag2{}];
a.member(tag1{});
a.member<tag1>();
}
Just define the enums as you want them. And leaving them unscoped is fine, you want the names to leak into the declaration's scope, and are helped by the implicit conversion to std::size_t.
template <typename K, typename T>
using NamedArray = std::array<T, K::NUM>;
Then
struct Gadget {
int i;
Gadget(int i) : i(i) {}
void operator()() const {
std::cout << "Gadget(" << i << ")\n";
}
};
enum Test1 : std::size_t { a, b, c, d, NUM };
int main() {
NamedArray<Test1,Gadget> gadgets { 0,1,2,3 };
// for each works:
for (auto const& gadget: gadgets) {
gadget();
}
// named access works:
gadgets[b]();
// access by index works:
gadgets[1]();
}

Dynamically allocated multidimensional array using recursive templates

In order to read and store some results from a MATLAB program, I need to use up to 6 dimensional matrices. Instead of doing something like:
typedef std::vector<double> Row;
typedef std::vector<Row> Matrix2;
typedef std::vector<Matrix2> Matrix3;
typedef std::vector<Matrix3> Matrix4;
typedef std::vector<Matrix4> Matrix5;
typedef std::vector<Matrix5> Matrix6;
I decided to go with templates, and here's what I have so far:
template <class T, int N>
class Matrix {
public:
typedef typename Matrix<T, N - 1>::type MatrixOneDimLower;
typedef std::vector<MatrixOneDimLower> type;
type _data;
template <unsigned int dn, typename ...NT>
Matrix(unsigned int dn, NT ...drest) : _data(dn, MatrixOneDimLower(drest)) {}
MatrixOneDimLower& operator[](unsigned int index)
{
return _data[index];
}
};
template <class T>
class Matrix<T, 1> {
public:
typedef std::vector<T> type;
type _data;
Matrix(unsigned int d0) : _data(d0, T(0.0)) {}
T& operator[](unsigned int index)
{
return _data[index];
}
};
Unfortunately, I'm not very adept in variadic templates and recursive templates, and this doesn't work. For example, if I try to use this as:
Matrix<double, 4> temp(n, dim[2], dim[1], dim[0]);
I get this compile time error (Visual Studio 2017):
error C2661: 'Matrix<double,4>::Matrix': no overloaded function takes 4 arguments
I would really appreciate if you can let me know what I'm doing wrong.
template<class T, std::size_t I>
struct MatrixView {
MatrixView<T, I-1> operator[](std::size_t i) {
return {ptr + i* *strides, strides+1};
}
MatrixView( T* p, std::size_t const* stride ):ptr(p), strides(stride) {}
private:
T* ptr = 0;
std::size_t const* strides = 0;
};
template<class T>
struct MatrixView<T, 1> {
T& operator[](std::size_t i) {
return ptr[i];
}
MatrixView( T* p, std::size_t const* stride ):ptr(p) {}
private:
T* ptr = 0;
};
template<class T, std::size_t N>
struct Matrix {
Matrix( std::array<std::size_t, N> sizes ) {
std::size_t accumulated = 1;
for (std::size_t i = 1; i < sizes.size(); ++i) {
accumulated *= sizes[N-i];
strides[N-i] = accumulated;
}
storage.resize( strides[0] * sizes[0] );
}
MatrixView<T, N> get() { return {storage.data(), strides.data()}; }
MatrixView<T const, N> get() const { return {storage.data(), strides.data()}; }
private:
std::vector<T> storage;
std::array<std::size_t, N-1> strides;
};
this requires doing Matrix<int, 6> m{ {5,4,2,1,3,5} }; to create a matrix with 6 dimensions.
To access it you need to do m.get()[3][0][0][0][0][0] = 4.
You get get rid of that .get() but it is a bit annoying so long as you want to support tensors of first order.
The data is stored contiguously.

Select right vector with template

I am following this question in order to select the right container, but I am encountering problems.
I have a selector class that must push back into a vector of pointers, but the right one depends on its dimension (1 for vectors, 2 for matrices):
class selector
{
struct formValues : std::vector<coolvector<double>*>, std::vector<coolmatrix<double>*> { };
formValues maps;
public:
selector() { };
template<unsigned int formdim, typename F>
void operator+=(const form<formdim, F> &f)
{
typedef typename form<formdim, F>::storage_type storage_type;
typedef typename std::vector<storage_type*> pointer_type;
// Push to the right vector
formValues<pointer_type> &m = maps;
m.push_back(f.storage.get());
}
};
The forms class have a dimension and a storage, again depending on the dimension, using shared pointers:
template <bool, class if_true, class if_false>
struct type_switch
{
typedef if_false type;
};
template <class if_true, class if_false>
struct type_switch<true, if_true, if_false>
{
typedef if_true type;
};
template <class T> class coolvector {};
template <class T> class coolmatrix {};
template<unsigned int formdim, typename F>
class form
{
public:
form() = delete;
form(const std::string &s) : type(s)
{
storage = std::make_shared<storage_type>();
}
std::string type;
typedef typename type_switch<formdim == 1, coolvector<double>, coolmatrix<double>>::type storage_type;
std::shared_ptr<storage_type> storage;
};
class oneform : public form<1, oneform>
{
public:
oneform() = delete;
oneform(const std::string &s) : form(s) { };
double operator()(unsigned int i) { return i * 2; };
};
class twoform : public form<2, twoform>
{
public:
twoform() = delete;
twoform(const std::string &s) : form(s) { };
double operator()(unsigned int i, unsigned int j) { return i * 2 + j * 20; };
};
The problem is that in the selector::operator+= I get this error:
main.cpp:77:19: error: expected unqualified-id
formValues<pointer_type> &m = maps;
^
Any hints are appreciated!
formValues is not a template, so you can't write formValues<pointer_type>.
You appear to mean
pointer_type& m = maps;
to get the appropriate base class subobject of maps.

Passing temporary struct as template argument

I'm in the process of creating a vector class and am trying to figure out ways to reuse the maximum amount of code for different size vectors.
Here's a basic example:
template<typename T, unsigned int D>
class Vector
{
public:
union {
T v[D];
struct {
/* T x;
* T y;
* T z;
* T w;
*/
};
};
Vector()
{
for(unsigned int i=0; i<D; ++i)
(*this)[i] = T(0);
}
Vector(T scalar)
{
for(unsigned int i=0; i<D; ++i)
(*this)[i] = scalar;
}
inline T operator[](int i) { return (*this).v[i]; }
};
I want the member variables to be publicly accessible. Ex:
Vector<float,2> vec;
printf("X: %.2f, Y: %.2f\n", vec.x, vec.y);
What I'd like to do is something along the lines of this:
template<typename T>
class Vector2 : public Vector<T,2, struct { T x; T y; }> {};
template<typename T>
class Vector3 : public Vector<T,2, struct { T x; T y; T z; }> {};
and have it override a struct in the union:
template<typename T, unsigned int D, struct C>
class Vector
{
public:
union {
T v[D];
// Place the passed struct here
};
};
Is there any feasible way to do this? I do not want to use anything other than the standard library if possible. Thanks in advance.
EDIT: After reading upon all of the answers, I have understood that the way I am using unions is incorrect! Thank you to #M.M for pointing this out. I have since chosen to go a different route, but I have selected the answer that best fit what I was looking for at the time. Once again, thank you for all of the welcomed responses below!
What you are trying to do is not allowed.
Anyway, you can do this:
template<typename T>
struct S { T x; T y; };
template<typename T>
class Vector2 : public Vector<T,2,S<T>> {};
Or this:
template<typename T>
class Vector2 : public Vector<T,2,S> {};
In the second case, Vector can be defined as:
template<typename T, unsigned int D, template<typename> class S>
class Vector {
using MyStruct = S<T>;
// ...
union {
T v[D];
MyStruct myStruct;
};
};
It doesn't scale very well to a large D, but if you're just after the four to six variants I'm imagining, you could partial-specialize a base class:
#include <iostream>
template<typename T, size_t D>
struct VectorBase;
template<typename T>
struct VectorBase<T, 2>
{
constexpr VectorBase() : v{} {}
union {
T v[2];
struct { T x, y; };
};
};
template<typename T>
struct VectorBase<T, 3>
{
constexpr VectorBase() : v{} {}
union {
T v[3];
struct { T x, y, z; };
};
};
template<typename T>
struct VectorBase<T, 4>
{
constexpr VectorBase() : v{} {}
union {
T v[4];
struct { T x, y, z, w; };
};
};
template<typename T, size_t D>
struct Vector : public VectorBase<T, D>
{
using VectorBase<T, D>::v;
using size_type = decltype(D);
using value_type = T;
constexpr Vector() : VectorBase<T,D>{} {}
constexpr Vector(T scalar) {
std::fill(std::begin(v), std::end(v), scalar);
}
constexpr T& operator[](size_type i) const noexcept { return v[i]; }
constexpr const T& operator[](size_type i) noexcept { return v[i]; }
constexpr size_type size() const noexcept { return D; }
constexpr T* data() noexcept { return &v[0]; }
constexpr const T* data() const noexcept { return &v[0]; }
};
template<typename T>
using Vector2 = Vector<T, 2>;
template<typename T>
using Vector3 = Vector<T, 3>;
template<typename T>
using Vector4 = Vector<T, 4>;
int main() {
Vector3<int> v{1};
std::cout << v[0] << ", " << v.z << "\n";
return 0;
}
Live demo: http://ideone.com/T3QHoq
If I understood you correctly your main purpose was to to declare order of fields that corresponds to the array elements of templated class. You cannot do this directly as templates does not accept inline type as parameter. To workaround the problem you could play with non-type template parameters to bind some labels to given index of an array:
#include <cstdio>
#include <unordered_map>
#include <utility>
struct Label { } x, y, z, w;
template <Label&... labels>
struct Pack { };
template <class, class>
struct VectorParent;
template <Label&... labels, size_t... Is>
struct VectorParent<Pack<labels...>, std::index_sequence<Is...>> {
static std::unordered_map<Label *, size_t> label_map;
};
template <Label&... labels, size_t... Is>
std::unordered_map<Label *, size_t> VectorParent<Pack<labels...>, std::index_sequence<Is...>>::label_map = {{&labels, Is}...};
struct LabelNotFound { };
template <class T, size_t N, Label&... labels>
struct Vector:VectorParent<Pack<labels...>, std::make_index_sequence<sizeof...(labels)>> {
static_assert(N == sizeof...(labels),
"the cound of labels should corespond to the number of elements of the vector");
using VectorParent<Pack<labels...>, std::make_index_sequence<sizeof...(labels)>>::label_map;
T t[N];
T &operator->*(Label& l) {
auto it = label_map.find(&l);
if (it == label_map.end())
throw LabelNotFound{};
return t[it->second];
}
};
int main() {
Vector<float,2,x,y> vec;
vec->*x = 10.0f;
printf("X: %.2f, Y: %.2f\n", vec->*x, vec->*y); // prints: X: 10.00, Y: 0.00
//vec->*w = 10.1f; //would throw an exception LabelNotFound
}

Overloading operator [] for N-dimensional structure

I made an N-dimensional structure with vectors and templates:
//----------------N-dimensional vector--------------------------------
template<int dim,typename T> class n_dim_vector {
public:
typedef std::vector<typename n_dim_vector<dim - 1, T>::vector> vector;
};
template<typename T> class n_dim_vector <0, T> {
public:
typedef T vector;
};
It can be instatiaated with different dimnsion-counts and is prt of a class that represent a search space.
template<int dim, typename T> class n_dim_ssc {
private:
typename n_dim_vector<dim, T>::vector searchspace;
};
My problem: I cannot get operator[] right to access searchspace properly, specifically the return type.
I tried:
template<typename V> std::vector<V>& operator[](unsigned i) {
return searchspace[i];
}
T& operator[](unsigned i) {
return searchspace[i];
}
at first, thinking the compiler would derive typename V as whatever type searchspace contained at all but the last level. Thats what T& operator[](unsigned i) was for.
But alas, doen't work this way. And I cannot work out how it would
EDIT Don't fear, I do not access empty memory, the structure is initialized and filled, I just didn't include the code for clarity's sake.
Also, I don't intend to access it with a single integer, I wanted to use searchspace[i][j]..[k]
The way to let compiler deduces the return type is auto:
In C++14:
auto operator[](unsigned i) { return searchspace[i]; }
In C++11:
auto operator[](unsigned i) -> decltype(searchspace[i]) { return searchspace[i]; }
I'm answering to your comment
Feel free to recommend something better, I'd appreciate it.
The following code shows one way to handle the multidimensional vector at once, i.e. non-recursively. It could be improved in several ways which I didn't consider for now (for instance, I wouldn't want to use and pass that many arrays but rather use variadic parameter lists. This however requires much more and more diffcult code, so I'll let it be.)
#include <numeric>
template<size_t Dim, typename T>
struct MultiDimVector
{
std::array<size_t, Dim> Ndim;
std::array<size_t, Dim> stride;
std::vector<T> container;
MultiDimVector(std::array<size_t, Dim> const& _Ndim) : Ndim(_Ndim), container(size())
{
stride[0] = 1;
for (size_t i = 1; i<Dim; ++i)
{
stride[i] = stride[i - 1] * Ndim[i - 1];
}
}
size_t size() const
{
return std::accumulate(Ndim.begin(), Ndim.end(), 1, std::multiplies<size_t>());
}
size_t get_index(std::array<size_t, Dim> const& indices) const
{
//here one could also use some STL algorithm ...
size_t ret = 0;
for (size_t i = 0; i<Dim; ++i)
{
ret += stride[i] * indices[i];
}
return ret;
}
T const& operator()(std::array<size_t, Dim> const& indices) const
{
return container[get_index(indices)];
}
};
You can use it like
MultiDimVector<3, double> v({ 3, 2, 5 }); //initialize vector of dimension 3x2x5
auto a = v({0,1,0}); //get element 0,1,0
But as I wrote, the curly brackets suck, so I'd rewrite the whole thing using variadic templates.
The problem with your approach is that you're not initializing any memory inside the vector and just trying to return non-existent memory spots. Something on the line of the following (WARNING: uncleaned and unrefactored code ahead):
#include <iostream>
#include <vector>
template<int dim,typename T> class n_dim_vector {
public:
typedef std::vector<typename n_dim_vector<dim - 1, T>::vector> vector;
};
template<typename T> class n_dim_vector <0, T> {
public:
typedef T vector;
};
template<int dim, typename T> class n_dim_ssc {
public:
typename n_dim_vector<dim, T>::vector searchspace;
n_dim_ssc() {}
n_dim_ssc(typename n_dim_vector<dim, T>::vector space) : searchspace(space) {}
n_dim_ssc<dim-1, T> operator[](std::size_t i) {
if(searchspace.size() < ++i)
searchspace.resize(i);
return n_dim_ssc<dim-1, T>(searchspace[--i]);
}
typename n_dim_vector<dim, T>::vector get() {
return searchspace;
}
};
template<typename T> class n_dim_ssc<0,T> {
public:
typename n_dim_vector<0, T>::vector searchspace;
n_dim_ssc() {}
n_dim_ssc(typename n_dim_vector<0, T>::vector space) : searchspace(space) {}
typename n_dim_vector<0, T>::vector get() {
return searchspace;
}
};
int main(int argc, char** argv) {
n_dim_ssc<0, int> ea;
int a = ea.get();
n_dim_ssc<1, int> ea2;
auto dd2 = ea2[0].get();
n_dim_ssc<2, int> ea3;
auto dd3 = ea3[0][0].get();
}
Try it out
will work with an accessor method (you can modify this as you want).
Anyway I strongly have to agree with Kerrek: a contiguous memory space accessed in a multi-dimensional array fashion will both prove to be faster and definitely more maintainable/easier to use and read.