#ifndef _vector_n_ #define _vector_n_ #include "iostream" #include #include #include #include #include #include #include namespace utils{ //###################################### //# VECTOR TYPE # //# Backed by std::vector # //###################################### template class Vector{ public: using value_type = T; std::vector v; // Default construtor utils::Vd vector; Vector() = default; // Construtor utils::Vd vector(2, 3.15); // Prevent implicit conversions like Vector v = 5; explicit Vector(uint64_t size, T value = T()) { v.resize(size, value); } // Construct from a braced list: utils::Vf v{1,2,3}; Vector(std::initializer_list init) : v(init) {} //########################################################## //# VECTOR: --- basic properties --- # //########################################################## // vector.clear(); void clear() noexcept {v.clear();} // vector.push_back(2); void push_back(const T& val) { v.push_back(val); } // vector[2] = 2; T& operator[](uint64_t idx) { return v[idx]; } // a = vector[2]; const T& operator[](uint64_t idx) const { return v[idx]; } // Assign from a braced list after default construction: Vector& operator=(std::initializer_list init) { v = init; return *this; } // vector.size(); uint64_t size() const noexcept { return v.size(); } void resize(uint64_t new_size, const T& value = T()) { v.resize(new_size, value); } T* data() noexcept { return v.data(); } const T* data() const noexcept { return v.data(); } //########################################### //# VECTOR: == and != # //########################################### bool operator==(const Vector& a) const { if (v.size() != a.size()) { return false; } const static T eps = static_cast(1e-6); // tweak if you like for (uint64_t i = 0; i < v.size(); ++i) { if (std::fabs(v[i] - a[i]) > eps) { return false; } } return true; } bool operator!=(const Vector& a) const { return !(*this == a); } //################################################## //# VECTOR: nearly_equal_vec # //################################################## bool nearly_equal_vec(const Vector& a, double tol=1e-12) const { if (a.size() != v.size()) return false; for (uint64_t i=0;itol) { return false; } } return true; } //################################################## //# VECTOR: Scalar Addition # //################################################## template ::value>::type> void inplace_add(const U a){ const T a_hat = static_cast(a); const uint64_t n = v.size(); for (uint64_t i = 0; i < n; ++i){ v[i] += a_hat; } } template ::value>::type> Vector add(const U a) const{ Vector result = *this; result.inplace_add(a); return result; } template ::value>::type> Vector operator+(const U a) const { return add(a); } template ::value>::type> friend Vector operator+(U a, const Vector& b) { return b + a; } template ::value>::type> Vector& operator+=(const U a) { inplace_add(a); return *this; } //################################################## //# VECTOR: Vector Addition # //################################################## void inplace_add(const Vector& a){ if (a.size() != v.size()){ throw std::runtime_error("utill:Vector.inplace_add -> Dimensions does not fit"); } const uint64_t n = v.size(); for (uint64_t i = 0; i < n; ++i){ v[i] += a[i]; } } Vector add(const Vector& a) const{ Vector result = *this; result.inplace_add(a); return result; } Vector operator+(const Vector& a) const { return add(a); } Vector& operator+=(const Vector& a) { inplace_add(a); return *this; } //################################################## //# VECTOR: Scalar Subtract # //################################################## template ::value>::type> void inplace_subtract(const U a){ const T a_hat = static_cast(a); const uint64_t n = v.size(); for (uint64_t i = 0; i < n; ++i){ v[i] -= a_hat; } } template ::value>::type> Vector subtract(const U a) const{ Vector result = *this; result.inplace_subtract(a); return result; } template ::value>::type> Vector operator-(const U a) const { return subtract(a); } template ::value>::type> Vector& operator-=(const U a) { inplace_subtract(a); return *this; } //################################################## //# VECTOR: Vector Subtract # //################################################## void inplace_subtract(const Vector& a){ if (a.size() != v.size()){ throw std::runtime_error("utill:Vector.inplace_subtract -> Dimensions does not fit"); } const uint64_t n = v.size(); for (uint64_t i = 0; i < n; ++i){ v[i] -= a[i]; } } Vector subtract(const Vector& a) const{ Vector result = *this; result.inplace_subtract(a); return result; } Vector operator-(const Vector& a) const { return subtract(a); } Vector& operator-=(const Vector& a) { inplace_subtract(a); return *this; } //################################################## //# VECTOR: Scalar Multiply # //################################################## template ::value>::type> void inplace_multiply(const U a){ const T a_hat = static_cast(a); const uint64_t n = v.size(); for (uint64_t i = 0; i < n; ++i){ v[i] *= a_hat; } } template ::value>::type> Vector multiply(const U a) const{ Vector result = *this; result.inplace_multiply(a); return result; } template ::value>::type> Vector operator*(const U a) const { return multiply(a); } template ::value>::type> friend Vector operator*(U a, const Vector& b) { return b * a; } template ::value>::type> Vector& operator*=(const U a) { inplace_multiply(a); return *this; } //################################################## //# VECTOR: Vector Multiply # //################################################## void inplace_multiply(const Vector& a){ if (a.size() != v.size()){ throw std::runtime_error("utill:Vector.inplace_multiply -> Dimensions does not fit"); } const uint64_t n = v.size(); for (uint64_t i = 0; i < n; ++i){ v[i] *= a[i]; } } Vector multiply(const Vector& a) const{ Vector result = *this; result.inplace_multiply(a); return result; } Vector operator*(const Vector& a) const { return multiply(a); } Vector& operator*=(const Vector& a) { inplace_multiply(a); return *this; } //################################################ //# VECTOR: Scalar Divide # //################################################ template ::value>::type> void inplace_divide(const U a){ const T a_hat = static_cast(a); const uint64_t n = v.size(); for (uint64_t i = 0; i < n; ++i){ v[i] /= a_hat; } } template ::value>::type> Vector divide(const U a) const{ Vector result = *this; result.inplace_divide(a); return result; } template ::value>::type> Vector operator/(const U a) const { return divide(a); } template ::value>::type> Vector& operator/=(const U a) { inplace_divide(a); return *this; } //################################################## //# VECTOR: Vector Divide # //################################################## void inplace_divide(const Vector& a){ if (a.size() != v.size()){ throw std::runtime_error("utill:Vector.inplace_divide -> Dimensions does not fit"); } uint64_t n = a.size(); for (uint64_t i = 0; i < n; ++i){ v[i] /= a[i]; } } Vector divide(const Vector& a) const{ Vector result = *this; result.inplace_divide(a); return result; } Vector operator/(const Vector& a) const { return divide(a); } Vector& operator/=(const Vector& a) { inplace_divide(a); return *this; } //############################################### //# VECTOR: Scalar Power # //############################################### template ::value>::type> void inplace_power(const U a){ const uint64_t n = v.size(); for (uint64_t i = 0; i < n; ++i){ v[i] = static_cast(std::pow(v[i], a)); } } template ::value>::type> Vector power(const U a) const{ Vector result = *this; result.inplace_power(a); return result; } //############################################### //# VECTOR: Vector Power # //############################################### void inplace_power(const Vector& a){ if (a.size() != v.size()){ throw std::runtime_error("utill:Vector.inplace_power -> Dimensions does not fit"); } uint64_t n = a.size(); for (uint64_t i = 0; i < n; ++i){ v[i] = static_cast(std::pow(v[i], a[i])); } } Vector power(const Vector& a) const{ Vector result = *this; result.inplace_power(a); return result; } //################################################ //# VECTOR: Vector square # //################################################ void inplace_sqrt(){ uint64_t n = v.size(); for (uint64_t i = 0; i < n; ++i){ v[i] = static_cast(std::sqrt(v[i])); } } Vector sqrt() const{ Vector result = *this; result.inplace_sqrt(); return result; } //################################################### //# VECTOR: Dot Product # //################################################### T dot(const Vector& a)const { if (a.size() != v.size()){ throw std::runtime_error("utill:Vector.dot -> Dimensions does not fit"); } T result = T{0}; const uint64_t n = v.size(); for (uint64_t i = 0; i < n; ++i){ result += a[i]*v[i]; } return result; } //############################################ //# VECTOR: Sum # //############################################ T sum()const{ T result = T{0}; const uint64_t n = v.size(); for (uint64_t i = 0; i < n; ++i){ result += v[i]; } return result; } //############################################ //# VECTOR: Norm # //############################################ T norm() const{ return static_cast(std::sqrt(this->dot(*this))); } //############################################ //# VECTOR: Normalize # //############################################ void inplace_normalize() { T norm = this->norm(); if (norm == T{0}){ throw std::runtime_error("utils::Vector.normalize -> zero norm"); } this->inplace_divide(norm); } Vector normalize() const{ Vector result = *this; result.inplace_normalize(); return result; } //###################################################### //# VECTOR: Support Functions # //###################################################### inline friend std::ostream& operator << (std::ostream& out, const Vector& vec){ out << "["; for (uint64_t i = 0; i < vec.v.size(); i++){ out << vec.v[i]; if (i != vec.v.size() - 1) { out << ", "; } } out << "]"; return out; } void print() const{ std::cout << *this << std::endl; } bool nearly_equal(const Vector& a, T tol = static_cast(1e-9)) const { if (v.size() != a.size()){ return false; } for (uint64_t i = 0; i < v.size(); ++i){ T val1 = v[i]; T val2 = a[i]; if (std::is_floating_point::value) { if (std::fabs(val1 - val2) > tol) return false; } else { if (val1 != val2) return false; } } return true; } }; typedef Vector Vi; typedef Vector Vf; typedef Vector Vd; /* if (std::is_floating_point::value) { if (std::fabs(a - b) > tol) return false; } else { if (a != b) return false; }*/ } // namespace utils #endif // _vector_n_