#ifndef MATRIX_H_
#define MATRIX_H_
// Author: clangpp@gmail.com
//
// Intention:
// 1. C++11 r-value reference is already released and well supported, it's time
// to write a matrix class to take advantage of that, to perform space-cheaper
// matrix arithmetics.
// 2. C++11 std::async() is a powerful tool to perform concurrent operations,
// it can be used to make full use of multi-core CPU's power, to perform
// time-faster matrix arithmetrics.
#include <algorithm>
#include <cstddef> // size_t, ptrdiff_t
#include <functional>
#include <future>
#include <initializer_list>
#include <iterator>
#include <numeric>
#include <ostream>
#include <sstream>
#include <stdexcept>
#include <utility> // move(), make_pair(), swap()
#include <vector>
#include <iostream> // debug
template <typename T> class Matrix;
namespace matrix {
template <typename T>
void CheckDimensionMatches(const Matrix<T>& lhs, const Matrix<T>& rhs) {
if (lhs.row_size() != rhs.row_size() ||
lhs.column_size() != rhs.column_size()) {
std::stringstream ss;
ss << "Matrices dimensions don't match: "
<< "(" << lhs.row_size() << ", " << lhs.column_size() << ") vs "
<< "(" << rhs.row_size() << ", " << rhs.column_size() << ")";
throw std::runtime_error(ss.str());
}
}
template <typename T>
void CheckDimensionMultipliable(const Matrix<T>& lhs, const Matrix<T>& rhs) {
if (lhs.column_size() != rhs.row_size()) {
std::stringstream ss;
ss << "Matrices dimensions not multipliable: "
<< "(" << lhs.row_size() << ", " << lhs.column_size() << ") vs "
<< "(" << rhs.row_size() << ", " << rhs.column_size() << ")";
throw std::runtime_error(ss.str());
}
}
template <typename T>
void CheckIndicesRange(const Matrix<T>& mat,
typename Matrix<T>::size_type row,
typename Matrix<T>::size_type column) {
if (row >= mat.row_size() || column >= mat.column_size()) {
std::stringstream ss;
ss << "Matrix indices (" << row << ", " << column << ") out of range "
<< "(" << mat.row_size() << ", " << mat.column_size() << ")";
throw std::out_of_range(ss.str());
}
}
template <typename T>
void CheckRowRange(const Matrix<T>& mat, typename Matrix<T>::size_type row) {
if (row >= mat.row_size()) {
std::stringstream ss;
ss << "Matrix row " << row << ") out of range "
<< "(" << mat.row_size() << ", " << mat.column_size() << ")";
throw std::out_of_range(ss.str());
}
}
template <typename T>
void CheckColumnRange(const Matrix<T>& mat,
typename Matrix<T>::size_type column) {
if (column >= mat.column_size()) {
std::stringstream ss;
ss << "Matrix column " << column << ") out of range "
<< "(" << mat.row_size() << ", " << mat.column_size() << ")";
throw std::out_of_range(ss.str());
}
}
template <typename T>
struct TrivialIsZero {
bool operator()(const T& value) {
return value == 0;
}
};
// T: StreamOutputable
template <typename T, typename IsZero = TrivialIsZero<T>>
void CheckValueNotZero(const T& value, IsZero is_zero = IsZero()) {
if (is_zero(value)) {
std::stringstream ss;
ss << "Non-zero value expected, actual " << value;
throw std::invalid_argument(ss.str());
}
}
void CheckIndicesNotEqual(size_t index1, size_t index2) {
if (index1 == index2) {
std::stringstream ss;
ss << "Indices should'nt be equal, actual " << index1 << " and " << index2;
throw std::runtime_error(ss.str());
}
}
template <typename T>
void CheckColumnSizesEqual(
std::initializer_list<std::initializer_list<T>> il) {
auto iter = std::adjacent_find(
il.begin(), il.end(),
[](std::initializer_list<T> lhs, std::initializer_list<T> rhs) {
return lhs.size() != rhs.size();
});
if (iter != il.end()) {
auto diff = iter + 1; // std::adjacent_find() tells us *iter != *(iter+1)
std::stringstream ss;
ss << "Each row should have the same column size: "
<< "row " << (diff - il.begin()) << "'s column size " << diff->size()
<< " vs previous rows' column size " << iter->size();
throw std::invalid_argument(ss.str());
}
}
template <typename T>
void CheckAugmentable(const Matrix<T>& coef, const Matrix<T>& extra) {
if (coef.row_size() != extra.row_size()) {
std::stringstream ss;
ss << "Equal row size expected, actual "
<< "(" << coef.row_size() << ", " << coef.column_size() << ") vs "
<< "(" << extra.row_size() << ", " << extra.column_size() << ")";
throw std::runtime_error(ss.str());
}
}
void ConcurrentProcess(std::size_t count,
std::function<void(std::size_t)> process,
std::vector<std::future<void>>* helper_futures) {
helper_futures->resize(count);
for (std::size_t index = 0; index < count; ++index) {
(*helper_futures)[index] = std::async(std::launch::async, process, index);
}
for (std::size_t index = 0; index < count; ++index) {
(*helper_futures)[index].wait();
}
}
inline void ConcurrentProcess(std::size_t count,
std::function<void(std::size_t)> process) {
std::vector<std::future<void>> futures(count);
ConcurrentProcess(count, process, &futures);
}
template <typename T>
void Print(const Matrix<T>& mat, std::ostream* os) {
typedef typename Matrix<T>::size_type size_type;
for (size_type row = 0; row < mat.row_size(); ++row) {
for (size_type column = 0; column < mat.column_size(); ++column) {
(*os) << mat[row][column] << " ";
}
(*os) << "\n";
}
}
template <typename T>
void PrintAugmented(const Matrix<T>& coef, const Matrix<T>& extra,
std::ostream* os) {
CheckAugmentable(coef, extra);
typedef typename Matrix<T>::size_type size_type;
for (size_type row = 0; row < coef.row_size(); ++row) {
for (size_type column = 0; column < coef.column_size(); ++column) {
(*os) << coef[row][column] << " ";
}
(*os) << "| ";
for (size_type column = 0; column < extra.column_size(); ++column) {
(*os) << extra[row][column] << " ";
}
(*os) << "\n";
}
}
} // namespace matrix
template <typename T>
class Matrix {
public:
typedef T value_type;
typedef T& reference;
typedef const T& const_reference;
typedef T* pointer;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
// ==== Iterators ====
typedef typename std::vector<value_type>::iterator row_iterator;
typedef typename std::vector<value_type>::const_iterator const_row_iterator;
template <typename Container, typename ValueType>
class basic_column_iterator:
public std::iterator<std::random_access_iterator_tag, ValueType> {
public:
typedef basic_column_iterator self;
typedef std::iterator<std::random_access_iterator_tag, ValueType> base;
typedef typename base::difference_type difference_type;
typedef typename base::pointer pointer;
typedef typename base::reference reference;
// ==== InputIterator requirements ====
bool operator==(const self& other) const {
return (data_ == other.data_ && row_ == other.row_ &&
column_ == other.column_);
}
bool operator!=(const self& other) const { return !(*this == other); }
reference operator*() const { return (*data_)[row_][column_]; }
pointer operator->() const { return &*(*this); }
// ==== ForwardIterator requirements ====
self& operator++() {
++row_;
return *this;
}
self operator++(int) {
self result(*this);
++*this;
return result;
}
// ==== BidirectionalIterator requirements ====
self& operator--() {
--row_;
return *this;
}
self operator--(int){
self result(*this);
--*this;
return result;
}
// ==== RandomAccessIterator requirements ====
self& operator+=(difference_type n) {
row_ += n;
return *this;
}
self operator+(difference_type n) const {
self re
评论0
最新资源