fbpx

C++: Matrix Transposition

Bjarne-stroustrup
 


Transpose an arbitrarily sized rectangular Matrix.

Library: Boost.uBLAS

#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/io.hpp>

int main()
{
	using namespace boost::numeric::ublas;

	matrix<double> m(3,3);

	for(int i=0; i!=m.size1(); ++i)
	for(int j=0; j!=m.size2(); ++j)
	m(i,j)=3*i+j;

	std::cout << trans(m) << std::endl;
}
Output:
 [3,3]((0,3,6),(1,4,7),(2,5,8))

Generic solution

main.cpp
#include <iostream>
#include "matrix.h"
 
#if !defined(ARRAY_SIZE)
    #define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
#endif
 
template<class T>
void printMatrix(const Matrix<T>& m) {
    std::cout << "rows = " << m.rowNum() << "   columns = " << m.colNum() << std::endl;
    for (unsigned int i = 0; i < m.rowNum(); i++) {
        for (unsigned int j = 0; j < m.colNum(); j++) {
            std::cout <<  m[i][j] << "  ";
        }
        std::cout << std::endl;
    }
} /* printMatrix() */
 
int main() {
    int  am[2][3] = {
        {1,2,3},
        {4,5,6},
    };
 
    Matrix<int> a(ARRAY_SIZE(am), ARRAY_SIZE(am[0]), am[0], ARRAY_SIZE(am)*ARRAY_SIZE(am[0]));
 
    try {
        std::cout << "Before transposition:" << std::endl;
        printMatrix(a);
        std::cout << std::endl;
        a.transpose();
        std::cout << "After transposition:" << std::endl;
        printMatrix(a);
    } catch (MatrixException& e) {
        std::cerr << e.message() << std::endl;
        return e.errorCode();
    }
 
} /* main() */

matrix.h

#ifndef _MATRIX_H
#define	_MATRIX_H

#include <sstream>
#include <string>
#include <vector>
#include <algorithm>

#define MATRIX_ERROR_CODE_COUNT 5
#define MATRIX_ERR_UNDEFINED "1 Undefined exception!"
#define MATRIX_ERR_WRONG_ROW_INDEX "2 The row index is out of range."
#define MATRIX_ERR_MUL_ROW_AND_COL_NOT_EQUAL "3 The row number of second matrix must be equal with the column number of first matrix!"
#define MATRIX_ERR_MUL_ROW_AND_COL_BE_GREATER_THAN_ZERO "4 The number of rows and columns must be greater than zero!"
#define MATRIX_ERR_TOO_FEW_DATA "5 Too few data in matrix."

class MatrixException {
private:
	std::string message_;
	int errorCode_;
public:
	MatrixException(std::string message = MATRIX_ERR_UNDEFINED);

	inline std::string message() {
		return message_;
	};

	inline int errorCode() {
		return errorCode_;
	};
};

MatrixException::MatrixException(std::string message) {
	errorCode_ = MATRIX_ERROR_CODE_COUNT + 1;
	std::stringstream ss(message);
	ss >> errorCode_;
	if (errorCode_ < 1) {
		errorCode_ = MATRIX_ERROR_CODE_COUNT + 1;
	}
	std::string::size_type pos = message.find(' ');
	if (errorCode_ <= MATRIX_ERROR_CODE_COUNT && pos != std::string::npos) {
		message_ = message.substr(pos + 1);
	} else {
		message_ = message + " (This an unknown and unsupported exception!)";
	}
}

/**
* Generic class for matrices.
*/
template <class T>
class Matrix {
private:
	std::vector<T> v; // the data of matrix
	unsigned int m;   // the number of rows
	unsigned int n;   // the number of columns
protected:

	virtual void clear() {
		v.clear();
		m = n = 0;
	}
public:

	Matrix() {
		clear();
	}
	Matrix(unsigned int, unsigned int, T* = 0, unsigned int = 0);
	Matrix(unsigned int, unsigned int, const std::vector<T>&);

	virtual ~Matrix() {
		clear();
	}
	Matrix& operator=(const Matrix&);
	std::vector<T> operator[](unsigned int) const;
	Matrix operator*(const Matrix&);
	void transpose();

	inline unsigned int rowNum() const {
		return m;
	}

	inline unsigned int colNum() const {
		return n;
	}

	inline unsigned int size() const {
		return v.size();
	}

	inline void add(const T& t) {
		v.push_back(t);
	}
};

