SHOW ME THE CODE !

Binary tree

150px-Binary_tree.svg.png

1633990707354.webp
 
Exsan, how does your work compare to similar stuff in Boost Intrusive

I have not seen this before, please let me go through it.
However, before any comment I would say that my work is kind of THINK DIFFERENT, so far roughly more than 100K lines source code- fully integrated. I developed most of the library of my product, I try to avoid external libraries, as you can imagine my work is just: OOP + POINTERS
By the way, which version of Boost have you lately installed in your machine? 1.77?
have you tried the new Visual Studio 64 bits? do you recommend it ?
 
Last edited:
Refreshing my C++ programming skills by reviewing the material in the book : C++17 by Ivor Horton; the idea is to try and implement some numerical code in the short term.

Any feedback is super-helpful.

Merge Sort.
[CODE lang="cpp" title="Merge Sort"]// MergeSort.cpp : MergeSort on an std::array<T,N>

#include <iostream>
#include <array>
#include <cmath>
#include <iomanip>

template <class T, std::size_t N>
void merge(std::array<T, N>& A, const int l, const int m, const int r)
{
// A[l..m] and A[m+1..r] are two sorted lists and
// we are interested to merge them.

int l1{ l }; //This index always points to the beginning of the first list
int l2{ m + 1 }; //This index always points to the beginning of the second list
int i{ 0 }; //This index always points to the beginning of the merged list

std::array<T, N> result {}; //The merged list will be held in a fixed-size array (auto storage duration), until
//merge is complete.

// Iterate until we do not reach the end of atleast one of the lists
while (l1 <= m && l2 <= r)
{
// Compare the current element of the first list with the second list
// and find the least element.
if (A[l1] <= A[l2])
{
result = A[l1];
++l1;
}
else
{
result = A[l2];
++l2;
}
++i;
}

// If the end of either one of the lists is reached, flush all the remaining elements
// of the other list to result
while (l1 <= m)
{
result = A[l1];
++i;
++l1;
}

while (l2 <= r)
{
result = A[l1];
++i;
++l2;
}

//Copy all elements from the result into A[l..r]
int j{ l };
for (int k{}; k < r - l + 1; ++k)
{
A[j] = result[k];
++j;
}
}

template <class T, int N>
void mergeSort(std::array<T,N>& a, int l, int r)
{
// If the problem is of size 1, then we are done. There is nothing to be
// sorted.
if (N == 1 || l == r)
return;

// Divide the problem into 2 smaller subproblems of a smaller size (N/2).
int m{ static_cast<int>(floor((l + r) / 2.0)) };

// Recursively conquer the two sub-problems of size (N/2)
mergeSort<T, N>(a, l, m);
mergeSort<T, N>(a, m+1, r);

// Now, we have two sorted lists and we would like to merge them.
merge<T, N>(a, l, m, r);
}

int main()
{
std::array<int, 10> A{ 10,9,8,7,6,5,4,3,2,1 };
std::cout << "Before mergeSort : " << std::endl;
for (int element : A)
{
std::cout << std::setw(5) << element;
}
std::cout << std::endl;
mergeSort(A, 0, 9);

std::cout << "After mergeSort : " << std::endl;
for (int element : A)
{
std::cout << std::setw(5) << element;
}
std::cout << std::endl;
return 0;
}[/CODE]
 
Last edited:
Is there not a standard STL algorithm?
A while loop with nested if else might be 1) slow, 2) shaky/flaky, 3) difficult to maintain.
e.g. arrays of length 1'000'000, exception handling etc.

It looks like reinvention of wheel. It means less time for 'bigger' stuff.

BTW what's a good rationale for merge()? Just asking. It's not documented.

// Complexity: O(N^2)??
 
Last edited:
Is there not a standard STL algorithm?
A while loop with nested if else might be 1) slow, 2) shaky/flaky, 3) difficult to maintain.
e.g. arrays of length 1'000'000, exception handling etc.

It looks like reinvention of wheel. It means less time for 'bigger' stuff.

BTW what's a good rationale for merge()? Just asking. It's not documented.

// Complexity: O(N^2)??

Daniel, in case of Merge sort, if the array has size 2^M = N , then at level j of the recursion tree, you are left with 2^j arrays of size N/2^j each that you wanna merge. The merge operation is linear so, each stage should take like O(N) work and there are \log N/\log 2 stages so, its ~N \log N; that's atleast what I recall.

