Ready for fvm steady case

This commit is contained in:
2025-09-21 20:57:02 +02:00
parent 3a53b6ebf7
commit 513f071748
59 changed files with 1813 additions and 983 deletions
+156 -171
View File
@@ -4,208 +4,193 @@
using utils::Vf; using utils::Vd; using utils::Vi;
//
// ---------- Basic construction & access ----------
//
TEST_CASE(Vector_Construct_Size_Access) {
Vd a; // default
CHECK(a.size() == 0, "default size must be 0");
Vf b(3, 1.0f); // (n, fill)
CHECK(b.size() == 3, "size wrong");
CHECK(b[0] == 1.0f && b[1] == 1.0f && b[2] == 1.0f, "fill wrong");
b[1] = 2.5f;
CHECK(b[1] == 2.5f, "operator[] write failed");
// resize (grow + value)
b.resize(5, 7.0f);
CHECK(b.size() == 5, "resize grow size wrong");
CHECK(b[0] == 1.0f && b[1] == 2.5f && b[2] == 1.0f && b[3] == 7.0f && b[4] == 7.0f,
"resize grow values wrong");
// resize (shrink)
b.resize(2);
CHECK(b.size() == 2, "resize shrink size wrong");
// ---------- helpers ----------
template <typename T>
static bool vec_equal_exact(const utils::Vector<T>& a, const utils::Vector<T>& b) {
if (a.size() != b.size()) return false;
for (std::uint64_t i=0;i<a.size();++i) if (a[i]!=b[i]) return false;
return true;
}
TEST_CASE(Vector_Clear_PushBack) {
Vi v(0, 0);
v.push_back(10);
v.push_back(20);
CHECK(v.size() == 2, "push_back size wrong");
CHECK(v[0] == 10 && v[1] == 20, "push_back values wrong");
v.clear();
CHECK(v.size() == 0, "clear failed");
// ---------- tests ----------
TEST_CASE(Vector_Construct_Size_Fill) {
utils::Vd v0;
CHECK(v0.size()==0, "default size should be 0");
utils::Vd v1(5, 3.5);
CHECK(v1.size()==5, "size 5");
for (std::uint64_t i=0;i<5;++i) CHECK(v1[i]==3.5, "filled value 3.5");
}
//
// ---------- Equality / Inequality (tolerant for float/double) ----------
//
TEST_CASE(Vector_Equality_Tolerant) {
Vd a(3, 1.0), b(3, 1.0);
CHECK(a == b, "== identical failed");
CHECK(!(a != b), "!= identical failed");
// Tiny perturbation within eps (1e-6 default)
b[1] += 1e-7;
CHECK(a == b, "== tolerant failed");
TEST_CASE(Vector_PushBack_Resize) {
utils::Vi v;
v.push_back(1); v.push_back(2);
CHECK(v.size()==2, "push_back size");
CHECK(v[0]==1 && v[1]==2, "push_back contents");
// Larger perturbation should fail equality
b[1] += 1e-4;
CHECK(a != b, "!= with difference failed");
v.resize(5, 7);
CHECK(v.size()==5, "resize size");
CHECK(v[2]==7 && v[3]==7 && v[4]==7, "resize fill value");
}
//
// ---------- Scalar arithmetic: +, -, *, / (inplace and returning) ----------
//
TEST_CASE(Vector_Data_ReadWrite) {
utils::Vd v(4, 0.0);
double* p = v.data();
for (std::uint64_t i=0;i<4;++i) p[i] = double(i+1);
CHECK(v[0]==1.0 && v[3]==4.0, "write via data()");
const utils::Vd& cv = v;
const double* cp = cv.data();
double s=0.0; for (std::uint64_t i=0;i<cv.size();++i) s += cp[i];
CHECK(std::fabs(s-10.0) < 1e-12, "read via const data()");
}
TEST_CASE(Vector_Equality_and_NearlyEqual) {
utils::Vd a(3, 1.0), b(3, 1.0);
CHECK(a==b, "operator== equal");
b[1] += 5e-7;
CHECK(a==b, "operator== within eps (1e-6)");
b[1] += 2e-6;
CHECK(!(a==b), "operator== beyond eps");
utils::Vd c = a;
c[2] += 1e-10;
CHECK(c.nearly_equal_vec(a, 1e-9), "nearly_equal_vec within tol");
c[2] += 1e-6;
CHECK(!c.nearly_equal_vec(a, 1e-9), "nearly_equal_vec beyond tol");
}
TEST_CASE(Vector_Scalar_Arithmetic) {
Vf a(3, 1.0f);
utils::Vi v(3, 10); // [10,10,10]
// inplace
a.inplace_add(2); // int convertible to float
CHECK(a[0] == 3.0f && a[1] == 3.0f && a[2] == 3.0f, "inplace_add failed");
auto vadd = v + 2; // [12,12,12]
CHECK(vadd[0]==12 && vadd[2]==12, "scalar +");
a.inplace_subtract(1.5f);
CHECK(std::fabs(a[0] - 1.5f) < 1e-6f &&
std::fabs(a[1] - 1.5f) < 1e-6f &&
std::fabs(a[2] - 1.5f) < 1e-6f, "inplace_subtract failed");
v += 3; // [13,13,13]
CHECK(v[1]==13, "scalar +=");
a.inplace_multiply(4.0);
CHECK(a[0] == 6.0f && a[1] == 6.0f && a[2] == 6.0f, "inplace_multiply failed");
auto vsub = v - 5; // [8,8,8]
CHECK(vsub[2]==8, "scalar -");
a.inplace_divide(2);
CHECK(a[0] == 3.0f && a[1] == 3.0f && a[2] == 3.0f, "inplace_divide failed");
v -= 3; // [10,10,10]
CHECK(v[0]==10, "scalar -=");
// returning
auto b = a + 1.0f;
CHECK(b[0] == 4.0f && b[1] == 4.0f && b[2] == 4.0f, "operator+(scalar) failed");
auto vmul = v * 2; // [20,20,20]
CHECK(vmul[0]==20 && vmul[1]==20, "scalar *");
b = a - 2.0f;
CHECK(b[0] == 1.0f && b[1] == 1.0f && b[2] == 1.0f, "operator-(scalar) failed");
v *= 3; // [30,30,30]
CHECK(v[2]==30, "scalar *=");
b = a * 10; // int -> float
CHECK(b[0] == 30.0f && b[1] == 30.0f && b[2] == 30.0f, "operator*(scalar) failed");
auto vdiv = v / 3; // [10,10,10]
CHECK(vdiv[0]==10 && vdiv[1]==10, "scalar /");
b = a / 3.0f;
CHECK(std::fabs(b[0] - 1.0f) < 1e-6f &&
std::fabs(b[1] - 1.0f) < 1e-6f &&
std::fabs(b[2] - 1.0f) < 1e-6f, "operator/(scalar) failed");
// scalar on the left (friends implemented for + and *)
Vf c(3, 2.0f);
auto d = 5 + c; // friend operator+(U, Vector<T>)
CHECK(d[0] == 7.0f && d[1] == 7.0f && d[2] == 7.0f, "scalar + vector failed");
d = 3 * c; // friend operator*(U, Vector<T>)
CHECK(d[0] == 6.0f && d[1] == 6.0f && d[2] == 6.0f, "scalar * vector failed");
v /= 2; // [15,15,15]
CHECK(v[0]==15 && v[2]==15, "scalar /=");
}
//
// ---------- Vector arithmetic: +, -, *, / (elementwise) ----------
//
TEST_CASE(Vector_Vector_Arithmetic) {
Vd a(3, 1.0), b(3, 2.0);
utils::Vi a(4, 1), b(4, 2);
// returning
auto c = a + b;
CHECK(c[0]==3.0 && c[1]==3.0 && c[2]==3.0, "vec + vec failed");
auto c = a + b; // [3,3,3,3]
CHECK(c[0]==3 && c[3]==3, "v+v");
c = b - a;
CHECK(c[0]==1.0 && c[1]==1.0 && c[2]==1.0, "vec - vec failed");
a += b; // [3,3,3,3]
CHECK(a[1]==3, "v+=v");
c = a * b;
CHECK(c[0]==2.0 && c[1]==2.0 && c[2]==2.0, "vec * vec failed");
auto d = a - b; // [1,1,1,1]
CHECK(d[2]==1, "v-v");
c = b / b;
CHECK(c[0]==1.0 && c[1]==1.0 && c[2]==1.0, "vec / vec failed");
a -= b; // [1,1,1,1]
CHECK(a[0]==1, "v-=v");
// inplace
a = Vd(3, 1.0);
a += b;
CHECK(a[0]==3.0 && a[1]==3.0 && a[2]==3.0, "inplace vec + vec failed");
a -= b;
CHECK(a[0]==1.0 && a[1]==1.0 && a[2]==1.0, "inplace vec - vec failed");
a *= b;
CHECK(a[0]==2.0 && a[1]==2.0 && a[2]==2.0, "inplace vec * vec failed");
a /= b;
CHECK(a[0]==1.0 && a[1]==1.0 && a[2]==1.0, "inplace vec / vec failed");
}
//
// ---------- Size mismatch error paths ----------
//
TEST_CASE(Vector_SizeMismatch_Throws) {
Vd a(3, 1.0), b(4, 2.0);
auto e = a * b; // [2,2,2,2]
CHECK(e[1]==2, "v*v (elemwise)");
bool threw = false;
try { auto c = a + b; (void)c; } catch (const std::runtime_error&) { threw = true; }
CHECK(threw, "add should throw on size mismatch");
a *= b; // [2,2,2,2]
CHECK(a[3]==2, "v*=v");
threw = false;
try { a.inplace_subtract(b); } catch (const std::runtime_error&) { threw = true; }
CHECK(threw, "inplace_subtract should throw on size mismatch");
auto f = e / b; // [1,1,1,1]
CHECK(f[0]==1 && f[3]==1, "v/v (elemwise)");
threw = false;
try { auto d = a * b; (void)d; } catch (const std::runtime_error&) { threw = true; }
CHECK(threw, "multiply should throw on size mismatch");
threw = false;
try { auto s = a.dot(b); (void)s; } catch (const std::runtime_error&) { threw = true; }
CHECK(threw, "dot should throw on size mismatch");
e /= b; // [1,1,1,1]
CHECK(e[2]==1, "v/=v");
}
//
// ---------- Power / sqrt ----------
//
TEST_CASE(Vector_Power_Sqrt) {
Vd a(3, 2.0); // [2,2,2]
auto b = a.power(3.0); // [8,8,8]
CHECK(b[0]==8.0 && b[1]==8.0 && b[2]==8.0, "scalar power failed");
TEST_CASE(Vector_Friend_Scalar_Left) {
utils::Vd v(3, 2.0); // [2,2,2]
auto s1 = 3.0 + v; // [5,5,5]
CHECK(s1[0]==5.0 && s1[2]==5.0, "left scalar +");
Vd p(3, 3.0); // [3,3,3]
auto c = b.power(p); // 8^3 = 512
CHECK(c[0]==512.0 && c[1]==512.0 && c[2]==512.0, "vector power failed");
Vd d(3, 9.0);
auto e = d.sqrt(); // [3,3,3]
CHECK(e[0]==3.0 && e[1]==3.0 && e[2]==3.0, "sqrt failed");
// inplace
d.inplace_sqrt(); // becomes [3,3,3]
CHECK(d == e, "inplace_sqrt failed");
auto s2 = 4.0 * v; // [8,8,8]
CHECK(s2[1]==8.0, "left scalar *");
}
//
// ---------- Dot / Sum / Norm / Normalize ----------
//
TEST_CASE(Vector_Dot_Sum_Norm_Normalize) {
Vd a(3, 0.0);
a[0]=1.0; a[1]=2.0; a[2]=2.0;
TEST_CASE(Vector_Power_and_Sqrt) {
utils::Vd v(3, 4.0); // [4,4,4]
auto p = v.power(2.0); // [16,16,16]
CHECK(p[0]==16.0 && p[2]==16.0, "power scalar");
CHECK(a.sum() == 5.0, "sum failed");
CHECK(a.dot(a) == 9.0, "dot self failed");
auto n = a.norm();
CHECK(std::fabs(n - 3.0) < 1e-12, "norm failed");
auto b = a.normalize();
CHECK(std::fabs(b.norm() - 1.0) < 1e-12, "normalize() not unit");
// inplace normalize
a.inplace_normalize();
CHECK(std::fabs(a.norm() - 1.0) < 1e-12, "inplace_normalize not unit");
// zero-norm error
Vd z(3, 0.0);
bool threw = false;
try { z.inplace_normalize(); } catch (const std::runtime_error&) { threw = true; }
CHECK(threw, "normalize zero vector must throw");
v.inplace_sqrt(); // sqrt([4,4,4]) -> [2,2,2]
CHECK(v[0]==2.0 && v[1]==2.0, "inplace_sqrt");
}
//
// ---------- Stream output (basic sanity) ----------
//
TEST_CASE(Vector_StreamOutput) {
Vi a(3, 2);
std::ostringstream oss;
oss << a;
auto s = oss.str();
CHECK(s == "[2, 2, 2]", "ostream<< wrong format");
TEST_CASE(Vector_Dot_Sum_Norm) {
utils::Vd a(3, 0.0), b(3, 0.0);
a[0]=1.0; a[1]=2.0; a[2]=3.0; // a = [1,2,3]
b[0]=4.0; b[1]=5.0; b[2]=6.0; // b = [4,5,6]
double dot = a.dot(b); // 1*4 + 2*5 + 3*6 = 32
CHECK(std::fabs(dot - 32.0) < 1e-12, "dot");
double s = a.sum(); // 6
CHECK(std::fabs(s - 6.0) < 1e-12, "sum");
double n = a.norm(); // sqrt(14)
CHECK(std::fabs(n - std::sqrt(14.0)) < 1e-12, "norm");
}
TEST_CASE(Vector_Normalize_and_Throws) {
utils::Vd v(3, 0.0);
v[0]=3.0; v[1]=4.0; v[2]=0.0; // norm = 5
auto u = v.normalize(); // returns new vector
CHECK(std::fabs(u.norm() - 1.0) < 1e-12, "normalize() unit length");
v.inplace_normalize();
CHECK(std::fabs(v.norm() - 1.0) < 1e-12, "inplace_normalize unit length");
utils::Vd z(3, 0.0);
bool threw=false;
try { z.inplace_normalize(); } catch(const std::runtime_error&) { threw=true; }
CHECK(threw, "normalize should throw on zero vector");
}
// Size mismatch throws (elementwise ops)
TEST_CASE(Vector_Size_Mismatch_Throws) {
utils::Vi a(3,1), b(4,2);
bool threw=false;
try { (void)a.dot(b); } catch(const std::runtime_error&) { threw=true; }
CHECK(threw, "dot size mismatch should throw");
threw=false;
try { a.inplace_add(b); } catch(const std::runtime_error&) { threw=true; }
CHECK(threw, "add size mismatch should throw");
threw=false;
try { a.inplace_subtract(b); } catch(const std::runtime_error&) { threw=true; }
CHECK(threw, "subtract size mismatch should throw");
threw=false;
try { a.inplace_multiply(b); } catch(const std::runtime_error&) { threw=true; }
CHECK(threw, "multiply size mismatch should throw");
threw=false;
try { a.inplace_divide(b); } catch(const std::runtime_error&) { threw=true; }
CHECK(threw, "divide size mismatch should throw");
threw=false;
try { a.inplace_power(b); } catch(const std::runtime_error&) { threw=true; }
CHECK(threw, "power size mismatch should throw");
}