Matrix multiplication (with different dimensions) - c++

For Math class in school I need to create an application that does something (just anything) with matrices. I decided to create a matrix calculator. I have a Matrix class which contains a 2D array, an row integer and a column integer. I created the following function to multiply two matrices:
public: Matrix* multiply(Matrix* other)
{
Matrix* temp = new Matrix(other->r, other->c);
for(int i = 0; i < this->r; i++)
{
for(int j = 0; j < this->c; j++)
{
for(int k = 0; k < other->c; k++)
temp->mat[i][j] += this->mat[i][k] * other->mat[k][j];
}
}
return temp;
}
This works perfectly, but only if I multiply matrices with the same dimensions (e.g. Mat4x4*Mat4x4 or Mat2x4*Mat2x4). I understand I can't just multiply an Mat4x4 with an Mat9X2 or anything, but I do know the second matrix's columns should be equal to the first matrix's rows (so a Mat2x2 should be able to multiply with a Mat2x1) and that the answer will have the dimensions of the second matrix. How could (or should) I make the function so it will multiply the matrices with the same and with different dimensions?
Thanks in advance

A solution for your program would be to make the temp dimensions not the others dimension but this->r, other->c in order to make the dimensions valid with the outputs from the matrix multiplication.
Hope this helps.

The following code contains a Matrix class implementation meant to show a few features of C++ (like unique pointers, random numbers, and stream formatting). I often use it when I want to explain a little bit about the language. Maybe it can help you.
#include <cassert>
#include <iostream>
#include <iomanip>
#include <memory>
#include <random>
// Pedagogical implementation of matrix type.
class Matrix {
public:
// Create a rows-by-cols matrix filled with random numbers in (-1, 1).
static Matrix Random(std::size_t rows, std::size_t cols) {
Matrix m(rows, cols);
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<double> dis(-1, 1);
for (std::size_t row = 0; row < rows; ++row) {
for (std::size_t col = 0; col < cols; ++col) {
m(row, col) = dis(gen);
}
}
return m;
}
// Build an uninitialized rows-by-cols matrix.
Matrix(std::size_t rows, std::size_t cols)
: m_data { std::make_unique<double[]>(rows * cols) },
m_rows { rows },
m_cols { cols }
{
assert(m_rows > 0);
assert(m_cols > 0);
}
// Return number of rows
std::size_t rows() const { return m_rows; }
// Return number of columns
std::size_t cols() const { return m_cols; }
// Value at (row, col)
double operator()(std::size_t row, std::size_t col) const {
assert(row < rows());
assert(col < cols());
return m_data[row * cols() + col];
}
// Reference to value at (row, col)
double& operator()(std::size_t row, std::size_t col) {
assert(row < rows());
assert(col < cols());
return m_data[row * cols() + col];
}
// Matrix multiply
Matrix operator*(const Matrix& other) const {
assert(cols() == other.rows());
Matrix out(rows(), other.cols());
for (std::size_t i = 0; i < rows(); ++i) {
for (std::size_t j = 0; j < other.cols(); ++j) {
double sum { 0 };
for (std::size_t k = 0; k < cols(); ++k) {
sum += (*this)(i, k) * other(k, j);
}
out(i, j) = sum;
}
}
return out;
}
private:
std::unique_ptr<double[]> m_data; // will cleanup after itself
const std::size_t m_rows;
const std::size_t m_cols;
};
// Pretty-print a matrix
std::ostream& operator<<(std::ostream& os, const Matrix& m) {
os << std::scientific << std::setprecision(16);
for (std::size_t row = 0; row < m.rows(); ++row) {
for (std::size_t col = 0; col < m.cols(); ++col) {
os << std::setw(23) << m(row, col) << " ";
}
os << "\n";
}
return os;
}
int main() {
Matrix A = Matrix::Random(3, 4);
Matrix B = Matrix::Random(4, 2);
std::cout << "A\n" << A
<< "B\n" << B
<< "A * B\n" << (A * B);
}
Possible output:
$ clang++ matmul.cpp -std=c++17 -Ofast -march=native -Wall -Wextra
$ ./a.out
A
1.0367049464391398e-01 7.4917987082978588e-03 -2.7966084757805687e-01 -7.2325095373639048e-01
2.2478938813996119e-01 8.4194832286446353e-01 5.3602376615184033e-01 7.1132727553003439e-01
1.9608747339865196e-01 -6.4829263198209253e-01 -2.7477471919710350e-01 1.2721104074473044e-01
B
-8.5938605801284385e-01 -6.2981285198013204e-01
-6.0333085647033191e-01 -6.8234173530317577e-01
-1.2614486249714407e-01 -3.3875904433100934e-01
-6.9618174970366520e-01 6.6785401241316045e-01
A * B
4.4517888255515814e-01 -4.5869338680118737e-01
-1.2639839804611623e+00 -4.2259184895688506e-01
1.6871952235091500e-01 4.9689953389829533e-01