merge() is supposed to simply encapsulate the functionality of merging two sorted arrays.

I will add some exception handling; also want to learn to write unit tests for my code (I have used xUnit before, but haven't used a framework for C++).

BTW, i did bookmark this SE post on how to implement classic sorting algorithms in modern C++. But, I don't know the standard library <algorithms> just yet. The book I am using is modular; might take me a little while to write code like in that SE post.
 
Hi guys,

I am writing a matrix class - and wanted to get some feedback. My idea is that one should be capable of creating both fixed-size(compile-time) and dynamic matrices. So, containerType template parameter would be either std::array<T,N> or std::vector<N>.

I should provide proper iterators to traverse through my matrix and also need to overload the assignment operator.

[CODE lang="cpp" title="Matrix.h"]#pragma once

#include <array>
#include <vector>

template <typename T, int r, int c, typename cType=std::array<T,r*c>>
class Matrix;

using Matrix1d = Matrix<double, 1, 1>;
using Matrix2d = Matrix<double, 2, 2>;
using Matrix3d = Matrix<double, 3, 3>;
using Matrix4d = Matrix<double, 4, 4>;

using Matrix1i = Matrix<int, 1, 1>;
using Matrix2i = Matrix<int, 2, 2>;
using Matrix3i = Matrix<int, 3, 3>;
using Matrix4i = Matrix<int, 4, 4>;

using Matrix1f = Matrix<float, 1, 1>;
using Matrix2f = Matrix<float, 2, 2>;
using Matrix3f = Matrix<float, 3, 3>;
using Matrix4f = Matrix<float, 4, 4>;

using Vector1d = Matrix<double, 1, 1>;
using Vector2d = Matrix<double, 1, 2>;
using Vector3d = Matrix<double, 1, 3>;
using Vector4d = Matrix<double, 1, 4>;

using Vector1i = Matrix<int, 1, 1>;
using Vector2i = Matrix<int, 2, 2>;
using Vector3i = Matrix<int, 3, 3>;
using Vector4i = Matrix<int, 4, 4>;

using Vector1f = Matrix<float, 1, 1>;
using Vector2f = Matrix<float, 2, 2>;
using Vector3f = Matrix<float, 3, 3>;
using Vector4f = Matrix<float, 4, 4>;

using MatrixXi = Matrix<int, 0, 0, std::vector<int>>;
using MatrixXd = Matrix<double, 0, 0, std::vector<double>>;
using MatrixXf = Matrix<float, 0, 0, std::vector<float>>;

template <typename scalarType, int rowsAtCompileTime = 0, int colsAtCompileTime = 0, typename containerType = std::array<scalarType,(rowsAtCompileTime * colsAtCompileTime)>>
class Matrix
{
private:
containerType A;
int _rows;
int _cols;
public:
Matrix() = default;
Matrix(const Matrix& m);

int rows() const;
int cols() const;
int size() const;

//Overloaded operators
scalarType operator()(const int i, const int j) const;
scalarType& operator()(const int i, const int j);
Matrix operator+(const Matrix& m) const;
Matrix operator-(const Matrix& m) const;
Matrix operator*(const Matrix& m) const;
};[/CODE]

[CODE lang="cpp" title="Matrix.cpp"]
#pragma once

#include "Matrix.h"
#include <stdexcept>

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::Matrix(const Matrix& m):A{m.A}, _rows{m.rows()}, _cols{m.cols()}, _size{m.size()}
{
}

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
int Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::rows() const
{
return _rows;
}

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
int Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::cols() const
{
return _cols;
}

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
int Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::size() const
{
return A.size();
}

/// <summary>
/// Coefficient accessors.
/// The primary coefficient accessor is the overloaded parenthesis operators. The data of the matrix
/// is stored in an underlying sequential container such as std::array or std::vector. The element
/// A(i,j) is at an offset of (i*_cols)+j in memory.
/// </summary>
/// <typeparam name="scalarType"></typeparam>
/// <typeparam name="containerType"></typeparam>
/// <param name="i">The row index</param>
/// <param name="j">The col index</param>
/// <returns>The element at position (i,j)</returns>
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
scalarType Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::operator()(const int i, const int j) const
{
containerType::const_iterator it{ A.begin() };
it = it + (i * _cols) + j;
if (it < A.end())
return *it;
else
throw std::out_of_range("\nError accessing an element beyond matrix bounds");
}

/// <summary>
/// Matrix addition.
/// Overload of the binary operator +. The left hand side and the right hand side matrix must have
/// the same number of rows and columns.
/// </summary>
/// <typeparam name="scalarType"></typeparam>
/// <typeparam name="containerType"></typeparam>
/// <param name="i"></param>
/// <param name="j"></param>
/// <returns></returns>
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
scalarType& Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::operator()(const int i, const int j)
{
containerType::iterator it{ A.begin() };
it = it + (i * _cols) + j;
if (it < A.end())
return *it;
else
throw std::out_of_range("\nError accessing an element beyond matrix bounds");
}

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType> Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::operator+(const Matrix& m) const
{
Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType> result{};

if (this->rows() == m.rows() && this->cols() == m.cols())
{
containerType::const_iterator it1{ A.begin() };
containerType::const_iterator it2{ m.A.begin() };
containerType::iterator resultIter{ result.A.begin() };
while (it1 < A.end() && it2 < m.A.end())
{
*resultIter = *it1 + *it2;
++it1; ++it2; ++resultIter;
}
}
else
{
throw std::logic_error("Matrices have different dimensions; therefore cannot be added!");
}


return result;
}

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType> Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::operator-(const Matrix& B) const
{
Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType> result{};

if (this->rows() == m.rows() && this->cols() == m.cols())
{
containerType::const_iterator it1{ A.begin() };
containerType::const_iterator it2{ m.A.begin() };
containerType::iterator resultIter{ result.A.begin() };
while (it1 < A.end() && it2 < m.A.end())
{
*resultIter = *it1 - *it2;
++it1; ++it2; ++resultIter;
}
}
else
{
throw std::logic_error("Matrices have different dimensions; therefore cannot be added!");
}
return result;
}

template<typename scalarType, int m, int n, int p, typename containerType>
Matrix<scalarType, m, p, containerType> operator*(const Matrix<scalarType, m, n, containerType>& A, const Matrix<scalarType, n, p, containerType>& B)
{
Matrix<scalarType, m, p, containerType> result;

for (int i{}; i < m; ++i)
{
for (int k{}; k < p; ++k)
{
scalarType sum{};
for (int j{}; j < n; ++j)
{
sum += A(i, j) * B(j, k);
}
result(i, k) = sum;
}
}
}
[/CODE]
 
Last edited:
Hi guys,

I am writing a matrix class - and wanted to get some feedback. My idea is that one should be capable of creating both fixed-size(compile-time) and dynamic matrices. So, containerType template parameter would be either std::array<T,N> or std::vector<N>.

I should provide proper iterators to traverse through my matrix and also need to overload the assignment operator.

[CODE lang="cpp" title="Matrix.h"]#pragma once

#include <array>
#include <vector>

template <typename T, int r, int c, typename cType=std::array<T,r*c>>
class Matrix;

using Matrix1d = Matrix<double, 1, 1>;
using Matrix2d = Matrix<double, 2, 2>;
using Matrix3d = Matrix<double, 3, 3>;
using Matrix4d = Matrix<double, 4, 4>;

using Matrix1i = Matrix<int, 1, 1>;
using Matrix2i = Matrix<int, 2, 2>;
using Matrix3i = Matrix<int, 3, 3>;
using Matrix4i = Matrix<int, 4, 4>;

using Matrix1f = Matrix<float, 1, 1>;
using Matrix2f = Matrix<float, 2, 2>;
using Matrix3f = Matrix<float, 3, 3>;
using Matrix4f = Matrix<float, 4, 4>;

using Vector1d = Matrix<double, 1, 1>;
using Vector2d = Matrix<double, 1, 2>;
using Vector3d = Matrix<double, 1, 3>;
using Vector4d = Matrix<double, 1, 4>;

using Vector1i = Matrix<int, 1, 1>;
using Vector2i = Matrix<int, 2, 2>;
using Vector3i = Matrix<int, 3, 3>;
using Vector4i = Matrix<int, 4, 4>;

using Vector1f = Matrix<float, 1, 1>;
using Vector2f = Matrix<float, 2, 2>;
using Vector3f = Matrix<float, 3, 3>;
using Vector4f = Matrix<float, 4, 4>;

using MatrixXi = Matrix<int, 0, 0, std::vector<int>>;
using MatrixXd = Matrix<double, 0, 0, std::vector<double>>;
using MatrixXf = Matrix<float, 0, 0, std::vector<float>>;

template <typename scalarType, int rowsAtCompileTime = 0, int colsAtCompileTime = 0, typename containerType = std::array<scalarType,(rowsAtCompileTime * colsAtCompileTime)>>
class Matrix
{
private:
containerType A;
int _rows;
int _cols;
public:
Matrix() = default;
Matrix(const Matrix& m);

int rows() const;
int cols() const;
int size() const;

//Overloaded operators
scalarType operator()(const int i, const int j) const;
scalarType& operator()(const int i, const int j);
Matrix operator+(const Matrix& m) const;
Matrix operator-(const Matrix& m) const;
Matrix operator*(const Matrix& m) const;
};[/CODE]

[CODE lang="cpp" title="Matrix.cpp"]
#pragma once

#include "Matrix.h"
#include <stdexcept>

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::Matrix(const Matrix& m):A{m.A}, _rows{m.rows()}, _cols{m.cols()}, _size{m.size()}
{
}

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
int Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::rows() const
{
return _rows;
}

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
int Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::cols() const
{
return _cols;
}

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
int Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::size() const
{
return A.size();
}

/// <summary>
/// Coefficient accessors.
/// The primary coefficient accessor is the overloaded parenthesis operators. The data of the matrix
/// is stored in an underlying sequential container such as std::array or std::vector. The element
/// A(i,j) is at an offset of (i*_cols)+j in memory.
/// </summary>
/// <typeparam name="scalarType"></typeparam>
/// <typeparam name="containerType"></typeparam>
/// <param name="i">The row index</param>
/// <param name="j">The col index</param>
/// <returns>The element at position (i,j)</returns>
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
scalarType Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::operator()(const int i, const int j) const
{
containerType::const_iterator it{ A.begin() };
it = it + (i * _cols) + j;
if (it < A.end())
return *it;
else
throw std::out_of_range("\nError accessing an element beyond matrix bounds");
}

/// <summary>
/// Matrix addition.
/// Overload of the binary operator +. The left hand side and the right hand side matrix must have
/// the same number of rows and columns.
/// </summary>
/// <typeparam name="scalarType"></typeparam>
/// <typeparam name="containerType"></typeparam>
/// <param name="i"></param>
/// <param name="j"></param>
/// <returns></returns>
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
scalarType& Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::operator()(const int i, const int j)
{
containerType::iterator it{ A.begin() };
it = it + (i * _cols) + j;
if (it < A.end())
return *it;
else
throw std::out_of_range("\nError accessing an element beyond matrix bounds");
}

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType> Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::operator+(const Matrix& m) const
{
Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType> result{};

if (this->rows() == m.rows() && this->cols() == m.cols())
{
containerType::const_iterator it1{ A.begin() };
containerType::const_iterator it2{ m.A.begin() };
containerType::iterator resultIter{ result.A.begin() };
while (it1 < A.end() && it2 < m.A.end())
{
*resultIter = *it1 + *it2;
++it1; ++it2; ++resultIter;
}
}
else
{
throw std::logic_error("Matrices have different dimensions; therefore cannot be added!");
}


return result;
}

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime, typename containerType>
Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType> Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType>::operator-(const Matrix& B) const
{
Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, containerType> result{};

if (this->rows() == m.rows() && this->cols() == m.cols())
{
containerType::const_iterator it1{ A.begin() };
containerType::const_iterator it2{ m.A.begin() };
containerType::iterator resultIter{ result.A.begin() };
while (it1 < A.end() && it2 < m.A.end())
{
*resultIter = *it1 - *it2;
++it1; ++it2; ++resultIter;
}
}
else
{
throw std::logic_error("Matrices have different dimensions; therefore cannot be added!");
}
return result;
}

template<typename scalarType, int m, int n, int p, typename containerType>
Matrix<scalarType, m, p, containerType> operator*(const Matrix<scalarType, m, n, containerType>& A, const Matrix<scalarType, n, p, containerType>& B)
{
Matrix<scalarType, m, p, containerType> result;

for (int i{}; i < m; ++i)
{
for (int k{}; k < p; ++k)
{
scalarType sum{};
for (int j{}; j < n; ++j)
{
sum += A(i, j) * B(j, k);
}
result(i, k) = sum;
}
}
}
[/CODE]
Sorry for the duplication, but posting some working code now. One failure I corrected:
  • When using class templates, the member function definitions should have been in the same header-file Matrix.h, because these are really function templates (not instantiated). Failing to do this results in the compiler not instantiating them, and the linker would complain about missing symbols.
A matrix M can be initialized as, M << 1, 0, 0,
0, 1, 0,
0, 0, 1.

Nice to have functionality.

Any suggestions/feedback is super-helpful.

[CODE lang="cpp" title="Matrix.h"]
#pragma once

#include <array>
#include <vector>
#include <stdexcept>
#include <type_traits>
#include <iterator>

template <typename T, int r=0, int c=0, typename cType=std::array<T,r*c>>
class Matrix;

using Matrix1d = Matrix<double, 1, 1, std::array<double,1>>;
using Matrix2d = Matrix<double, 2, 2, std::array<double, 4>>;
using Matrix3d = Matrix<double, 3, 3, std::array<double, 9>>;
using Matrix4d = Matrix<double, 4, 4, std::array<double, 16>>;

using Matrix1i = Matrix<int, 1, 1, std::array<int, 1>>;
using Matrix2i = Matrix<int, 2, 2, std::array<int, 4>>;
using Matrix3i = Matrix<int, 3, 3, std::array<int, 9>>;
using Matrix4i = Matrix<int, 4, 4, std::array<int, 16>>;

using Matrix1f = Matrix<float, 1, 1, std::array<float, 1>>;
using Matrix2f = Matrix<float, 2, 2, std::array<float, 4>>;
using Matrix3f = Matrix<float, 3, 3, std::array<float, 9>>;
using Matrix4f = Matrix<float, 4, 4, std::array<float, 16>>;

using Vector1d = Matrix<double, 1, 1, std::vector<double>>;
using Vector2d = Matrix<double, 1, 2, std::vector<double>>;
using Vector3d = Matrix<double, 1, 3, std::vector<double>>;
using Vector4d = Matrix<double, 1, 4, std::vector<double>>;

using Vector1i = Matrix<int, 1, 1, std::vector<double>>;
using Vector2i = Matrix<int, 2, 2, std::vector<double>>;
using Vector3i = Matrix<int, 3, 3, std::vector<double>>;
using Vector4i = Matrix<int, 4, 4, std::vector<double>>;

using Vector1f = Matrix<float, 1, 1, std::vector<double>>;
using Vector2f = Matrix<float, 2, 2, std::vector<double>>;
using Vector3f = Matrix<float, 3, 3, std::vector<double>>;
using Vector4f = Matrix<float, 4, 4, std::vector<double>>;

using MatrixXi = Matrix<int, 0, 0, std::vector<int>>;
using MatrixXd = Matrix<double, 0, 0, std::vector<double>>;
using MatrixXf = Matrix<float, 0, 0, std::vector<float>>;

template <typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
class Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>
{
private:
std::array<scalarType, rowsAtCompileTime* colsAtCompileTime> A;
int _rows;
int _cols;
int _size;
typename std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>::iterator currentPosition{A.begin()};
public:
Matrix();
Matrix(int m, int n);
Matrix(const Matrix& m);

int rows() const;
int cols() const;
int size() const;

//Overloaded operators
scalarType operator()(const int i, const int j) const; //Subscript operator
scalarType& operator()(const int i, const int j); //Subscript operator const arrays
Matrix operator+(const Matrix& m) const;
Matrix operator-(const Matrix& m) const;
Matrix& operator<<(const scalarType x);
Matrix& operator,(const scalarType x);
Matrix& operator=(const Matrix& right_hand_side);
};

template <typename scalarType>
class Matrix<typename scalarType, 0, 0, std::vector<scalarType>>
{
private:
std::vector<scalarType> A;
int _rows;
int _cols;
int _size;
typename std::vector<scalarType>::iterator currentPosition{};
public:
Matrix();
Matrix(int m, int n);
Matrix(const Matrix& m);

int rows() const;
int cols() const;
int size() const;

//Overloaded operators
scalarType operator()(const int i, const int j) const;
scalarType& operator()(const int i, const int j);
Matrix operator+(const Matrix& m) const;
Matrix operator-(const Matrix& m) const;
Matrix& operator<<(const scalarType x);
Matrix& operator,(const scalarType x);
Matrix& operator=(const Matrix& right_hand_side);
};

// Non-member operator functions
template<typename scalarType, int m, int n, int p, int q>
Matrix<scalarType, m, q, std::vector<scalarType>> operator*(const Matrix<scalarType, m, n, std::vector<scalarType>>& A, const Matrix<scalarType, p, q, std::vector<scalarType>>& B);

template<typename scalarType, int m, int n, int p, int q>
Matrix<scalarType, m, q, std::array<scalarType,m*q>> operator*(const Matrix<scalarType, m, n, std::array<scalarType,m*n>>& A, const Matrix<scalarType, p, q, std::array<scalarType,p*q>>& B);


//Default constructor
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>::Matrix():_rows{rowsAtCompileTime}, _cols{colsAtCompileTime}, currentPosition{A.begin()}
{
//Do nothing.
}

//Default constructor
template<typename scalarType>
inline Matrix<typename scalarType, 0, 0, std::vector<scalarType>>::Matrix() :_rows{ 0 }, _cols{ 0 }
{
currentPosition = A.begin();
}

//Fixed-Size matrices
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType,rowsAtCompileTime * colsAtCompileTime>>::Matrix(int m, int n)
{
//Do nothing.
}

//Run-time matrices
template<typename scalarType>
inline Matrix<typename scalarType, 0, 0, std::vector<scalarType>>::Matrix(int m, int n) : currentPosition{A.begin()}
{
int numOfElements{ m * n };
for (int i{}; i < numOfElements; ++i)
{
A.push_back(0);
}
}

template<typename scalarType>
inline Matrix<typename scalarType, 0, 0, std::vector<scalarType>>::Matrix(const Matrix& m): A{m.A}, _rows{m.rows()}, _cols{m.cols()}, currentPosition{m.currentPosition}
{
}

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType,rowsAtCompileTime*colsAtCompileTime>>::Matrix(const Matrix& m) : A{ m.A }, _rows{ m.rows() }, _cols{ m.cols() }, currentPosition{ m.currentPosition }
{
}

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline int Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType,rowsAtCompileTime* colsAtCompileTime>>::rows() const
{
return _rows;
}

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline int Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>::cols() const
{
return _cols;
}

template<typename scalarType>
inline int Matrix<scalarType, 0, 0, std::vector<scalarType>>::rows() const
{
return _rows;
}

template<typename scalarType>
inline int Matrix<scalarType, 0, 0, std::vector<scalarType>>::cols() const
{
return _cols;
}

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline int Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>::size() const
{
return A.size();
}

template<typename scalarType>
inline int Matrix<scalarType, 0, 0, std::vector<scalarType>>::size() const
{
return A.size();
}

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline scalarType Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>::operator()(const int i, const int j) const
{
typename std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>::const_iterator it{ A.begin() };
it = it + (i * _cols) + j;
if (it < A.end())
return *it;
else
throw std::out_of_range("\nError accessing an element beyond matrix bounds");
}

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline scalarType& Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>::operator()(const int i, const int j)
{
typename std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>::iterator it{ A.begin() };
it = it + (i * _cols) + j;
if (it < A.end())
return *it;
else
throw std::out_of_range("\nError accessing an element beyond matrix bounds");
}

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>> Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>::operator+(const Matrix& m) const
{
Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>> result{};

if (this->rows() == m.rows() && this->cols() == m.cols())
{
typename std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>::const_iterator it1{ A.begin() };
typename std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>::const_iterator it2{ m.A.begin() };
typename std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>::iterator resultIter{ result.A.begin() };
while (it1 < A.end() && it2 < m.A.end())
{
*resultIter = *it1 + *it2;
++it1; ++it2; ++resultIter;
}
}
else
{
throw std::logic_error("Matrices have different dimensions; therefore cannot be added!");
}


return result;
}

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>> Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>::operator-(const Matrix& m) const
{
Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>> result{};

if (this->rows() == m.rows() && this->cols() == m.cols())
{
typename std::array<scalarType, rowsAtCompileTime*colsAtCompileTime>::const_iterator it1{ A.begin() };
typename std::array<scalarType, rowsAtCompileTime*colsAtCompileTime>::const_iterator it2{ m.A.begin() };
typename std::array<scalarType, rowsAtCompileTime*colsAtCompileTime>::iterator resultIter{ result.A.begin() };
while (it1 < A.end() && it2 < m.A.end())
{
*resultIter = *it1 - *it2;
++it1; ++it2; ++resultIter;
}
}
else
{
throw std::logic_error("Matrices have different dimensions; therefore cannot be added!");
}


return result;
}

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>& Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>::operator<<(const scalarType x)
{
if (currentPosition < A.end())
{
*currentPosition = x;
++currentPosition;
}
else
{
throw std::logic_error("Error: Attempting to set values beyond matrix bounds!");
}
return *this;
}

template<typename scalarType>
inline Matrix<typename scalarType, 0, 0, std::vector<scalarType>>& Matrix<typename scalarType, 0, 0, std::vector<scalarType>>::operator<<(const scalarType x)
{
if (currentPosition < A.end())
{
*currentPosition = x;
++currentPosition;
}
else
{
throw std::logic_error("Error: Attempting to set values beyond matrix bounds!");
}
return *this;
}

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>& Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>::operator,(const scalarType x)
{
if (currentPosition < A.end())
{
*currentPosition = x;
++currentPosition;
}
else
{
throw std::logic_error("Error: Attempting to set values beyond matrix bounds!");
}
return *this;
}

template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
inline Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>& Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime, std::array<scalarType, rowsAtCompileTime* colsAtCompileTime>>::operator=(const Matrix& right_hand_side)
{
if (this == &right_hand_side)
return *this;

this->A = right_hand_side.A;
this->_rows = right_hand_side._rows;
this->_cols = right_hand_side._cols;
this->currentPosition = right_hand_side.currentPosition;
return *this;
}

template<typename scalarType>
inline Matrix<typename scalarType, 0, 0, std::vector<scalarType>>& Matrix<typename scalarType, 0, 0, std::vector<scalarType>>::operator=(const Matrix& right_hand_side)
{
if (this == &right_hand_side)
return *this;

this->A = right_hand_side.A;
this->_rows = right_hand_side._rows;
this->_cols = right_hand_side._cols;
this->currentPosition = right_hand_side.currentPosition;
return *this;
}

template<typename scalarType>
inline Matrix<typename scalarType, 0, 0, std::vector<scalarType>>& Matrix<typename scalarType, 0, 0, std::vector<scalarType>>::operator,(const scalarType x)
{
if (currentPosition < A.end())
{
*currentPosition = x;
++currentPosition;
}
else
{
throw std::logic_error("Error: Attempting to set values beyond matrix bounds!");
}
return *this;
}

template<typename scalarType>
inline Matrix<typename scalarType, 0, 0, std::vector<scalarType>> Matrix<typename scalarType, 0, 0, std::vector<scalarType>>::operator+(const Matrix& m) const
{
Matrix<scalarType, 0, 0, std::vector<scalarType>> result{};

if (this->rows() == m.rows() && this->cols() == m.cols())
{
typename std::vector<scalarType>::const_iterator it1{ A.begin() };
typename std::vector<scalarType>::const_iterator it2{ m.A.begin() };
typename std::vector<scalarType>::iterator resultIter{ result.A.begin() };
while (it1 < A.end() && it2 < m.A.end())
{
*resultIter = *it1 - *it2;
++it1; ++it2; ++resultIter;
}
}
else
{
throw std::logic_error("Matrices have different dimensions; therefore cannot be added!");
}


return result;
}

template<typename scalarType>
inline Matrix<typename scalarType, 0, 0, std::vector<scalarType>> Matrix<typename scalarType, 0, 0, std::vector<scalarType>>::operator-(const Matrix& m) const
{
Matrix<scalarType, 0, 0, std::vector<scalarType>> result{};

if (this->rows() == m.rows() && this->cols() == m.cols())
{
typename std::vector<scalarType>::const_iterator it1{ A.begin() };
typename std::vector<scalarType>::const_iterator it2{ m.A.begin() };
typename std::vector<scalarType>::iterator resultIter{ result.A.begin() };
while (it1 < A.end() && it2 < m.A.end())
{
*resultIter = *it1 + *it2;
++it1; ++it2; ++resultIter;
}
}
else
{
throw std::logic_error("Matrices have different dimensions; therefore cannot be added!");
}


return result;
}

template<typename scalarType, int m, int n, int p, int q>
inline Matrix<scalarType, m, q, std::vector<scalarType>> operator*(const Matrix<scalarType, m, n, std::vector<scalarType>>& A, const Matrix<scalarType, p, q, std::vector<scalarType>>& B)
{
if (n != p)
throw std::logic_error("Error multiplying the matrices; the number of cols(A) must equal the number of rows(B)!");

Matrix<scalarType, m, q, std::vector<scalarType>> result;

for (int i{}; i < m; ++i)
{
for (int k{}; k < p; ++k)
{
scalarType sum{};
for (int j{}; j < n; ++j)
{
sum += A(i, j) * B(j, k);
}
result(i, k) = sum;
}
}

return result;
}

template<typename scalarType, int m, int n, int p, int q>
Matrix<scalarType, m, q, std::array<scalarType, m* q>> operator*(const Matrix<scalarType, m, n, std::array<scalarType, m* n>>& A, const Matrix<scalarType, p, q, std::array<scalarType, p* q>>& B)
{
if (n != p)
throw std::logic_error("Error multiplying the matrices; the number of cols(A) must equal the number of rows(B)!");

Matrix<scalarType, m, q, std::array<scalarType, m * q>> result;

for (int i{}; i < m; ++i)
{
for (int k{}; k < p; ++k)
{
scalarType sum{};
for (int j{}; j < n; ++j)
{
sum += A(i, j) * B(j, k);
}
result(i, k) = sum;
}
}

return result;
}
[/CODE]

[CODE lang="cpp" title="TestMatrix.cpp"]
// MatrixImpl.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include <iostream>
#include "Matrix.h"
#include <iomanip>

int main()
{
Matrix<int, 3, 3> m1;
m1 <<1, 0, 0,
0, 1, 0,
0, 0, 1;

Matrix<int, 3, 3> m2;
m2 << 2, 0, 0,
0, 1, 0,
0, 0, 3;

Matrix<int, 3, 3> m3 = m1 + m2;

for (int i{}; i < 3; ++i)
{
for (int j{}; j < 3; ++j)
{
std::cout << std::setw(5) << m3(i, j);
}
std::cout << std::endl;
}
return 0;
}
[/CODE]
 
the notation m << .. is kinda non-standard and a bit weird. See how Python does it. And Boost uBLAS.

C++ initialisation

Hi Daniel,
  • Added a constructor that takes std::initializer_list<std::initializer_list<T>> as a parameter and initializes the matrix.

C++:
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
Matrix<typename scalarType, rowsAtCompileTime, colsAtCompileTime>::Matrix(std::initializer_list<std::initializer_list<scalarType>> list):Matrix<scalarType,rowsAtCompileTime,colsAtCompileTime>{}    //Delegate to the default constructor to set up the initial array
{
    // Initialize the array from our list.
    typename std::array<scalarType,rowsAtCompileTime*colsAtCompileTime>::iterator A_it{ A.begin() };
    typename std::initializer_list<std::initializer_list<scalarType>>::iterator i{};

    for (i = list.begin(); i < list.end(); ++i)
    {
        typename std::initializer_list<scalarType>::iterator j{};
        for (j = (*i).begin(); j < (*i).end(); ++j)
        {
            *A_it = *j;
            ++A_it;
        }
    }
}

  • Pretty printing the matrix in a rectangular format.
C++:
template<typename scalarType, int rowsAtCompileTime, int colsAtCompileTime>
std::ostream& operator<<(std::ostream& os, Matrix<scalarType, rowsAtCompileTime, colsAtCompileTime>& m)
{
    for (int i{}; i < m.rows(); ++i)
    {
        os << "Row(";
        for (int j{}; j < m.cols(); ++j)
        {
            if (j != m.cols() - 1)
                os << m(i, j) << std::setw(5);
            else
                os << m(i, j);
            if (j % 10 == 0 && j > 0)
                os << std::endl;
        }

        os << ")" << std::endl;
    }

    return os;
}
  • Multiplication with scalars.
C++:
template<typename scalarType, int m, int n, typename T>
Matrix<scalarType, m, n>& operator*(const T k, Matrix<scalarType, m, n>& mat)
{
    for (int i{}; i < m.rows(); ++i)
    {
        for (int j{}; j < m.cols(); ++j)
        {
            mat(i, j) *= k;
        }
    }

    return mat;
}

  • Created two separate types : Matrix for compile-time matrices and MatrixX for run-time matrices, since they really are different, instead of shoe-horning them into one.
I think something that might make this piece of code more useful, is the ability to promote a matrix e.g. from Matrix<int> to Matrix<long>(of the same dimensions). Right now, addition is too restrictive.

Quick Question - I am building this project in VS as a DLL. But, libraries are no good use, if traders/structurers/risk managers can't easily use them. I have seen a couple of solutions that allow exposing this functionality to excel. Do you have any suggestions?

Also, I read up a bit on the net, and my understanding is __declspec(dllexport) is used to expose C++ class member functions in a DLL to the the outside. Is my understanding correct?
 
Last edited:
Back
Top Bottom