#ifndef VECTOR_H #define VECTOR_H #include #include #include #include #include #include #include namespace Vector { //=========================================================================== // This header contains a definition for all the most common mathematical // operations on vectors implemented as overlading of standard operators. //=========================================================================== //=========================================================================== // Binary vector-vector operations //=========================================================================== // Element-wise vector addition (vector1+vector2) template std::vector operator+(std::vector vector1, const std::vector& vector2) { if(vector1.size() != vector2.size()) { throw std::invalid_argument("std::vector operator+"); } // This is actually implemented as vector1 += vector2, so the first // parameter is passed by copy and then overwritten with the result std::transform(vector1.begin(), vector1.end(), vector2.begin(), vector1.begin(), std::plus()); return vector1; } // Element-wise vector addition and assignment (vector1+=vector2) template std::vector& operator+=(std::vector& vector1, const std::vector& vector2) { if(vector1.size() != vector2.size()) { throw std::invalid_argument("std::vector operator+="); } // The first parameter is passed by reference, modified and returned std::transform(vector1.begin(), vector1.end(), vector2.begin(), vector1.begin(), std::plus()); return vector1; } // Element-wise vector subtraction (vector1-vector2) template std::vector operator-(std::vector vector1, const std::vector& vector2) { if(vector1.size() != vector2.size()) { throw std::invalid_argument("std::vector operator-"); } std::transform(vector1.begin(), vector1.end(), vector2.begin(), vector1.begin(), std::minus()); return vector1; } // Element-wise vector subtraction and assignment (vector1-=vector2) template std::vector& operator-=(std::vector& vector1, const std::vector& vector2) { if(vector1.size()!=vector2.size()) { throw std::invalid_argument("std::vector operator-="); } std::transform(vector1.begin(), vector1.end(), vector2.begin(), vector1.begin(), std::minus()); return vector1; } // Element-wise vector multiplication (vector1*vector2) template std::vector operator*(std::vector vector1, const std::vector& vector2) { if(vector1.size() != vector2.size()) { throw std::invalid_argument("std::vector operator*"); } std::transform(vector1.begin(), vector1.end(), vector2.begin(), vector1.begin(), std::multiplies()); return vector1; } // Element-wise vector multiplication and assignment (vector1*=vector2) template std::vector& operator*=(std::vector& vector1, const std::vector& vector2) { if(vector1.size() != vector2.size()) { throw std::invalid_argument("std::vector operator*="); } std::transform(vector1.begin(), vector1.end(), vector2.begin(), vector1.begin(), std::multiplies()); return vector1; } // Element-wise vector division (vector1/vector2) template std::vector operator/(std::vector vector1, const std::vector& vector2) { if(vector1.size() != vector2.size()) { throw std::invalid_argument("std::vector operator/"); } std::transform(vector1.begin(), vector1.end(), vector2.begin(), vector1.begin(), std::divides()); return vector1; } // Element-wise vector division and assignment (vector1/=vector2) template std::vector& operator/=(std::vector& vector1, const std::vector& vector2) { if(vector1.size() != vector2.size()) { throw std::invalid_argument("std::vector operator/="); } std::transform(vector1.begin(), vector1.end(), vector2.begin(), vector1.begin(), std::divides()); return vector1; } //=========================================================================== // Unary vector operations //=========================================================================== // Element-wise vector negation (-vector) template std::vector operator-(std::vector vector) { std::transform(vector.begin(), vector.end(), vector.begin(), std::negate()); return vector; } //=========================================================================== // Binary vector-scalar operations //=========================================================================== // Right scalar vector addition (vector+scalar) template std::vector operator+(std::vector vector, T scalar) { std::transform(vector.begin(), vector.end(), vector.begin(), [&scalar](T value) { return scalar + value; }); return vector; } // Left scalar vector addition (scalar+vector) template std::vector operator+(T scalar, std::vector vector) { return vector + scalar; } // Right scalar vector subtraction (vector-scalar) template std::vector operator-(std::vector vector, T scalar) { std::transform(vector.begin(), vector.end(), vector.begin(), [&scalar](T value) { return value - scalar; }); return vector; } // Left scalar vector subtraction (scalar-vector) template std::vector operator-(T scalar, std::vector vector) { std::transform(vector.begin(), vector.end(), vector.begin(), [&scalar](T value) { return scalar - value; }); return vector; } // Right scalar vector multiplication (vector*scalar) template std::vector operator*(std::vector vector, T scalar) { std::transform(vector.begin(), vector.end(), vector.begin(), [&scalar](T value) { return value * scalar; }); return vector; } // Left scalar vector multiplication (scalar*vector) template std::vector operator*(T scalar, std::vector vector) { return vector * scalar; } // Right scalar vector division (vector/scalar) template std::vector operator/(std::vector vector, T scalar) { std::transform(vector.begin(), vector.end(), vector.begin(), [&scalar](T value) { return value / scalar; }); return vector; } // Left scalar vector division (scalar/vector) template std::vector operator/(T scalar, std::vector vector) { std::transform(vector.begin(), vector.end(), vector.begin(), [&scalar](T value) { return scalar / value; }); return vector; } // Vector power to the given scalar (vector^scalar) template std::vector operator^(std::vector vector, T scalar) { std::transform(vector.begin(), vector.end(), vector.begin(), [&scalar](T value) { return std::pow(value, scalar); }); return vector; } //=========================================================================== // Utils //=========================================================================== // Element-wise round of vector template void Round(std::vector& vector) { std::transform(vector.begin(), vector.end(), vector.begin(), [](T value) { return std::round(value); }); } // Element-wise floor of vector template void Floor(std::vector& vector) { std::transform(vector.begin(), vector.end(), vector.begin(), [](T value) { return std::floor(value); }); } // Element-wise ceil of vector template void Ceil(std::vector& vector) { std::transform(vector.begin(), vector.end(), vector.begin(), [](T value) { return std::ceil(value); }); } // Element-wise clamp of vector template void Clamp(std::vector& vector, T min_value, T max_value) { std::transform(vector.begin(), vector.end(), vector.begin(), [&min_value, &max_value](T value) { return std::min(std::max(value, min_value), max_value); }); } // Get maximum value of vector template T Max(const std::vector& vector) { return *std::max_element(vector.begin(), vector.end()); } // Get minimum value of vector template T Min(const std::vector& vector) { return *std::min_element(vector.begin(), vector.end()); } // Sum of elements in vector template T Sum(const std::vector& vector) { T val = 0; val = std::accumulate(vector.begin(), vector.end(), val); return val; } // Product of elements in vector template T Prod(const std::vector& vector) { T val = 1; val = std::accumulate(vector.begin(), vector.end(), val, std::multiplies()); return val; } // Dot-product between vectors template T Dot(const std::vector& vector1, const std::vector& vector2) { return Sum(vector1 * vector2); } // Lp-norm of vector template T LpNorm(const std::vector& vector, T p) { return Sum(vector ^ p) ^ (static_cast(1) / p); } // L2-norm of vector template T Norm(const std::vector& vector) { return std::sqrt(Dot(vector, vector)); } // Normalise vector template std::vector Normalise(const std::vector& vector) { return vector / Norm(vector); } // Convolution types enum ConvolutionType { kFullConvolution = 0, kSameConvolution, kValidConvolution }; // Convolution of vector with given filter template std::vector Conv(const std::vector& vector, const std::vector& filter, ConvolutionType convolutionType = kFullConvolution) { const size_t vector_size = vector.size(); const size_t filter_size = filter.size(); if (filter_size > vector_size) { throw std::invalid_argument("Conv"); } // Compute convolution size_t minI = 0; size_t maxI = vector_size + filter_size - 1; if (convolutionType == kSameConvolution) { minI = filter_size / 2; maxI = minI + vector_size; } else if (convolutionType == kValidConvolution) { minI = filter_size - 1; maxI = vector_size; } std::vector output; output.reserve(maxI - minI); for (size_t i = minI; i < maxI; i++) { const size_t minJ = (i < filter_size - 1) ? 0 : i - filter_size + 1; const size_t maxJ = (i >= vector_size - 1) ? vector_size : i + 1; T value = static_cast(0); for (size_t j = minJ; j < maxJ; j++) { value += vector[j] * filter[i - j]; } output.push_back(value); } return output; } } // namespace Vector //============================================================================= // Output to std::ostream //============================================================================= // Overloaded operator<< for std::vector template inline std::ostream& operator<<(std::ostream& out, const std::vector& vector) { for(size_t i = 0, endI = vector.size(); i < endI; i++) { out << std::setw(8) << std::setprecision(4) << std::left << vector.at(i); } return out; } #endif // VECTOR_H