It turnes out the order of the rows and columns got me heckin' bamboozled. The formula was correct. Sorry for unnecessary post.

Related

Operator Overloading Matrix Multiplication

The issue I am having is how to get the correct number columns to go through for the inner most loop of K.
An example is a 2x3 matrix and a 3x2 matrix being multiplied.
The result should be a 2x2 matrix, but currently I dont know how to send the value of 2 to the operator overloaded function.
It should be
int k = 0; k < columns of first matrix;k++
Matrix::Matrix(int row, int col)
{
rows = row;
cols = col;
cx = (float**)malloc(rows * sizeof(float*)); //initialize pointer to pointer matrix
for (int i = 0; i < rows; i++)
*(cx + i) = (float*)malloc(cols * sizeof(float));
}
Matrix Matrix::operator * (Matrix dx)
{
Matrix mult(rows, cols);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
mult.cx[i][j] = 0;
for (int k = 0; k < ?;k++) //?????????????
{
mult.cx[i][j] += cx[i][k] * dx.cx[k][j];
}
}
}
mult.print();
return mult;
//calling
Matrix mult(rowA, colB);
mult = mat1 * mat2;
}
Linear algebra rules say the result should have dimensions rows x dx.cols
Matrix Matrix::operator * (Matrix dx)
{
Matrix mult(rows, dx.cols);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
mult.cx[i][j] = 0;
for (int k = 0; k < cols;k++) //?????????????
{
mult.cx[i][j] += cx[i][k] * dx.cx[k][j];
}
}
}
mult.print();
return mult;
A few random hints:
Your code is basically C; it doesn’t use (e.g.) important memory-safety features from C++. (Operator overloading is the only C++-like feature in use.) I suggest that you take advantage of C++ a bit more.
Strictly avoid malloc() in C++. Use std::make_unique(...) or, if there is no other way, a raw new operator. (BTW, there is always another way.) In the latter case, make sure there is a destructor with a delete or delete[]. The use of malloc() in your snippet smells like a memory leak.
What can be const should be const. Initialize as many class members as possible in the constructor’s initializer list and make them const if appropriate. (For example, Matrix dimensions don’t change and should be const.)
When writing a container-like class (which a Matrix may be, in a sense), don’t restrict it to a single data type; your future self will thank you. (What if you need a double instead of a float? Is it going to be a one-liner edit or an all-nighter spent searching where a forgotten float eats away your precision?)
Here’s a quick and dirty runnable example showing matrix multiplication:
#include <cstddef>
#include <iomanip>
#include <iostream>
#include <memory>
namespace matrix {
using std::size_t;
template<typename Element>
class Matrix {
class Accessor {
public:
Accessor(const Matrix& mat, size_t m) : data_(&mat.data_[m * mat.n_]) {}
Element& operator [](size_t n) { return data_[n]; }
const Element& operator [](size_t n) const { return data_[n]; }
private:
Element *const data_;
};
public:
Matrix(size_t m, size_t n) : m_(m), n_(n),
data_(std::make_unique<Element[]>(m * n)) {}
Matrix(Matrix &&rv) : m_(rv.m_), n_(rv.n_), data_(std::move(rv.data_)) {}
Matrix operator *(const Matrix& right) {
Matrix result(m_, right.n_);
for (size_t i = 0; i < m_; ++i)
for (size_t j = 0; j < right.n_; ++j) {
result[i][j] = Element{};
for (size_t k = 0; k < n_; ++k) result[i][j] +=
(*this)[i][k] * right[k][j];
}
return result;
}
Accessor operator [](size_t m) { return Accessor(*this, m); }
const Accessor operator [](size_t m) const { return Accessor(*this, m); }
size_t m() const { return m_; }
size_t n() const { return n_; }
private:
const size_t m_;
const size_t n_;
std::unique_ptr<Element[]> data_;
};
template<typename Element>
std::ostream& operator <<(std::ostream &out, const Matrix<Element> &mat) {
for (size_t i = 0; i < mat.m(); ++i) {
for (size_t j = 0; j < mat.n(); ++j) out << std::setw(4) << mat[i][j];
out << std::endl;
}
return out;
}
} // namespace matrix
int main() {
matrix::Matrix<int> m22{2, 2};
m22[0][0] = 0; // TODO: std::initializer_list
m22[0][1] = 1;
m22[1][0] = 2;
m22[1][1] = 3;
matrix::Matrix<int> m23{2, 3};
m23[0][0] = 0; // TODO: std::initializer_list
m23[0][1] = 1;
m23[0][2] = 2;
m23[1][0] = 3;
m23[1][1] = 4;
m23[1][2] = 5;
matrix::Matrix<int> m32{3, 2};
m32[0][0] = 5; // TODO: std::initializer_list
m32[0][1] = 4;
m32[1][0] = 3;
m32[1][1] = 2;
m32[2][0] = 1;
m32[2][1] = 0;
std::cout << "Original:\n\n";
std::cout << m22 << std::endl << m23 << std::endl << m32 << std::endl;
std::cout << "Multiplied:\n\n";
std::cout << m22 * m22 << std::endl
<< m22 * m23 << std::endl
<< m32 * m22 << std::endl
<< m23 * m32 << std::endl
<< m32 * m23 << std::endl;
}
Possible improvements and other recommendations:
Add consistency checks. throw, for example, a std::invalid_argument when dimensions don’t match on multiplication, i.e. when m_ != right.n_, and a std::range_error when the operator [] gets an out-of-bounds argument. (The checks may be optional, activated (e.g.) for debugging using an if constexpr.)
Use a std::initializer_list or the like for initialization, so that you can have (e.g.) a const Matrix initialized in-line.
Always check your code using valgrind. (Tip: Buliding with -g lets valgrind print also the line numbers where something wrong happened (or where a relevant preceding (de)allocation had happened).)
The code could me made shorter and more elegant (not necessarily more efficient; compiler optimizations are magic nowadays) by not using operator [] everywhere and having some fun with pointer arithmetics instead.
Make the type system better, so that (e.g.) Matrix instances with different types can play well with each other. Perhaps a Matrix<int> multiplied by a Matrix<double> could yield a Matrix<double> etc. One could also support multiplication between a scalar value and a Matrix. Or between a Matrix and a std::array, std::vector etc.

