#ifndef HELPER_H_
#define HELPER_H_
#include "Matrix.h" #include <iostream>using namespace std; typedef enum {OK, MULT_ERR, ROWS_NUM, COLS_NUM, DIFF_MATRIX} StatusCode; ////////////////////////////////////////////////////////////////////////////////////////// template <typename T> unsigned CheckTestResults(Matrix<T> target, Matrix<T> test); template <typename T> StatusCode CompareMatrices(Matrix<T> m1, Matrix<T> m2); template <typename T> Matrix<T> MultMatrices(Matrix<T> m1, Matrix<T> m2) throw(StatusCode); template <typename T> Matrix<T> SubstractMatrices(Matrix<T> m1, Matrix<T> m2) throw(StatusCode); template <typename T> Matrix<T> AddMatrices(Matrix<T> m1, Matrix<T> m2) throw(StatusCode); ////////////////////////////////////////////////////////////////////////////////////////// // Check test results, report ////////////////////////////////////////////////////////////////////////////////////////// template <typename T> unsigned CheckTestResults(Matrix<T> target, Matrix<T> test) { StatusCode s = CompareMatrices(target, test); switch(s) { case OK: cout << "ok"; break; case MULT_ERR: cout << "Error during multiplication"; break; case ROWS_NUM: cout << "wrong number of rows: " << test.num_rows() << " instead of " << target.num_rows(); break; case COLS_NUM: cout << "wrong number of columns: " << test.num_columns() << " instead of " << target.num_columns(); break; case DIFF_MATRIX: cout << "result is different from expected"; break; } return (s == OK); } ////////////////////////////////////////////////////////////////////////////////////////// // Compare matrices ////////////////////////////////////////////////////////////////////////////////////////// template <typename T> StatusCode CompareMatrices(Matrix<T> m1, Matrix<T> m2) { if(m1.num_rows() != m2.num_rows()) return ROWS_NUM; if(m1.num_columns() != m2.num_columns()) return COLS_NUM; for(unsigned i=0; i<m1.num_rows(); i++) for(unsigned j=0; j<m1.num_columns(); j++) if(m1(i, j) != m2(i, j)) return DIFF_MATRIX; return OK; } ////////////////////////////////////////////////////////////////////////////////////////// // "run-time" add ////////////////////////////////////////////////////////////////////////////////////////// template <typename T> Matrix<T> AddMatrices(Matrix<T> m1, Matrix<T> m2) throw(StatusCode) { if(m1.num_rows() != m2.num_rows()) throw ROWS_NUM; if(m1.num_columns() != m2.num_columns()) throw COLS_NUM; Matrix<T> temp(m1.num_rows(), m1.num_columns()); for(unsigned i=0; i<m1.num_rows(); i++) for(unsigned j=0; j<m1.num_columns(); j++) temp(i, j) = m1(i, j) + m2(i, j); return temp; } ////////////////////////////////////////////////////////////////////////////////////////// // "run-time" substract ////////////////////////////////////////////////////////////////////////////////////////// template <typename T> Matrix<T> SubstractMatrices(Matrix<T> m1, Matrix<T> m2) throw(StatusCode) { if(m1.num_rows() != m2.num_rows()) throw ROWS_NUM; if(m1.num_columns() != m2.num_columns()) throw COLS_NUM; Matrix<T> temp(m1.num_rows(), m1.num_columns()); for(unsigned i=0; i<m1.num_rows(); i++) for(unsigned j=0; j<m1.num_columns(); j++) temp(i, j) = m1(i, j) - m2(i, j); return temp; } ////////////////////////////////////////////////////////////////////////////////////////// // "run-time" multiply ////////////////////////////////////////////////////////////////////////////////////////// template <typename T> Matrix<T> MultMatrices(Matrix<T> m1, Matrix<T> m2) throw(StatusCode) { if((m1.num_columns() != m2.num_rows()) || (m2.num_columns() != m1.num_rows())) throw MULT_ERR; Matrix<T> temp(m1.num_rows(), m2.num_columns()); for(unsigned i=0; i<m1.num_rows(); i++) for(unsigned j=0; j<m2.num_columns(); j++) { temp(i, j) = 0; for(unsigned k=0; k<m1.num_columns(); k++) temp(i, j) += m1(i, k)*m2(k, j); } return temp; } #endif /* HELPER_H_ */
|
#ifndef MATRIX_H_ #define MATRIX_H_#include <vector> #include <stdexcept> #include <ostream> #include "Expression.h" ////////////////////////////////////////////////////////////////////////////////////////// // Class Matrix // Simple implementation of 2D matrix with basic operations. Difference from other // implementation is in operator = (Expr const& expr), see below. ////////////////////////////////////////////////////////////////////////////////////////// template <typename T> class Matrix { public: // Both R and C must be strictly positive Matrix(size_t R, size_t C) {this->resize(R, C);} // Default: an empty matrix. Matrix() {} virtual ~Matrix(void) {} // The following is unusual for matrices. Expr is expected to be a derivative of // Expression, this function actually does the computation expressed by expr and // saves the result directly rather than going through temporary matrices template <class Expr> Matrix& operator = (Expr const& expr) { this->resize(expr.num_rows(), expr.num_columns()); for(unsigned i=0; i<this->num_rows(); i++) for(unsigned j=0; j<this->num_columns(); j++) (*this)(i, j) = expr(i, j); return *this; } size_t num_rows() const {return matrix.size();} size_t num_columns() const {return this->num_rows()? matrix[0].size() : 0;} // Get item at row r, column c. This operator should have two versions, regular and // const. T& operator () (unsigned r, unsigned c); const T& operator () (unsigned r, unsigned c) const; void resize(size_t R, size_t C); // Nicely prints the contents of the matrix void print (std::ostream& os) const; protected: std::vector<std::vector<T> > matrix; }; // operator << which enables us to print the contents of the matrix to an ostream template <typename T> std::ostream& operator << (std::ostream& os, const Matrix<T>& m) { m.print(os); return os; } ////////////////////////////////////////////////////////////////////////////////////////// // Class Matrix - function implementation ////////////////////////////////////////////////////////////////////////////////////////// // T& operator () (unsigned r, unsigned c) template <typename T> void Matrix<T>::resize(size_t R, size_t C) { // Make sure that both R and C are strictly positive if(!R || !C) throw std::invalid_argument("Matrix<T>::Matrix: both number of rows and columns must be strictly positive"); // matrix keeps the rows, matrix[i] represents row i matrix.resize(R); for(unsigned i=0; i<R; i++) matrix[i].resize(C); } ////////////////////////////////////////////////////////////////////////////////////////// // T& operator () (unsigned r, unsigned c) template <typename T> T& Matrix<T>::operator () (unsigned r, unsigned c) { // Make sure that the indices are legal if((r>=matrix.size()) || (c>=matrix[0].size())) throw std::out_of_range("Matrix<T>::operator (): illegal row or column indices"); return matrix[r][c]; } ////////////////////////////////////////////////////////////////////////////////////////// // const T& operator () const (unsigned r, unsigned c) template <typename T> const T& Matrix<T>::operator () (unsigned r, unsigned c) const { // The use of const_cast is generally not recommended, however in this case it saves // us from code duplication and does not cause any harm so it's OK. return((*const_cast<Matrix*>(this))(r, c)); } ////////////////////////////////////////////////////////////////////////////////////////// // void print (ostream& os) const template <typename T> void Matrix<T>::print (std::ostream& os) const { for(unsigned i=0; i<this->num_rows(); i++) { for(unsigned j=0; j<this->num_columns(); j++) { os << (*this)(i, j) << "\t"; } os << std::endl; } } #endif /* MATRIX_H_ */
|
#ifndef OPS_H_
#define OPS_H_
struct minus { static int apply(int a, int b) {return a-b;} };struct mul { static int apply(int a, int b) {return a*b;} }; ////////////////////////////////////////////////////////////////////////////////////////// // operator + overload // Rather than simply adding two matrices, create an object which will be operated at a // later time. template <class L, class R> ExpressionCellCell<L, minus, R> operator -(L const& left, R const& right) { return ExpressionCellCell<L, minus, R>(left, right); } template <class L, class R> ExpressionCellCell<L, mul, R> operator *(L const& left, R const& right) { return ExpressionCellCell<L, mul, R>(left, right); } template <class L, class R> struct ExpressionCellCell<L, mul, R> : public Expression<L, mul, R> { ExpressionCellCell(L const& left, R const& right) : Expression<L, mul, R>(left, right) {if(!this->is_legal()) throw std::length_error("ExpressionCellCell: illegal operation on matrices"); } // Operator (): simply apply the operator on left(r, c) and right(r, c) using a recursive mul calculation int operator () (unsigned r, unsigned c) const { int sum = 0; unsigned size = Expression<L, mul, R>::right.num_rows(); for (unsigned i=0; i<size; i++) sum += mul::apply(Expression<L, mul, R>::left(r, i), Expression<L, mul, R>::right(i, c)); return sum; } size_t num_rows() const {return Expression<L, mul, R>::left.num_rows();} size_t num_columns() const {return Expression<L, mul, R>::right.num_columns();} protected: bool is_legal() const { //check if the matrix are multiplyable return (Expression<L, mul, R>::left.num_columns()==Expression<L, mul, R>::right.num_rows()); } }; #endif
|
// MAIN.cpp
#include "Solution.h" #include "Helper.h" #include "Expression.h" #include <iostream> #include <stdlib.h> #include <conio.h> using namespace std; ////////////////////////////////////////////////////////////////////////////////////////// // Usage ////////////////////////////////////////////////////////////////////////////////////////// #define N 10 #define TEST(TEST_NUM, TEST_AS_STRING, target_expr, result_expr) { \ cout << "Test " << TEST_NUM << "\t|\t" << TEST_AS_STRING << "\t|\t"; \ try { \ target = target_expr; \ result = result_expr; \ success += CheckTestResults(target, result); \ } \ catch(StatusCode s) { \ switch(s) { \ case MULT_ERR: \ cout << "Error during multiplication"; \ break; \ case ROWS_NUM: \ cout << "failed during test, different number of rows between matrices"; \ break; \ case COLS_NUM: \ cout << "failed during test, different number of columns between matrices"; \ break; \ default: \ cout << "failed during test, unknown error code (" << s << ")" << endl; \ } \ } \ catch(...) { \ cout << "failed during test, unknown reason"; \ } \ cout << endl; \ } int main(int argc, const char* argv[]) { // Make sure that rand() will generate the same series of numbers each time  srand(0); unsigned success = 0; try { Matrix<int> a(N, 2*N), b(N, 2*N), c(N, 2*N), g(2*N, N), result, target; Matrix<int> d(N, N), e(N, 1), f(1, N); for(unsigned i=0; i<a.num_rows(); i++) { for(unsigned j=0; j<a.num_columns(); j++) { a(i, j) = rand()%10; b(i, j) = rand()%10; c(i, j) = rand()%10; g(j, i) = rand()%10; } e(i, 0) = rand()%10; f(0, i) = rand()%10; } /*cerr << "a:" << endl << a << endl << "g:" << endl << g << endl << "d:" << endl << d << endl << endl;*/ TEST(1, "a-b", (a-b), SubstractMatrices(a, b)) TEST(2, "a-b-c", (a-b-c), SubstractMatrices(SubstractMatrices(a, b), c)) TEST(3, "a-b+c", (a-b+c), AddMatrices(SubstractMatrices(a, b), c)) TEST(4, "a-a+a", (a-a+a), AddMatrices(SubstractMatrices(a, a), a)) d = a*g; TEST(5, "a*g", d, MultMatrices(a, g)) TEST(6, "d*d", (d*d), MultMatrices(d, d)) TEST(7, "d*d*d", (d*d*d), MultMatrices(d, MultMatrices(d, d))) TEST(8, "d*d+d-d", (d*d+d-d), SubstractMatrices(AddMatrices(MultMatrices(d, d), d), d)) TEST(9, "e*f", (e*f), MultMatrices(e, f)) TEST(10, "f*e", (f*e), MultMatrices(f, e)) } catch(exception& e) { cout << "Fatal error during test: " << e.what() << endl; while(!kbhit()) ; return 1; } catch(...) { cerr << "Fatal unknown error during test" << endl; while(!kbhit()) ; return 1; } cout << endl << "Score for tests: " << success*3 << "/30" << endl << endl; while(!kbhit()) ; return 0; }
|
בברכה,
עידן