I have a 3D Matrix with the MxNxL elements. Both M and N are known at the compile time. Whereas, L is variable and depends on user's input. But it will be provided at the beginning of the program and will never change during the life time of the program. I want to implement this Matrix in C++11 and I want to give the user the flexibility to rotate the 3D Matrix along both the the 1st and 2nd dimension of the matrix.
I would like to know what is the best and most efficient design option to implement this Matrix?
I have seen the below solution which uses std::vector. With std::vector the user can rotate any dimension using std::rotate. The solution is taken from this thread. However, vsoftco mentions that it is not good to use nested vector but rather make it linear. But since I have the requirement of rotating across dimension, having linear array will make the processing hard.
#include <vector>
#define M_SIZE 360
#define N_SIZE 180
template<typename T>
using vec = std::vector<T>;
int main()
{
uint16_t L;
std::cin << L;
vec<vec<vec<double>>> v{M_SIZE, vec<vec<double>>{N_SIZE, vec<double>{L}}};
}
Again, using dynamic c array is a possible solution but std::rotate would only work on the last dimension of the 3D Matrix.
Note: I would prefer to do this without relying on a third party library.
I don't know if this will help you to achieve what you are after but this is a Matrix class that I have started to build using modern C++ features; such as variadic templates. The Matrix Class is self contained into a single header file.
#ifndef MATRIX_H
#define MATRIX_H
#include <cstddef> // std::size_t
#include <numeric> // std::accumulate
#include <vector>
namespace /*Your namespace name here*/ {
template<typename Type, std::size_t... Dims>
class Matrix {
public:
static const std::size_t numDims_ = sizeof...(Dims);
private:
std::size_t numElements_;
std::vector<Type> elements_;
std::vector<std::size_t> strides_;
public:
Matrix() noexcept;
template<typename... Args>
Matrix(Args&&... args) noexcept;
const Type& operator[](std::size_t idx) const;
std::size_t numElements() const { return elements_.size(); }
const std::vector<std::size_t>& strides() const { return strides_; }
const std::vector<Type>& elements() const { return elements_; }
};
template<typename Type, std::size_t... Dims>
Matrix<Type, Dims...>::Matrix() noexcept :
strides_({ Dims... }) {
using std::begin;
using std::end;
auto mult = std::accumulate(begin(strides_), end(strides_), 1, std::multiplies<>());
numElements_ = mult;
elements_.resize(numElements_);
}
template<typename Type, std::size_t... Dims>
template<typename... Args>
Matrix<Type, Dims...>::Matrix(Args&&... args) noexcept :
elements_({ args... }),
strides_({ Dims... }) {
numElements_ = elements_.size();
}
template<typename T, std::size_t... d>
const T& Matrix<T, d...>::operator[](std::size_t idx) const {
if (idx > numElements_)
throw std::runtime_error("Invalid index");
return elements_[idx];
}
} // Your namespace name here
#endif MATRIX_H
And a small sample program using it:
#include <iostream>
#include <exception>
#include "Matrix.h"
int main() {
try {
using /*your namespace name here*/;
Matrix<double, 2, 2, 2> mat( 1.0 ,1.1, 1.2, 1.3,
1.4, 1.5, 1.6, 1.7 );
// Print the elements from the use of getting the vector
for (auto& e : mat.elements()) {
std::cout << e << " ";
}
std::cout << '\n';
// Print the elements from the use of using operator[]
for ( std::size_t n = 0; n < mat.numElements(); n++ ) {
std::cout << mat[n] << " ";
}
std::cout << '\n';
// Print out the strides
std::cout << "Number of strides: " << mat.numDims_ << '\n';
for (auto& s : mat.strides()) {
std::cout << s << " ";
}
std::cout << '\n';
} catch ( std::exception& e ) {
std::cerr << e.what();
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
-Output-
1 1.1 1.2 1.3 1.4 1.5 1.6 1.7
1 1.1 1.2 1.3 1.4 1.5 1.6 1.7
Number of strides: 3
2 2 2
This class is far from complete as it is only just the containing shell of any arbitrary Dimensional Size of Any MxNx...Zx... Matrix. In the template argument list it expects a single Type: int, float, char, user defined etc. The variadic arguments for the tempale arguments after the Type determines how many Dimensions this matrix has, and the dimensional size of each dimension. Examples:
Matrix<type,1> = a 1 matrix which in essence would be a scalar
Matrix<type,1,2> = a 1x2 matrix and would be considered a vector
Matrix<type,3,1> = a 3x1 matrix and would be considered a vector
Matrix<type,2,2> = a 2x2 matrix
Matrix<type,3,4> = a 3x4 matrix
Matrix<type,3,3,3> = a 3x3x3 Matrix (3D-Matrix) and has 27 elements
Matrix<type,3,4,5,3,2> = a 3x4x5x3x2 (5D - Matrix) and has 360 elements
// The number of elements will always equal the product of all of the strides.
// When creating an arbitrary matrix size; careful consideration needs to be taken
// when it comes to how many dimensions and the size of that dimension. Even lower
// dimensional matrices can explode in the amount of elements...
Matrix<type, 128, 356, 242> = a 128x356x242 (3D - Matrix) but has 11,027,456 elements
// It is the Matrix's user defined variadic constructor that the number of arguments
// in the parameter list that has to equal the total amount of elements defined by
// the product of all of its strides.
When working with higher dimensional matrices it is hard to visualize them, but they can easily be managed with the use of the strides vector. We can use these for proper indexing.
The challenging aspect of this design approach is being able to implement the actual arithmetic-computational operators. For this if we have two different matrices that have different strides, they will be treated as different types... and this is just with simple matrix arithmetic; when it comes to matrix multiplication things even get harder because the edges of Matrix A and Matrix B have to be of the same size. Ex: 4x2 * 2x3 would give a 4x3 Matrix. And this is only a 2D matrix issue, when getting into 3D, 4D, ... ND matrices the notation even gets harder. However this template approach does allow the code to be more generic and readable to be self contained into a single class as opposed to having many different matrix classes for various matrix sizes...
Related
I have a multi-dimensional array represented contiguously in memory. I want to keep this representation hidden and just let the user access the array elements as if it were a multi-dimensional one: e.g. my_array[0][3][5] or my_array(0,3,5) or something similar. The dimensions of the object are not determined until runtime, but the object is created with a type that specifies how many dimensions it has. This element look-up will need to be called billions of times, and so should hopefully involve minimal overhead for each call.
I have looked at similar questions but not really found a good solution. Using the [] operator requires the creation of N-1 dimensional objects, which is fine for multi-dimensional structures like vectors-of-vectors because the object already exists, but for a contiguous array it seems like it would get convoluted very quickly and require some kind of slicing through the original array.
I have also looked at overloading (), which seems more promising, but requires specifying the number of arguments, which will vary depending upon the number of dimensions of the array. I have thought about using list initialization or vectors, but wanted to avoid instantiating objects.
I am only a little familiar with templates and figure that there should be some way with C++'s majestic template powers to specify a unique overloading of () for arrays with different types (e.g. different numbers of dimensions). But I have only used templates in really basic generic cases like making a function use both float and double.
I am imagining something like this:
template<typename TDim>
class MultiArray {
public:
MultiArray() {} //build some things
~MultiArray() {} //destroy some things
// The number of arguments would be == to TDim for the instantiated class
float& operator() (int dim1, int dim2, ...) {
//convert to contiguous index and return ref to element
// I believe the conversion equation is something like:
// dim1 + Maxdim1 * ( dim2 + MaxDim2 * ( dim3 + MaxDim3 * (...)))
}
private:
vector<float> internal_array;
vector<int> MaxDimX; // Each element says how large each corresponding dim is.
};
So if I initialize this class and attempted to access an element, it would look something like this:
my_array = MultiArray<4>();
element = my_array(2,5,4,1);
How might I go about doing this using templates? Is this even possible?
template<class T>
struct slice {
T* data = 0;
std::size_t const* stride = 0;
slice operator[](std::size_t I)const {
return{ data + I* *stride, stride + 1 };
}
operator T&()const {
return *data;
}
T& operator=(typename std::remove_const<T>::type in)const {
*data = std::move(in); return *data;
}
};
store a vector<T> of data, and an std::vector<std::size_t> stride of strides, where stride[0] is the element-stride that the first index wants.
template<class T>
struct buffer {
std::vector<T> data;
std::vector<std::size_t> strides;
buffer( std::vector<std::size_t> sizes, std::vector<T> d ):
data(std::move(d)),
strides(sizes)
{
std::size_t scale = 1;
for (std::size_t i = 0; i<sizes.size(); ++i){
auto next = scale*strides[sizes.size()-1-i];
strides[sizes.size()-1-i] = scale;
scale=next;
}
}
slice<T> get(){ return {data.data(), strides.data()}; }
slice<T const> get()const{ return {data.data(), strides.data()}; }
};
c++14. Live example.
If you use not enough []s it refers to the first element of the subarray in question. If you use too many it does UB. It does zero dimension checking, both in count of dimensions and in size.
Both can be added, but would cost performance.
The number of dimensions is dynamic. You can split buffer into two types, one that owns the buffer and the other that provides the dimensioned view of it.
It seems to me that you could use Boost.MultiArray, boost::multi_array_ref to be more specific. boost::multi_array_ref does exactly what you want: it wraps continuous data array into an object that may be treated as a multidimensional array. You may also use boost::multi_array_ref::array_view for slicing purposes.
I cannot provide you with any benchmark results, but from my experience, I can say that boost::multi_array_ref works pretty fast.
If you can use C++17, so variadic template folding, and row major order, I suppose you can write something like (caution: not tested)
template <template ... Args>
float & operator() (Args ... dims)
{
static_assert( sizeof...(Args) == TDim , "wrong number of indexes" );
// or SFINAE enable instead of static_assert()
std::size_t pos { 0U };
std::size_t i { 0U };
( pos *= MaxDimX[i++], pos += dims, ... );
return internal_array[pos];
}
OTPS (Off Topic Post Scriptum): your MaxDimX, if I understand correctly, is a vector of dimensions; so should be an unsigned integer, non a signed int; usually, for indexes, is used std::size_t [see Note 1].
OTPS 2: if you know compile time the number of dimensions (TDim, right?) instead of a std::vector, I suggest the use of a std::array; I mean
std::array<std::size_t, TDim> MaxDimX;
-- EDIT --
If you can't use C++17, you can use the trick of the unused array initialization to obtain something similar.
I mean
template <template ... Args>
float & operator() (Args ... dims)
{
using unused = int[];
static_assert( sizeof...(Args) == TDim , "wrong number of indexes" );
// or SFINAE enable instead of static_assert()
std::size_t pos { 0U };
std::size_t i { 0U };
(void)unused { (pos *= MaxDimX[i++], pos += dims, 0) ... };
return internal_array[pos];
}
Note 1: as pointed by Julius, the use of a signed or an unsigned integer for indexes is controversial.
So I try to explain better why I suggest to use an unsigned value (std::size_t, by example) for they.
The point is that (as far I know) all Standard Template Library is designed to use unsigned integer for index values. You can see it by the value returned by the size() method and by the fact that access methods that receive an index, as at() or operator[], receive an unsigned value.
Right or wrong, the language itself is designed to return a std::size_t from the old sizeof() and from more recent variadic sizeof...(). The same class std::index_sequence is an alias for std::integer_sequence with a fixed unsigned, again std::size_t, type.
In a world designed to use unsigned integers for indexes, the use of a signed integer for they it's possible but, IMHO, dangerous (because error prone).
I've used this pattern several times when creating a class templates of a matrix class with variable dimensions.
Matrix.h
#ifndef MATRIX_H
template<typename Type, size_t... Dims>
class Matrix {
public:
static const size_t numDims_ = sizeof...(Dims);
private:
size_t numElements_;
std::vector<Type> elements_;
std::vector<size_t> strides_; // Technically this vector contains the size of each dimension... (its shape)
// actual strides would be the width in memory of each element to that dimension of the container.
// A better name for this container would be dimensionSizes_ or shape_
public:
Matrix() noexcept;
template<typename... Arg>
Matrix( Arg&&... as ) noexcept;
const Type& operator[]( size_t idx ) const;
size_t numElements() const {
return elements_.size();
}
const std::vector<size_t>& strides() const {
return strides_;
}
const std::vector<Type>& elements() const {
return elements_;
}
}; // matrix
#include "Matrix.inl"
#endif // MATRIX_H
Matrix.inl
template<typename Type, size_t... Dims>
Matrix<Type, Dims...>::Matrix() noexcept :
strides_( { Dims... } ) {
using std::begin;
using std::end;
auto mult = std::accumulate( begin( strides_ ), end( strides_ ), 1, std::multiplies<>() );
numElements_ = mult;
elements_.resize( numElements_ );
} // Matrix
template<typename Type, size_t... Dims>
template<typename... Arg>
Matrix<Type, Dims...>::Matrix( Arg&&... as ) noexcept :
elements_( { as... } ),
strides_( { Dims... } ){
numElements_ = elements_.size();
} // Matrix
template<typename T, size_t... d>
const T& Matrix<T,d...>::operator[]( size_t idx ) const {
return elements_[idx];
} // Operator[]
Matrix.cpp
#include "Matrix.h"
#include <vector>
#include <numeric>
#include <functional>
#include <algorithm>
main.cpp
#include <vector>
#include <iostream>
#include "matrix.h"
int main() {
Matrix<int, 3, 3> mat3x3( 1, 2, 3, 4, 5, 6, 7, 8, 9 );
for ( size_t idx = 0; idx < mat3x3.numElements(); idx++ ) {
std::cout << mat3x3.elements()[idx] << " ";
}
std::cout << "\n\nnow using array index operator\n\n";
for ( size_t idx = 0; idx < mat3x3.numElements(); idx++ ) {
std::cout << mat3x3[idx] << " ";
}
std::cout << "\n\ncheck the strides\n\n";
for ( size_t idx = 0; idx < mat3x3.numDims_; idx++ ) {
std::cout << mat3x3.strides()[idx] << " ";
}
std::cout << "\n\n";
std::cout << "=================================\n\n";
Matrix<float, 5, 2, 9, 7> mf5x2x9x7;
// Check Strides
// Num Elements
// Total Size
std::cout << "The total number of dimensions are: " << mf5x2x9x7.numDims_ << "\n";
std::cout << "The total number of elements are: " << mf5x2x9x7.numElements() << "\n";
std::cout << "These are the strides: \n";
for ( size_t n = 0; n < mf5x2x9x7.numDims_; n++ ) {
std::cout << mf5x2x9x7.strides()[n] << " ";
}
std::cout << "\n";
std::cout << "The elements are: ";
for ( size_t n = 0; n < mf5x2x9x7.numElements(); n++ ) {
std::cout << mf5x2x9x7[n] << " ";
}
std::cout << "\n";
std::cout << "\nPress any key and enter to quit." << std::endl;
char c;
std::cin >> c;
return 0;
} // main
This is a simple variable multidimensional matrix class of the Same Type <T>
You can create a matrix of floats, ints, chars etc of varying sizes such as a 2x2, 2x3, 5x3x7, 4x9x8x12x2x19. This is a very simple but versatile class.
It is using std::vector<> so the search time is linear. The larger the multi - dimensional matrix grows in dimensions the larger the internal container will grow depending on the size of each dimension; this can "explode" fairly quick if each individual dimensions are of a large dimensional size for example: a 9x9x9 is only a 3 dimensional volumetric matrix that has many more elements than a 2x2x2x2x2 which is a 5 dimensional volumetric matrix. The first matrix has 729 elements where the second matrix has only 32 elements.
I did not include a default constructor, copy constructor, move constructor, nor any overloaded constructors that would accept either a std::container<T> or another Matrix<T,...>. This can be done as an exercise for the OP.
I also did not include any simple functions that would give the size of total elements from the main container, nor the number of total dimensions which would be the size of the strides container size. The OP should be able to implement these very simply.
As for the strides and for indexing with multiple dimensional coordinates the OP would need to use the stride values to compute the appropriate indexes again I leave this as the main exercise.
EDIT - I went ahead and added a default constructor, moved some members to private section of the class, and added a few access functions. I did this because I just wanted to demonstrate in the main function the power of this class even when creating an empty container of its type.
Even more you can take user Yakk's answer with his "stride & slice" algorithm and should easily be able to plug it right into this class giving you the full functionality of what you are looking for.
What I am trying to do is to shuffle an existing array (vector). There is a catch here, there are actually two arrays (vectors) that depend on each other.
To be more exact, I have a 2d vector which contains patterns , so each row denotes a single pattern, and then there is another 2d vector which contains the desired output of each pattern.
So it would look like something like this :
vector<vector<float>> P{ vector < float > {0, 0},
vector < float > {1, 0},
vector < float > {0, 1},
vector < float > {1, 1} };
vector<vector<float>> T{ vector < float > {0},
vector < float > {1},
vector < float > {1},
vector < float > {0} };
Now I need to shuffle the patterns collection, so their individual rows order differ each time we traverse P. again I mean, since P's size() here is 4, and thus we have 4 patterns, and we want to select one at a time till we access all of them.
When all of the patterns are selected one after the other, an epoch is completed, and we need to change the patterns order for the next epoch. We are going to do this for an arbitrary number of times, and each time, these patterns order need to get changed, (e.g. the first time (0,0) is first, followed by (0,1) and (1,0) and finally (1,1), in the second epoch we might be having (1,1) (1,0) (0,0) (0,1) as the patterns).
So when we shuffle the pattern collection, we need to have the targets collection shuffled exactly the same as well. What is fastest way of doing so? There are different ways that ran through my head, such as:
creating a map out of these two arrays, and map each pattern with the corresponding target, and then shuffle the the patterns collection. Whenever there is a need for a target it can easily be accessed by the map.
use tuples to create a new list and shuffle the newly created tuple and get going.
just use a random number between 0 to 3 and pick a number, (a pattern index) and use that, store the index in an array, which is used to prevent selecting the same index twice in one epoch.
What would you suggest in this scenario?
It seems that you want to shuffle indexes:
std::vector<std::size_t> indexes{0, 1, 2, 3}; // or initialize with std::iota
std::shuffle(indexes.begin(), indexes.end(), my_random_generator);
Your question is very hard to answer definitively as it lacks a lot of information. And even with all the information needed, a definitive answer would still be very hard to give without measuring different options.
The first and most important question is: what is it that you're trying to make fast - generating a new epoch or accessing your data? Answering this question would require knowing the size of the actual data you have, the ways and number of times you access your data in the other code, how is your data modified/generated during runtime, etc.
Here's some general advice though. If you know the size of inner vectors of your T and P - use std::array instead of std::vector. This way your inner arrays will be laid out in a single chunk of memory improving cache behaviour. For the same reason, if you can, combine the patterns and outputs into a std::tuple or a std::pair or a struct for that matter and put them all in one array.
Let's assume you can put them into a single vector. Then the regarding the shuffling itself, you can either take the approach with shuffling indices into a static vector or shuffling the vector itself. Shuffling a vector of indices will likely be faster, but you will pay an additional indirection every time you access your pattern-outcome pairs which might make your overall performance way worse than shuffling the vector itself. Your access patterns are of the utmost importance when making the decision - measure your options!
If for some reason you absolutely cannot put everything in one vector and additional array of indices is too expensive, consider using this code (note, you need boost and c++14 compiler for this to work, live demo here):
#include <iostream>
#include <string>
#include <random>
#include <vector>
#include <tuple>
#include <utility>
#include <algorithm>
#include <boost/iterator/iterator_facade.hpp>
template <typename... IteratorTypes>
using value_tuple = std::tuple<typename IteratorTypes::value_type...>;
template <typename... IteratorTypes>
class reference_tuple : public std::tuple<typename IteratorTypes::value_type&...> {
using std::tuple<typename IteratorTypes::value_type&...>::tuple;
};
template<typename... IteratorTypes, size_t... Index>
void swap_impl(reference_tuple<IteratorTypes...> left, reference_tuple<IteratorTypes...> right, std::index_sequence<Index...>)
{
using std::swap;
int dummy[] = {(swap(std::get<Index>(left), std::get<Index>(right)), 0)...};
(void)dummy;
}
template <typename... IteratorTypes>
void swap(reference_tuple<IteratorTypes...> left, reference_tuple<IteratorTypes...> right)
{
swap_impl(left, right, std::index_sequence_for<IteratorTypes...>{});
}
template <typename... IteratorTypes>
class zip_iter
: public boost::iterator_facade<
zip_iter<IteratorTypes...> // Derived
, value_tuple<IteratorTypes...> // Value
, boost::random_access_traversal_tag
, reference_tuple<IteratorTypes...> // Reference
>
{
public:
zip_iter() = default;
explicit zip_iter(IteratorTypes... iters)
: iterators(iters...)
{
}
private:
friend class boost::iterator_core_access;
void increment() { increment_impl(std::index_sequence_for<IteratorTypes...>()); }
template<size_t... Index>
void increment_impl(std::index_sequence<Index...>)
{
int dummy[] = {(++std::get<Index>(iterators), 0)...};
(void)dummy;
}
void decrement() { decrement_impl(std::index_sequence_for<IteratorTypes...>()); }
template<size_t... Index>
void decrement_impl(std::index_sequence<Index...>)
{
int dummy[] = {(--std::get<Index>(iterators), 0)...};
(void)dummy;
}
template<typename diff_t>
void advance(diff_t n) { advance_impl(n, std::index_sequence_for<IteratorTypes...>()); }
template<typename diff_t, size_t... Index>
void advance_impl(diff_t n, std::index_sequence<Index...>)
{
int dummy[] = {(std::advance(std::get<Index>(iterators), n), 0)...};
(void)dummy;
}
bool equal(zip_iter const& other) const
{
return std::get<0>(iterators) == std::get<0>(other.iterators);
}
auto dereference() const {
return dereferenceImpl(std::index_sequence_for<IteratorTypes...>{});
}
template<std::size_t... Index>
auto dereferenceImpl(std::index_sequence<Index...>) const
{
return reference_tuple<IteratorTypes...>(*std::get<Index>(iterators)...);
}
auto distance_to(zip_iter const& r) const
{
return std::distance(std::get<0>(iterators), std::get<0>(r.iterators));
}
std::tuple<IteratorTypes...> iterators;
};
template<typename... Iterators>
auto make_zip_iter(Iterators... iters)
{
return zip_iter<Iterators...>(iters...);
}
int main()
{
std::mt19937 rng(std::random_device{}());
std::vector<int> ints(10);
std::iota(ints.begin(), ints.end(), 0);
std::cout << "Before: ";
for (auto i : ints) {
std::cout << i << " ";
}
std::cout << "\n";
std::vector<int> ints2{ints};
std::shuffle(make_zip_iter(ints.begin(), ints2.begin()), make_zip_iter(ints.end(), ints2.end()), rng);
std::cout << "Are equal: " << (ints == ints2) << "\n";
std::cout << "After: ";
for (auto i : ints) {
std::cout << i << " ";
}
}
I have several constant matrices of defferent sizes of both dimensions, say
const int denoise[][3] = {...}.
const int deconv[][4] = {...}
Then I define a function like void handleMatrix(const int* const*){...} hoping to handle these matrices. But it is uncorrect.
one effort I tried is using a template like:
template<typename Ty> void handle Matrix(const Ty m){...}
It works perfectly on vs2013.
But how should I pass those matrices to a function without using template?
You should use a typedef so that you don't have to use any awful syntax:
using matrix_t = int[3][3];
And you should pass your args by reference whenever possible:
void handle_matrix(const matrix_t &mat){
// do something with 'mat'
}
If you want to use the original syntax without a typedef:
void handle_matrix(const int (&mat)[3][3]){
// ...
}
and if you want to use the original syntax and pass by pointer:
void handle_matrix(const int (*mat)[3]){
// ...
}
But then you lose type safety, so I'd recommend against this and just go with the nicest option: typedef and pass by reference.
EDIT
You said in a comment on #Kerrek SB's answer that your matrices will be different sizes.
So here is how to handle that and still keep the nice method:
template<size_t Columns, size_t Rows>
using matrix_t = int[Columns][Rows];
template<size_t Columns, size_t Rows>
void handle_matrix(const matrix_t<Columns, Rows> &mat){
// ...
}
Take into account that I'm presuming you can use C++14 in my answer, if you leave a comment I can modify it for any other version.
Your matrices are arrays of int[3]s. If you want C-style argument passing, you'd pass a pointer the first element of the array plus a size:
using Row = int[3];
void foo(const Row * p, std::size_t n_cols)
{
for (std::size_t i = 0; i != n_cols; ++i)
{
for (int n : p[i]) { std::cout << n << ' '; }
std::cout << '\n';
}
}
Usage example:
Row * matrix = new Row[40]();
foo(matrix, 40);
delete [] matrix;
With a typed variable:
Row matrix[] = { {1,2,3}, {2,3,4} };
foo(matrix, std::distance(std::begin(matrix), std::end(matrix)));
I want to build a 3D nx*ny*nz matrix that nx,ny,nz are about 200 so I have to use dynamic allocation and because I have a lot of these matrixes I need build these matrixes in a way that it uses minimum memory as is possible how can I do this and how can I build in contiguous form?
Using C++11:
template<typename T,size_t M,size_t N,size_t O>
using Matrix3D = std::array<std::array<std::array<T,O>,N>,M>;
std::unique_ptr<Matrix3D<double,200,200,200>> mat(new Matrix3D<double,200,200,200>);
(*mat)[m][n][o] = 10.0;
If you write a make_unique function the variable declaration becomes:
auto mat = std::make_unique<Matrix3D<double,200,200,200>>();
So a whole program might look like:
#include <memory> // std::unique_ptr for convenient and exception safe dynamic-memory management
#include <array> // std::array because it behaves much better than raw arrays
template<typename T,size_t M,size_t N,size_t O>
using Matrix3D = std::array<std::array<std::array<T,O>,N>,M>;
// A simple `make_unique`
template<typename T,typename... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
int main() {
auto mat = make_unique<Matrix3D<double,200,27,200>>();
(*mat)[199][26][199] = 10.0; // store 10.0 in the last element
}
Remember that this is C++11, and some compilers haven't yet implemented all the features I'm using. In particular the only released compiler I know of that supports template aliases (the using Matrix3D = line) is clang 3.0. The next version of GCC will support it though. Variadic templates (used to implement make_unique) are supported in both GCC and Clang, but not MSVC as of VS11.
Here's a version that uses only widely supported* C++11 features:
#include <memory>
#include <array>
template<typename T,size_t M,size_t N,size_t O>
struct Matrix3D {
std::array<std::array<std::array<T,O>,N>,M> array;
};
// A simple `make_unique` that supports only zero-argument construction.
template<typename T>
std::unique_ptr<T> make_unique() {
return std::unique_ptr<T>(new T);
}
int main() {
auto mat = make_unique<Matrix3D<double,200,27,200>>();
mat->array[199][26][199] = 10.0; // store 10.0 in the last element
}
* Widely supported means at least the latest releases of GCC, and MSVC.
You can write a wrapper around a std::vector and overload operator() to access matrix elements. The elements are stored contiguously in the 1D std::vector and operator() converts 3D indices into a 1D index into the std::vector. If the matrix was 2D, this is how the mapping from 2D to 1D would look like:
| 1 2 3 |
| 4 5 6 | ---> [1 2 3 4 5 6 7 8 9]
| 7 8 9 |
This ordering is called row major.
Here's an example of a class that overloads operator() to convert 3D indices into a row-major 1D index:
#include <iostream>
#include <vector>
template <class T>
class Matrix3D
{
public:
Matrix3D(size_t m, size_t n, size_t o)
: m_(m), n_(n), o_(o), data_(m*n*o) {}
T& operator()(size_t i, size_t j, size_t k)
{
return data_[(i * n_ * o_) + (j * o_) + k];
}
const T& operator()(size_t i, size_t j, size_t k) const
{
return data_[(i * n_ * o_) + (j * o_) + k];
}
private:
std::vector<T> data_;
size_t m_, n_, o_;
};
int main()
{
Matrix3D<float> m(4, 3, 2);
m(0,0,0) = 12.3f;
m(3,2,1) = 45.6f;
std::cout << m(0,0,0) << " " << m(3,2,1) << "\n";
}
The Boost.MultiArray library does essentially the same thing as this (and much more), but can be used for any dimension N.
If the dimensions are known at compile-time you can just allocate the object using new although I would probably put it int a structure because I keep mixing types up bewteen arrays and pointer (I barely ever use them directly):
struct array3d {
double array[200][200][200];
};
std::auto_ptr<areay3d> array(new array3d);
Obviously, the array dimensions can become template arguments.
If the dimensions are determined only at run-time you'd need to allocate a contiguous array of double and do the array subscript computations yourself. This probably would also become a set if classes accessibg the elements: the subscript operator for the 3d array would return a reference to a 2d array, etc. std::valarray<double> is meant to help with this and there are boost classes for this as well.
I have a method that takes a std::vector as one of its parameters. Is there a way I can initialize a matrix by assigning the std::vector to the matrix? Here's what I tried to do below. Does anyone know how i can achieve assigning the vector (or even a pointer of doubles) to the matrix? Thanks in advance. Mike
void Foo(std::vector v)
{
matrix<double> m(m, n, v);
// work with matrix...
}
Here is yet another example of how this can be done:
#include <algorithm>
#include <vector>
#include <boost/numeric/ublas/storage.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/io.hpp>
namespace ublas = boost::numeric::ublas;
template <typename T, typename F=ublas::row_major>
ublas::matrix<T, F> makeMatrix(std::size_t m, std::size_t n, const std::vector<T> & v)
{
if(m*n!=v.size()) {
; // Handle this case
}
ublas::unbounded_array<T> storage(m*n);
std::copy(v.begin(), v.end(), storage.begin());
return ublas::matrix<T>(m, n, storage);
}
int main () {;
std::vector<double> vec {1, 2, 3, 4, 5, 6};
ublas::matrix<double> mm = makeMatrix(3,2,vec);
std::cout << mm << std::endl;
}
According to the boost matrix documentation, there are 3 constructors for the matrix class: empty, copy, and one taking two size_types for the number of rows and columns. Since boost doesn't define it (probably because there are many ways to do it and not every class is gong to define a conversion into every other class) you are going to need to define the conversion.
Here's an approach that I would use, but since there are multiple ways to do this and the question doesn't specify how you want this done you may find a different approach more applicable to your situation.
void Foo(const std::vector<double> & v) {
size_t m = ... // you need to specify
size_t n = ... // you need to specify
if(v.size() < m * n) { // the vector size has to be bigger or equal than m * n
// handle this situation
}
matrix<double> mat(m, n);
for(size_t i=0; i<mat.size1(); i++) {
for(size_t j=0; j<mat.size2(); j++) {
mat(i,j) = v[i+j*mat.size1()];
}
}
}
A couple of notes about your provided code: std::vector needs a templated argument and you are declaring m as a matrix and an input argument to it's constructor.
A more convenient way is like this:
matrix<double> m(m*n);
std::copy(v.begin(), v.end(), m.data().begin());
Simple answer, but not very apparent from the Boost documentation.
You may just use std::vector<> as type of storage array template paramerter instead of default unbounded_array<> for your matrix. (It's mentioned in footnote 2 of documentation on matrix<> class.)
void Foo(const std::vector<double> &v, size_t n)
{
using namespace boost::numeric::ublas;
size_t m = v.size() / n;
matrix< double, row_major, std::vector<double> > M(m, n);
M.data() = v;
// work with matrix...
}
More variants of initialization can be found in your boost source:
boost/libs/numeric/ublas/doc/samples/assignment_examples.cpp, as pointed out here: assign multiple values to boost::numeric::ublas::vector in c++
Or here: uBLAS examples, example 3, which is mentioned by related question: ublas: Wrap ublas::vector as ublas::matrix_expression