Building a submatrix from a matrix

I'm trying to split a matrix given into 4, but I'm getting some errors and I can't figure out why. I'm kind of new to the language. Does anybody knows what am I doing wrong?
void split_tl(T **matrice, unsigned int dim){
if(dim == 1){
return;
}
T **tl = new T*[dim/4];
for(unsigned int i = 0; i<dim/4;++i){
tl[i] = new T[dim/4];
}
for(unsigned int i=0; i<dim;++i){
for(unsigned int j=0; j<dim;j++){
if((i<dim/2) && (j<dim/2)){
tl[i][j] = matrice[i][j];
} else{
std::cout << "no ";
}
}
std::cout << std::endl;
}
}
In this function I'm trying to obtain the top left corner of the matrix.
int **matrice = new int*[2];
for(unsigned int i = 0; i<2;++i){
matrice[i] = new int[2];
}
for(unsigned int i = 0; i<2;++i){
for(unsigned int j = 0; j<2;++j){
matrice[i][j] = i+j;
}
}
This is the matrix I'm sending. It is a 2x2 matrix, just for testing purposes.
These are the errors from Valgrind:
==133== Invalid read of size 8
==133== Invalid write of size 4
==133== Process terminating with default action of signal 11 (SIGSEGV)
==133== Access not within mapped region at address 0x0
If dim is the side of a matrix, allocating to a quarter matrix should be dim/2.
Below in the code you are using :
if((i<dim/2) && (j<dim/2)){
tl[i][j] = matrice[i][j];
}
here tl may exceed the allocation
What you're doing wrong? You're allocating memory and passing pointers around.
Build a proper matrix class, e.g. (very simplified version):
template <typename T, unsigned Rows, unsigned Cols>
struct generic_matrix {
using datatype = T;
static constexpr unsigned rows = Rows;
static constexpr unsigned cols = Cols;
datatype data[rows][cols];
constexpr datatype& operator()(unsigned row, unsigned col) noexcept
{ return data[row][col]; }
constexpr const datatype& operator()(unsigned row, unsigned col) const noexcept
{ return data[row][col]; }
};
Submatrix:
/* Returns a submatrix of the matrix m,
* by deleting the row r and the column c.*/
template <typename M>
auto submatrix(const M& m, unsigned r, unsigned c) noexcept
{
generic_matrix<typename M::datatype, M::rows-1, M::cols-1> res;
for (unsigned row = 0, i = 0; row < M::rows; ++row) {
if (row == r) continue; //this row we do not want
for (unsigned col = 0, j = 0; col < M::cols; ++col) {
if (col == c) continue; //this col we do not want
res(i,j) = m(row,col);
++j;
}
++i;
}
return res;
}
Print:
template <typename M>
void printmatrix(const M& m) noexcept
{
for (unsigned r=0; r < M::rows; ++r) {
for (unsigned c=0; c < M::cols; ++c) {
std::cout << m(r,c) << ' ';
}
std::cout << '\n';
}
}
Test:
int main()
{
int n=0;
generic_matrix<int, 3, 3> m;
for (int r = 0; r < 3; ++r)
for (int c = 0; c < 3; ++c)
m(r,c) = ++n;
printmatrix(m);
std::cout << '\n';
printmatrix(submatrix(m, 0, 0));
std::cout << '\n';
printmatrix(submatrix(m, 1, 1));
std::cout << '\n';
printmatrix(submatrix(m, 2, 2));
return 0;
}
Note: It is just a hint. As you can see, no allocation nor casting is needed.

