diff --git a/.gitignore b/.gitignore index f8305e747aa9833c9c18f69f80a2f0349b69398e..337b081acf511b0876dfef038158c1ba67f37b07 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -a.out \ No newline at end of file +a.out +build diff --git a/CMakeDemo/CMakeLists.txt b/CMakeDemo/CMakeLists.txt index 25013000a4ba983578849a79ca11bd140c5b99c2..36e83d33fd02ec274cfff5ab4a7be77580bd5544 100644 --- a/CMakeDemo/CMakeLists.txt +++ b/CMakeDemo/CMakeLists.txt @@ -16,4 +16,6 @@ endif() add_executable(hello_world HelloWorld.cpp) -add_executable(sanitizer Sanitizer.cpp) \ No newline at end of file +add_executable(sanitizer Sanitizer.cpp) + +add_executable(matmult MatMult.cpp Matrix.cpp) \ No newline at end of file diff --git a/CMakeDemo/MatMult.cpp b/CMakeDemo/MatMult.cpp new file mode 100644 index 0000000000000000000000000000000000000000..58e68d14451802f2c66f6f7a0b3838eb5ea3bd7a --- /dev/null +++ b/CMakeDemo/MatMult.cpp @@ -0,0 +1,41 @@ +#include "Matrix.h" +#include "Timer.h" + +#include <vector> +#include <string> +#include <iostream> +#include <fstream> + +int main( int argc, const char * argv[] ) +{ + std::vector<std::string> args( argv, argv + argc ); + + std::cout << "Called with arguments: "; + for( const auto & arg : args ) + { + std::cout << "\"" << arg << "\" "; + } + std::cout << "\n"; + + if( args.size() == 4 ) + { + std::cout << "Reading lhs matrix...\n"; + Matrix m0( readMatrixFromFile( args[1] ) ); + std::cout << "Reading rhs matrix...\n"; + Matrix m1( readMatrixFromFile( args[2] ) ); + + Timer timer; + std::cout << "Computing product...\n"; + timer.start(); + Matrix m2( m0 * m1 ); + timer.stop(); + std::cout << "Product took " << timer.elapsed() << "ms\n"; + + std::cout << "Writing result matrix...\n"; + writeMatrixToFile( m2, args[3] ); + } + else + { + std::cerr << "Usage: " << args[0] << " [IN_MATRIX_FILE IN_MATRIX_FILE OUT_MATRIX_FILE]\n"; + } +} diff --git a/CMakeDemo/Matrix.cpp b/CMakeDemo/Matrix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..064a46d68b9f0506db78e3551a592766617c07bf --- /dev/null +++ b/CMakeDemo/Matrix.cpp @@ -0,0 +1,103 @@ +#include "Matrix.h" + +#include <algorithm> +#include <sstream> +#include <string> +#include <istream> +#include <fstream> +#include <iterator> + +Matrix::Matrix( std::istream & is ) +{ + is >> m_ >> n_; + + values_.resize( m_ * n_ ); + + std::copy_n( std::istream_iterator<double>(is), m_ * n_, std::begin( values_ ) ); + + if(!is) + throw std::runtime_error("Error parsing Matrix!"); +} + +Matrix Matrix::operator+( const Matrix & other ) const +{ + Matrix result( *this ); // copy *this into the result + std::transform( result.values_.begin(), result.values_.end(), + other.values_.begin(), result.values_.begin(), + std::plus<double>() ); + return result; +} + +Matrix Matrix::operator-( const Matrix & other ) const +{ + Matrix result( *this ); // copy *this into the result + std::transform( result.values_.begin(), result.values_.end(), + other.values_.begin(), result.values_.begin(), + std::minus<double>() ); + return result; +} + +Matrix Matrix::operator*( const Matrix & other ) const +{ + if( n_ != other.m_ ) + throw std::invalid_argument("Matrix multiplication failed due to invalid layout!"); + + Matrix result( m_, other.n_ ); + + for( size_t i = 0; i < m_; ++i ) + for( size_t j = 0; j < other.n_; ++j ) + for( size_t k = 0; k < n_; ++k ) + result.get( i, j ) += get( i, k ) * other.get( k, j ); + + return result; +} + + +std::ostream & operator<<( std::ostream & os, const Matrix & m ) +{ + for( size_t i = 0; i < m.rows(); ++i ) + { + if( i != 0 ) + os << "\n"; + + for( size_t j = 0; j < m.cols(); ++j ) + { + if( j != 0 ) + os << " "; + + os << m.get( i, j ); + } + } + + return os; +} + +void Matrix::transpose() +{ + for( size_t i = 0; i < m_; ++i ) + for( size_t j = i + 1; j < n_; ++j ) + std::swap( get(i,j), get(j,i) ); +} + +Matrix readMatrixFromFile( const std::string & filename ) +{ + std::ifstream ifs( filename ); + if(!ifs) + throw std::runtime_error("Error opening file \"" + filename + "\"!" ); + + return Matrix( ifs ); +} + +void writeMatrixToFile( const Matrix & m, const std::string & filename ) +{ + std::ofstream ofs( filename ); + if(!ofs) + throw std::runtime_error("Error opening file \"" + filename + "\" for writing!" ); + + ofs << m.rows() << " " << m.cols() << "\n"; + std::copy( std::begin( m.getValues() ), std::end( m.getValues() ), std::ostream_iterator<double>(ofs, "\n") ); + + if(!ofs) + throw std::runtime_error("Error writing to file \"" + filename + "\"!" ); + +} \ No newline at end of file diff --git a/CMakeDemo/Matrix.h b/CMakeDemo/Matrix.h new file mode 100644 index 0000000000000000000000000000000000000000..4a69971e1630ae1980cd7e89441fcc3e5acfb93a --- /dev/null +++ b/CMakeDemo/Matrix.h @@ -0,0 +1,53 @@ +#pragma once + +#include <vector> +#include <istream> + +class Matrix +{ +public: + Matrix() = default; + Matrix( const size_t m, const size_t n, const double v ) + : m_(m), n_(n), values_( m * n, v ) { } + Matrix( const size_t m, const size_t n ) : Matrix( m, n, 0.0 ) { } + explicit Matrix( std::istream & is ); + + double get( const size_t row, const size_t col ) const { return values_[ row * n_ + col ]; } + double & get( const size_t row, const size_t col ) { return values_[ row * n_ + col ]; } + + size_t rows() const { return m_; } + size_t cols() const { return n_; } + + Matrix operator+( const Matrix & other ) const; + Matrix operator-( const Matrix & other ) const; + Matrix operator*( const Matrix & other ) const; + + inline bool operator==( const Matrix & other ) const; + inline bool operator!=( const Matrix & other ) const; + + void transpose(); + + const std::vector<double> & getValues() const { return values_; } + +private: + size_t m_ = 0; + size_t n_ = 0; + std::vector<double> values_; +}; + +Matrix readMatrixFromFile( const std::string & filename ); + +void writeMatrixToFile( const Matrix & m, const std::string & filename ); + +std::ostream & operator<<( std::ostream & os, const Matrix & m ); + + +bool Matrix::operator==( const Matrix & other ) const +{ + return m_ == other.m_ && n_ == other.n_ && values_ == other.values_; +} + +bool Matrix::operator!=( const Matrix & other ) const +{ + return !(*this == other); +} \ No newline at end of file diff --git a/CMakeDemo/Timer.h b/CMakeDemo/Timer.h new file mode 100644 index 0000000000000000000000000000000000000000..18a2daca60a6cbf9cef04100b08a6a2dd3ad2d13 --- /dev/null +++ b/CMakeDemo/Timer.h @@ -0,0 +1,31 @@ +#pragma once + +#include <chrono> + +class Timer +{ +public: + Timer() : begin_(), end_( begin_ ) { } + + void start() + { + begin_ = std::chrono::high_resolution_clock::now(); + end_ = begin_; + } + + void stop() + { + end_ = std::chrono::high_resolution_clock::now(); + } + + double elapsed() const + { + std::chrono::duration<double, std::milli> elapsed = end_ - begin_; + return elapsed.count(); + } + +private: + std::chrono::high_resolution_clock::time_point begin_; + std::chrono::high_resolution_clock::time_point end_; +}; +