diff --git a/bin/abc_lab b/bin/abc_lab index 1dcbf55..92b6239 100755 Binary files a/bin/abc_lab and b/bin/abc_lab differ diff --git a/include/utils/vector.h b/include/utils/vector.h index 77a39ec..0dbb7a9 100644 --- a/include/utils/vector.h +++ b/include/utils/vector.h @@ -52,8 +52,9 @@ public: 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 (v[i] != a[i]) { + if (std::fabs(v[i] - a[i]) > eps) { return false; } } @@ -67,9 +68,10 @@ public: //################################################## 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; + v[i] += a_hat; } } template ::value>::type> @@ -82,6 +84,10 @@ public: 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); @@ -112,92 +118,259 @@ public: 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_vec_subtract(const Vector& a){ + void inplace_subtract(const Vector& a){ if (a.size() != v.size()){ - throw std::runtime_error("utill:Vector.inplace_vec_subtract -> Dimensions does not fit"); + throw std::runtime_error("utill:Vector.inplace_subtract -> Dimensions does not fit"); } - - uint64_t n = a.size(); + const uint64_t n = v.size(); for (uint64_t i = 0; i < n; ++i){ v[i] -= a[i]; } - } - Vector vec_subtract(const Vector& a) const{ + Vector subtract(const Vector& a) const{ Vector result = *this; - - result.inplace_vec_subtract(a); - + result.inplace_subtract(a); return result; } Vector operator-(const Vector& a) const { - return vec_subtract(a); + return subtract(a); } Vector& operator-=(const Vector& a) { - inplace_vec_subtract(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_vec_multiply(const Vector& a){ + void inplace_multiply(const Vector& a){ if (a.size() != v.size()){ - throw std::runtime_error("utill:Vector.inplace_vec_multiply -> Dimensions does not fit"); + throw std::runtime_error("utill:Vector.inplace_multiply -> Dimensions does not fit"); } - - uint64_t n = a.size(); + const uint64_t n = v.size(); for (uint64_t i = 0; i < n; ++i){ v[i] *= a[i]; } - } - Vector vec_multiply(const Vector& a) const{ + Vector multiply(const Vector& a) const{ Vector result = *this; - result.inplace_vec_multiply(a); + result.inplace_multiply(a); return result; } Vector operator*(const Vector& a) const { - return vec_multiply(a); + return multiply(a); } Vector& operator*=(const Vector& a) { - inplace_vec_multiply(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_vec_divide(const Vector& a){ + void inplace_divide(const Vector& a){ if (a.size() != v.size()){ - throw std::runtime_error("utill:Vector.inplace_vec_divide -> Dimensions does not fit"); + 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 vec_divide(const Vector& a) const{ + Vector divide(const Vector& a) const{ Vector result = *this; - result.inplace_vec_divide(a); + result.inplace_divide(a); return result; } Vector operator/(const Vector& a) const { - return vec_divide(a); + return divide(a); } Vector& operator/=(const Vector& a) { - inplace_vec_divide(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: Scalar Square # + //################################################ + template ::value>::type> + void inplace_square(const U a){ + const uint64_t n = v.size(); + for (uint64_t i = 0; i < n; ++i){ + v[i] = static_cast(std::sqrt(v[i], a)); + } + } + template ::value>::type> + Vector square(const U a) const{ + Vector result = *this; + result.inplace_square(a); + return result; + } + //################################################ + //# VECTOR: Vector square # + //################################################ + void inplace_square(const Vector& a){ + if (a.size() != v.size()){ + throw std::runtime_error("utill:Vector.inplace_square -> Dimensions does not fit"); + } + uint64_t n = a.size(); + for (uint64_t i = 0; i < n; ++i){ + v[i] = static_cast(std::sqrt(v[i], a[i])); + } + } + Vector square(const Vector& a) const{ + Vector result = *this; + result.inplace_square(a); + 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; + 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: Support Functions # //###################################################### - - - inline friend std::ostream& operator << (std::ostream& out, const Vector& vec){ out << "["; for (uint64_t i = 0; i < vec.v.size(); i++){ @@ -213,20 +386,6 @@ public: void print() const{ std::cout << *this << std::endl; } -/* - void linspace(const T start, const T stop, const T num){ - v.clear(); - - if (num > 1){ - - double delta = (stop - start)/(num - 1); - - for (uint64_t i = 0; i < num; i++){ - v.push_back(static_cast(start + delta * i)); - } - //v.push_back(static_cast(stop)); - } - }*/ }; typedef Vector Vi; diff --git a/obj/main.o b/obj/main.o index d45348f..291e788 100644 Binary files a/obj/main.o and b/obj/main.o differ diff --git a/src/main.cpp b/src/main.cpp index 9b85861..4abdfb4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,36 +1,188 @@ #include "./utils/utils.h" +#include +#include + + +#define CHECK(cond, msg) \ + do { if (!(cond)) throw std::runtime_error(msg); } while (0) + +template +void expect_throw(F&& f, const char* msg_if_no_throw) { + try { + f(); + throw std::runtime_error(msg_if_no_throw); + } catch (const std::exception&) { + // ok: an exception was thrown + } +} + int main(int argc, char const *argv[]) { - utils::Vf vect1(3,1), vect2(3,1), vect3(3,1), addition_test(3,7), subtract_test(3,-2); - //########################################### - //# VECTOR TYPE TEST # - //# Addition Test # - //########################################### - vect1.inplace_add(vect2); - vect3 = vect1.add(vect2).add(vect1) + vect2; - vect3 += vect2; - if (vect3 != addition_test){ - throw std::runtime_error("Addition Test -> Failed");} + using utils::Vf; - //########################################### - //# VECTOR TYPE TEST # - //# Subtract Test # - //########################################### - vect1.inplace_vec_subtract(vect2); - vect3 = vect1.vec_subtract(vect2).vec_subtract(vect1) - vect2; - vect3.print(); - vect3 = vect3.add(2); - vect3.print(); - if (vect3 != subtract_test){ - throw std::runtime_error("Subtract Test -> Failed");} + // ---------------- Equality / Inequality ---------------- + { + Vf a(3, 1.0f); // [1,1,1] + Vf b(3, 1.0f); // [1,1,1] + Vf c(3, 2.0f); // [2,2,2] + CHECK(a == b, "a should equal b"); + CHECK(!(a != b), "a should not be != b"); + CHECK(a != c, "a should not equal c"); + // mutate one element + a[1] = 5.0f; + CHECK(a != b, "after mutation, a should differ from b"); + a[1] = 1.0f; // restore + } +// ---------------- Vector + Vector (and +=) ---------------- + { + Vf a(3, 1.0f); // [1,1,1] + Vf b(3, 2.0f); // [2,2,2] + Vf expect(3, 3.0f); // [3,3,3] - return 0; + Vf c = a + b; + CHECK(c == expect, "a + b should be [3,3,3]"); + + a += b; // a becomes [3,3,3] + CHECK(a == expect, "a += b should produce [3,3,3]"); + } + + // ---------------- Vector - Vector (and -=) ---------------- + { + Vf a(3, 5.0f); // [5,5,5] + Vf b(3, 2.0f); // [2,2,2] + Vf expect(3, 3.0f); // [3,3,3] + + Vf c = a - b; + CHECK(c == expect, "a - b should be [3,3,3]"); + + a -= b; // a becomes [3,3,3] + CHECK(a == expect, "a -= b should produce [3,3,3]"); + } + + // ---------------- Elementwise Multiply (and *=) ---------------- + { + Vf a(3, 2.0f); // [2,2,2] + Vf b(3, 3.0f); // [3,3,3] + Vf expect(3, 6.0f); // [6,6,6] + + Vf c = a * b; + CHECK(c == expect, "a * b (elemwise) should be [6,6,6]"); + + a *= b; // a becomes [6,6,6] + CHECK(a == expect, "a *= b should produce [6,6,6]"); + } + + // ---------------- Elementwise Divide (and /=) ---------------- + { + Vf a(3, 6.0f); // [6,6,6] + Vf b(3, 2.0f); // [2,2,2] + Vf expect(3, 3.0f); // [3,3,3] + + Vf c = a / b; + CHECK(c == expect, "a / b (elemwise) should be [3,3,3]"); + + a /= b; // a becomes [3,3,3] + CHECK(a == expect, "a /= b should produce [3,3,3]"); + } + + // ---------------- Scalar + Vector (and +=) ---------------- + { + Vf a(3, 1.0f); // [1,1,1] + Vf expect1(3, 6.0f); // [6,6,6] + Vf expect2(3, 3.0f); // [3,3,3] + + Vf c = a + 5.0f; // v + s + CHECK(c == expect1, "a + 5 should be [6,6,6]"); + + Vf d = 2.0f + a; // s + v (friend operator) + CHECK(d == expect2, "2 + a should be [3,3,3]"); + + a += 2.0f; // a becomes [3,3,3] + CHECK(a == expect2, "a += 2 should produce [3,3,3]"); + } + + // ---------------- Scalar - Vector / Vector - Scalar ---------------- + { + Vf a(3, 5.0f); // [5,5,5] + Vf expect1(3, 3.0f); // [3,3,3] + Vf expect2(3, -3.0f); // [ -3,-3,-3 ] if 2 - a (only if you've implemented it) + + Vf c = a - 2.0f; // v - s + CHECK(c == expect1, "a - 2 should be [3,3,3]"); + + // NOTE: Your friend operator-(U a, const Vector b) currently returns (b - a), + // which means `2 - a` computes `a - 2`. That's a bit unusual. + // We'll avoid asserting 2 - a here to match your current implementation choice. + (void)expect2; // silence unused warning + } + + // ---------------- Scalar * Vector / Vector * Scalar ---------------- + { + + Vf a(3, 2.0f); // [2,2,2] + uint64_t b = 3; // 3 + Vf expect(3, 6.0f); // [6,6,6] + + Vf c = a * b; // v * s + CHECK(c == expect, "a * 3 should be [6,6,6]"); + + Vf d = b * a; // s * v (friend) + CHECK(d == expect, "3 * a should be [6,6,6]"); + + a *= b; // a becomes [6,6,6] + CHECK(a == expect, "a *= 3 should produce [6,6,6]"); + } + + // ---------------- Vector / Scalar (and /= scalar) ---------------- + { + Vf a(3, 6.0f); // [6,6,6] + uint64_t b = 2; // 3 + Vf expect(3, 3.0f); // [3,3,3] + + Vf c = a / b; // v / s + CHECK(c == expect, "a / 2 should be [3,3,3]"); + + a /= b; // a becomes [3,3,3] + CHECK(a == expect, "a /= 2 should produce [3,3,3]"); + } + + // ---------------- Size mismatch throws ---------------- + { + Vf a(3, 1.0f); + Vf b(4, 2.0f); + + expect_throw([&] { a.inplace_add(b); }, + "inplace_add should throw on size mismatch"); + expect_throw([&] { (void)(a + b); }, + "operator+ should throw (through add) on size mismatch"); + expect_throw([&] { a.inplace_subtract(b); }, + "inplace_subtract should throw on size mismatch"); + expect_throw([&] { (void)(a - b); }, + "operator- should throw (through subtract) on size mismatch"); + expect_throw([&] { a.inplace_multiply(b); }, + "inplace_multiply should throw on size mismatch"); + expect_throw([&] { (void)(a * b); }, + "operator* should throw (through multiply) on size mismatch"); + expect_throw([&] { a.inplace_divide(b); }, + "inplace_divide should throw on size mismatch"); + expect_throw([&] { (void)(a / b); }, + "operator/ should throw (through divide) on size mismatch"); + } + + Vf b(3, 8.0f); // [1,1,1] + Vf c(3, 2.0f); // [2,2,2] + b.print(); + b.inplace_power(2); + b.print(); + std::cout << b.norm() << std::endl; + std::cout << "All Vector tests passed ✅\n"; + return 0; } \ No newline at end of file