How can I multiply two matrices if I only store non-zero elements in a list<list<pair<int,double>>>? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
So I got my Data structures and algorithms project. I basically need to develop a class Matrix with following atributes:
list<list<pair<int,double>>>, (In which are only non-zero elements of a Matrix. Value of a certain element is stored as the second argument of a pair, and the first argument of a pair represents an actual column in which that element is located in the original Matrix)
vector< int> rows, (rows[i] - Represents an actual row for each list in a list of lists above, respectively)
Actual number of rows,
Actual number of columns.
In my project so far I have developed specific constructors, adding and substracting matrices etc. The only thing that I am not able to do is multiply two instances of a class Matrix, meaning I am not able to develop an operator* for class Matrix.
Explanation of the problem:
Assuming I have the following two instances of class Matrix:
Instance A:
list<list<pair<int,double>>>: {{{10,5},{40,15}},{{50,25}},{{80,35}}}
vector<int>: {2,10,70};
actual number of rows: 100
actual number of columns: 100
Instance B:
list<list<pair<int,double>>>: {{{1,6},{2,5},{3,7}},{{3,4}},{{80,1}}}
vector<int>: {1,2,33};
actual number of rows: 100
actual number of columns: 100
Obviously multiplication is defined for these matrices since the number of columns of matrix A is equal to the number of rows of matrix B.
I am having trouble with finding the correct algorithm for multiplying these matrices.
Can somebody write in short lines what could be one of the algorithms for multiplying these.
The main idea consists in having convenient primitive to set/get the value at position (i, j) of a matrix, its number of rows and its number of column.
For sake of simplicity, I replaced in the following code your top list by a vector (it's more efficient as you have random access to the i-th value):
#include <cassert>
#include <iostream>
#include <list>
#include <vector>
using namespace std;
class Matrix {
private:
vector<list<pair<unsigned, double>>> data;
unsigned m;
unsigned n;
public:
Matrix(unsigned m, unsigned n):
m(m),
n(n),
data(m)
{}
inline unsigned num_rows() const {
return m;
}
inline unsigned num_columns() const {
return n;
}
double get(unsigned i, unsigned j) const {
for (pair<unsigned, double> p : data[i]) {
if (p.first == j) return p.second;
}
return 0.0;
}
void set(unsigned i, unsigned j, double v) {
for (pair<unsigned, double> p : data[i]) {
if (p.first == j) {
p.second = v;
return;
}
}
if (v) {
data[i].push_back(make_pair(j, v));
}
}
};
Matrix operator * (const Matrix & a, const Matrix & b) {
unsigned m = a.num_rows(),
n = b.num_columns(),
k_max = a.num_columns();
assert (a.num_columns() == b.num_rows());
Matrix c(m, n);
for (unsigned i = 0; i < m; i++) {
for (unsigned j = 0; j < n; j++) {
double value = 0;
for (unsigned k = 0; k < k_max; k++) {
value += a.get(i, k) * b.get(k, j);
}
if (value) c.set(i, j, value);
}
}
return c;
}
ostream & operator << (ostream & out, const Matrix & a) {
for (unsigned i = 0; i < a.num_rows(); i++) {
for (unsigned j = 0; j < a.num_columns(); j++) {
out << a.get(i, j) << "\t";
}
out << endl;
}
return out;
}
int main() {
Matrix a(2, 3), b(3, 1);
for (unsigned i = 0; i < a.num_rows(); i++) {
for (unsigned j = 0; j < a.num_columns(); j++) {
a.set(i, j, 10 * i + j);
}
}
for (unsigned i = 0; i < b.num_rows(); i++) {
for (unsigned j = 0; j < b.num_columns(); j++) {
b.set(i, j, 10 * (i + 1));
}
}
Matrix c = a * b;
cout << "a:" << endl << a << endl
<< "b:" << endl << b << endl
<< "c:" << endl << c << endl
;
return 0;
}
Result:
a:
0 1 2
10 11 12
b:
10
20
30
c:
80
680

How can I turn a set of set of integers into 3D vectors in C++?

I have a data matrix in an array of data[12][51] which is a 12 by 51 matrix.
If I have set<set<int>> rows as, for example,
{(1,2,5),(3,7,8),(9,11)} would denote rows indices of the data matrix.
I want to form matrices given those sets of rows indices, so the element of (1,2,5) would be a 3 by 51 matrix comprised by 1st, 2nd, and 5th rows of the data matrix.
vector<double> features[12];
for (int i = 0; i < 12; i++){
for (int j = 0; j < 51; j++){
features[i].push_back(data[i][j]);
}
}
So in the above section, features[i] would return an entire i'th row of the data matrix. And given an arbitrarily sized set<set<int>> rows,
vector<vector<vector<double>>> sets;
for (auto & it : rows){
vector<vector<double>> temp;
for (int i : it){
temp.push_back(features[i]);
}
sets.push_back(temp);
}
But when I try to print such vector of matrices, via,
for (int i = 0; i < sets.size(); i++){
for (int j = 0; j < sets[0].size(); j++){
for (int z = 0; z < sets[0][0].size(); z++){
cout << sets[i][j][z] << " , ";
}
cout << endl;
}
cout << " === Matrix === " << endl;
}
The executable freezes and just stops.
So, if the above method shouldn't be working, then how can I turn a set of set of integers into 3D vectors?
It's always nice to have a ready-made, all-purpose dynamically sized matrix in one's toolbox... It'even nicer when you don't have to link in a library, and can pop it in any project at anytime. I'm sure there are thousands of them out there.
Add toppings as needed, and keep the all-dressed file in a safe place.
Things you could add: Get a submatrix, addition, etc.
#include <vector>
#include <algorithm>
template <typename T>
class Matrix
{
private:
typedef std::vector<std::vector<T>> _Mat;
_Mat matrix_;
public:
Matrix(int rows, int cols)
{
matrix_.resize(rows);
for (auto& v : matrix_)
{
v.resize(cols);
}
}
Matrix(int rows, int cols, const T* data)
{
matrix_.resize(rows);
for (auto& v : matrix_)
{
v = std::vector<T>(data, data + cols);
data += cols;
}
}
size_t rowCount() const
{
return matrix_.size();
}
size_t colCount() const
{
return (rowCount()) ? matrix_[0].size() : 0;
}
const std::vector<T>& getRow(int n) const
{
return matrix_.at(n);
}
void setRow(int row, const std::vector<T>& v)
{
if (row >= rowCount() || v.size() != colCount())
{
throw std::exception(); // choose your favorite exception class
}
matrix_.at(row) = v;
}
std::vector<T> getCol(int col)
{
std::vector<T> result;
std::for_each(matrix_.begin(), matrix_.end(),
[&](std::vector<T>& r)
{
result.push_back(r.at(col));
});
return result;
}
void setCol(size_t col, const std::vector<T>& v)
{
if (col >= colCount() || v.size() != rowCount())
{
throw std::exception(); // choose your favorite exception class
}
for (size_t i = 0; i < matrix_.size(); ++i)
{
matrix_[i][col] = v[i];
}
}
std::vector<T>& operator[](size_t row)
{
return matrix_.at(row);
}
const std::vector<T>& operator[](size_t row) const
{
return matrix_.at(row);
}
};
int main()
{
Matrix<double> a(12, 51);
Matrix<double> b(3, 51);
Matrix<double> c(12, 2);
b.setRow(0, a.getRow(1));
b.setRow(1, a.getRow(25));
b.setRow(2, a.getRow(12));
Matrix<double> c(12, 2);
c.setCol(0, a.getRow(3));
c.setCol(1, a.getCol(4)); // << throws!!
std::vector<Matrix<double>> matrices;
matrices.push_back(a);
matrices.push_back(b);
matrices.push_back(c);
Matrix<std::vector<double>> matrixOfVectors;
return 0;
}
why not to use style like this:
int nMatrix[rowSize][volumnSize][deepSize] = { 0 };
Actually, we usually use array to operate 3D data

How can I return an array of matrices of differing sizes in c++?

I'm not so advanced in c++ yet, but I'm trying to perform clustering analysis,
the data, vector< vector< double>> X, is M by T, with M features and T data points, I'm trying to group features into sets in which the distance correlation between each of the features within the set is above a certain threshold. The distCorrelation function is already defined by the way.
set<vector<double>> clusterIndices(vector<vector<double>> &X, double threshold){
vector<double> feature[X.size()];
for(int i = 0; i < X.size(); i++){
for(int j = 0; j < X[0].size(); j++){
feature[i].push_back(X[i][j]);
}
}
vector<vector<double>> distCorrMatrix(X.size(), vector<double> (X.size()));
for (int i = 0; i < X.size(); i++){
for (int j = 0; j < X.size(); j++){
distCorrMatrix[i][j] = (distCorrelation(feature[i],feature[j]) >= threshold ? 1.0 : 0.0);
}
}
set<vector<double>> rows;
for (int i = 0; i < X.size(); i++){
vector<int> temp;
for (int j = 0; j < X.size(); j++){
if (distCorrMatrix[i][j] == 1){
temp.push_back(j);
}
}
rows.insert(temp);
}
return rows;
}
So the above code will produce sets of features with mutually high correlation but will only give indices of those features.
That is, the returned rows could be (1,2,5) , (3,7,8,10) ... etc which translates to (feature[1],feature[2],feature[5]) , (feature[3],feature[7],feature[8],feature[10]) ...etc in which feature[i] represents i'th row of the data matrix.
The problem is I don't know how I can create a function that turns those each sets into matrices and return them.
No, your code won't compile. You should do it like this:
// k is the number of clusters
vector<vector<vector<double> > > myFunction(vector<vector<double> > &X, int k) {
vector<vector<vector<double> > > result(k);
for (int i = 0; i < X.size(); i++){
//do something then know X[i] belongs to cluster j
result[j].push_back(X[i]);
}
return result;
}
From what I can tell, you want this
std::vector<int> myclusteringfunction(std::vector<std::vector<double> > const &dataitems)
{
/* assign a cluster id to each data item */
std::vector<int> answer;
for(i=0;i<dataitems.size();i++)
answer.push_back( /* get the cluster id for each data item */);
/* return the ids as a list of the same length as your input list
eg {0, 1, 2, 1, 1, 1, 2, 2, 0, 0, 3, 1, 1, 1, 1} for four clusters */
return answer;
}
Your input seems unclear, but we can go this way: (check function getVectorOfMatrices)
#include <vector>
#include <iostream>
/**
* A classic 2D matrix implementation.
* Pay attention to the constructors and the operator=.
*/
class Matrix2D {
public:
// Standard constructor, allocates memory and initializes.
Matrix2D(const unsigned int rows, const unsigned int columns)
: m_rows(rows), m_columns(columns) {
m_data = new float*[rows];
for(unsigned row = 0; row < rows; ++row) {
m_data[row] = new float[columns];
for (unsigned column = 0; column < columns; ++column) {
m_data[row][column] = 0;
}
}
}
// Copy-constructor - also allocates and initializes.
Matrix2D(const Matrix2D& rhs) {
m_rows = rhs.m_rows;
m_columns = rhs.m_columns;
m_data = new float*[rhs.m_rows];
for (unsigned row = 0; row < rhs.m_rows; ++row) {
m_data[row] = new float[rhs.m_columns];
for (unsigned column = 0; column < rhs.m_columns; ++column) {
m_data[row][column] = rhs.at(row, column);
}
}
}
// Affectation operator - also allocates memory and initializes.
Matrix2D& operator=(const Matrix2D& rhs) {
m_rows = rhs.m_rows;
m_columns = rhs.m_columns;
m_data = new float*[rhs.m_rows];
for (unsigned row = 0; row < rhs.m_rows; ++row) {
m_data[row] = new float[rhs.m_columns];
for (unsigned column = 0; column < rhs.m_columns; ++column) {
m_data[row][column] = rhs.at(row, column);
}
}
}
// Used to set values in the 2D matrix
// NOTA : This function should check row vs m_rows and column vs m_columns
float& at(const unsigned int row, const unsigned int column) {
return m_data[row][column];
}
// Used to get values of the 2D matrix
// NOTA : This function should check row vs m_rows and column vs m_columns
const float at(const unsigned int row, const unsigned int column) const {
return m_data[row][column];
}
// Debug tool - prints the matrix
void print() const {
for (unsigned row = 0; row < m_rows; ++row) {
for (unsigned column = 0; column < m_columns; ++column) {
std::cout << " " << m_data[row][column] << " ";
}
std::cout << std::endl;
}
}
// Destructor - deallocates the memory
~Matrix2D() {
for (unsigned int row=0; row<m_rows; ++row) {
delete[] m_data[row];
}
delete[] m_data;
}
private:
unsigned int m_rows; // y-size
unsigned int m_columns; // x-size
float** m_data; // the data
};
/*
* Function that creates and returns a vector of 2D matrices
* Matrices are of different sizes
*/
std::vector<Matrix2D> getVectorOfMatrices() {
Matrix2D m1(1,1);
Matrix2D m2(2,2);
Matrix2D m3(3,3);
Matrix2D m4(4,2);
m1.at(0, 0) = 4;
m2.at(0, 1) = 2;
m4.at(1, 1) = 8;
std::vector<Matrix2D> result;
result.push_back(m1);
result.push_back(m2);
result.push_back(m3);
result.push_back(m4);
return result;
}
/*
* Main - simply call our function.
*/
int main () {
std::vector<Matrix2D> vec = getVectorOfMatrices();
for(std::vector<Matrix2D>::iterator it = vec.begin(); it != vec.end(); ++it) {
it->print();
}
return 0;
}