template <class T>
Matrix<T>::Matrix(unsigned int row, unsigned int col, T* data, unsigned int dataLength) {
	clear();
	if (row > 0 && col > 0) {
		m = row;
		n = col;
		unsigned int mxn = m * n;
		if (dataLength && data) {
			for (unsigned int i = 0; i < dataLength && i < mxn; i++) {
				v.push_back(data[i]);
			}
		}
	}
}

template <class T>
Matrix<T>::Matrix(unsigned int row, unsigned int col, const std::vector<T>& data) {
	clear();
	if (row > 0 && col > 0) {
		m = row;
		n = col;
		unsigned int mxn = m * n;
		if (data.size() > 0) {
			for (unsigned int i = 0; i < mxn && i < data.size(); i++) {
				v.push_back(data[i]);
			}
		}
	}
}

template<class T>
Matrix<T>& Matrix<T>::operator=(const Matrix<T>& other) {
	clear();
	if (other.m > 0 && other.n > 0) {
		m = other.m;
		n = other.n;
		unsigned int mxn = m * n;
		for (unsigned int i = 0; i < mxn && i < other.size(); i++) {
			v.push_back(other.v[i]);
		}
	}
	return *this;
}

template<class T>
std::vector<T> Matrix<T>::operator[](unsigned int index) const {
	std::vector<T> result;
	if (index >= m) {
		throw MatrixException(MATRIX_ERR_WRONG_ROW_INDEX);
	} else if ((index + 1) * n > size()) {
		throw MatrixException(MATRIX_ERR_TOO_FEW_DATA);
	} else {
		unsigned int begin = index * n;
		unsigned int end = begin + n;
		for (unsigned int i = begin; i < end; i++) {
			result.push_back(v[i]);
		}
	}
	return result;
}

template<class T>
Matrix<T> Matrix<T>::operator*(const Matrix<T>& other) {
	Matrix result(m, other.n);
	if (n != other.m) {
		throw MatrixException(MATRIX_ERR_MUL_ROW_AND_COL_NOT_EQUAL);
	} else if (m <= 0 || n <= 0 || other.n <= 0) {
		throw MatrixException(MATRIX_ERR_MUL_ROW_AND_COL_BE_GREATER_THAN_ZERO);
	} else if (m * n > size() || other.m * other.n > other.size()) {
		throw MatrixException(MATRIX_ERR_TOO_FEW_DATA);
	} else {
		for (unsigned int i = 0; i < m; i++) {
			for (unsigned int j = 0; j < other.n; j++) {
				T temp = v[i * n] * other.v[j];
				for (unsigned int k = 1; k < n; k++) {
					temp += v[i * n + k] * other.v[k * other.n + j];
				}
				result.v.push_back(temp);
			}
		}
	}
	return result;
}

template<class T>
void Matrix<T>::transpose() {
	if (m * n > size()) {
		throw MatrixException(MATRIX_ERR_TOO_FEW_DATA);
	} else {
		std::vector<T> v2;
		std::swap(v, v2);
		for (unsigned int i = 0; i < n; i++) {
			for (unsigned int j = 0; j < m; j++) {
				v.push_back(v2[j * n + i]);
			}
		}
		std::swap(m, n);
	}
}

#endif	/* _MATRIX_H */
Output:
Before transposition:
rows = 2   columns = 3
1  2  3  
4  5  6  

After transposition:
rows = 3   columns = 2
1  4  
2  5  
3  6

Easy Mode

#include <iostream>

int main(){
	const int l = 5;
	const int w = 3;
	int m1[l][w] = {{1,2,3}, {4,5,6}, {7,8,9}, {10,11,12}, {13,14,15}};
	int m2[w][l];

	for(int i=0; i<w; i++){
		for(int x=0; x<l; x++){
			m2[i][x]=m1[x][i];
		}
	}

	// This is just output...

	std::cout << "Before:";
	for(int i=0; i<l; i++){
		std::cout << std::endl;
		for(int x=0; x<w; x++){
			std::cout << m1[i][x] << " ";
		}
	}

	std::cout << "\n\nAfter:";
	for(int i=0; i<w; i++){
		std::cout << std::endl;
		for(int x=0; x<l; x++){
			std::cout << m2[i][x] << " ";
		}
	}

	std::cout << std::endl;

	return 0;
}
Output:
Before:
1 2 3 
4 5 6 
7 8 9 
10 11 12 
13 14 15 

After:
1 4 7 10 13 
2 5 8 11 14 
3 6 9 12 15

SOURCE

Content is available under GNU Free Documentation License 1.2.