Ready for fvm steady case
This commit is contained in:
+139
-117
@@ -1,142 +1,164 @@
|
||||
|
||||
#include "test_common.h"
|
||||
#include "./utils/utils.h"
|
||||
#include "./utils/matrix.h"
|
||||
|
||||
using utils::Vf; using utils::Vd; using utils::Vi;
|
||||
using utils::Mf; using utils::Md; using utils::Mi;
|
||||
|
||||
|
||||
// ---------- Construction & element access ----------
|
||||
TEST_CASE(Matrix_Construct_Access) {
|
||||
Md M; // default
|
||||
CHECK(M.rows()==0 && M.cols()==0, "default ctor dims wrong");
|
||||
|
||||
Mf A(2,3, 1.0f);
|
||||
CHECK(A.rows()==2 && A.cols()==3, "ctor dims wrong");
|
||||
CHECK(A(0,0)==1.0f && A(1,2)==1.0f, "fill wrong");
|
||||
|
||||
A(0,1)=2.5f; A(1,0)=3.5f;
|
||||
CHECK(A(0,1)==2.5f && A(1,0)==3.5f, "operator() set/get failed");
|
||||
// tiny helper
|
||||
template <typename T>
|
||||
static bool mat_is_filled(const utils::Matrix<T>& M, T v) {
|
||||
for (std::uint64_t i = 0; i < M.rows(); ++i)
|
||||
for (std::uint64_t j = 0; j < M.cols(); ++j)
|
||||
if (M(i,j) != v) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------- Equality, inequality, nearly_equal ----------
|
||||
TEST_CASE(Matrix_Equality) {
|
||||
Mi A(2,2,0), B(2,2,0), C(2,2,1);
|
||||
A(0,0)=1; A(1,1)=1; // A = I
|
||||
B(0,0)=1; B(1,1)=1; // B = I
|
||||
|
||||
CHECK(A == B, "== failed identical");
|
||||
CHECK(!(A != B), "!= failed identical");
|
||||
CHECK(A != C, "!= failed different");
|
||||
|
||||
Md F1(2,2,0.0), F2(2,2,0.0);
|
||||
F1(0,0)=1.0; F1(1,1)=2.0;
|
||||
F2(0,0)=1.0; F2(1,1)=2.0 + 5e-10; // tiny perturbation
|
||||
CHECK(!(F1 == F2), "operator== is exact; should differ");
|
||||
CHECK(F1.nearly_equal(F2, 1e-9), "nearly_equal should accept tiny delta");
|
||||
CHECK(!F1.nearly_equal(F2, 1e-12), "nearly_equal too strict should fail");
|
||||
// ------------------- basic construction -------------------
|
||||
TEST_CASE(Matrix_Default_Construct) {
|
||||
Md M;
|
||||
CHECK_EQ(M.rows(), 0, "default rows should be 0");
|
||||
CHECK_EQ(M.cols(), 0, "default cols should be 0");
|
||||
}
|
||||
|
||||
// ---------- Row helpers ----------
|
||||
TEST_CASE(Matrix_Row_Get_Set) {
|
||||
Mf M(3,4, 0.0f);
|
||||
Vf r(4, 0.0f);
|
||||
for (uint64_t j=0;j<4;++j) r[j] = float(j+1); // [1,2,3,4]
|
||||
|
||||
M.set_row(1, r);
|
||||
auto out = M.get_row(1);
|
||||
CHECK(out == r, "set_row/get_row mismatch");
|
||||
|
||||
// size mismatch should throw
|
||||
bool threw=false;
|
||||
try { Vf bad(3, 9.0f); M.set_row(2, bad); } catch (const std::exception&) { threw=true; }
|
||||
CHECK(threw, "set_row should throw on size mismatch");
|
||||
|
||||
// out of range
|
||||
threw=false;
|
||||
try { (void)M.get_row(3); } catch (const std::out_of_range&) { threw=true; }
|
||||
CHECK(threw, "get_row should throw on OOB index");
|
||||
TEST_CASE(Matrix_Filled_Construct) {
|
||||
Md M(3, 4, 2.5);
|
||||
CHECK_EQ(M.rows(), 3, "rows");
|
||||
CHECK_EQ(M.cols(), 4, "cols");
|
||||
CHECK(mat_is_filled(M, 2.5), "all elements should be 2.5");
|
||||
}
|
||||
|
||||
// ---------- Column helpers ----------
|
||||
TEST_CASE(Matrix_Col_Get_Set) {
|
||||
Md M(3,2, 0.0);
|
||||
Vd c(3, 0.0);
|
||||
c[0]=10; c[1]=20; c[2]=30;
|
||||
|
||||
M.set_col(1, c);
|
||||
auto out = M.get_col(1);
|
||||
CHECK(out == c, "set_col/get_col mismatch");
|
||||
|
||||
// size mismatch should throw
|
||||
bool threw=false;
|
||||
try { Vd bad(2, 9.0); M.set_col(0, bad); } catch (const std::exception&) { threw=true; }
|
||||
CHECK(threw, "set_col should throw on size mismatch");
|
||||
|
||||
// out of range
|
||||
threw=false;
|
||||
try { (void)M.get_col(2); } catch (const std::out_of_range&) { threw=true; }
|
||||
CHECK(threw, "get_col should throw on OOB index");
|
||||
// ------------------- element access / write -------------------
|
||||
TEST_CASE(Matrix_Set_Get) {
|
||||
Mi M(2, 3, 0);
|
||||
M(0,0) = 42;
|
||||
M(1,2) = -7;
|
||||
CHECK_EQ(M(0,0), 42, "set/get (0,0)");
|
||||
CHECK_EQ(M(1,2), -7, "set/get (1,2)");
|
||||
}
|
||||
|
||||
// ---------- swap_rows / swap_cols ----------
|
||||
TEST_CASE(Matrix_Swap_Rows_Cols) {
|
||||
// ------------------- resize semantics -------------------
|
||||
TEST_CASE(Matrix_Resize_Grow) {
|
||||
Mf M(2, 2, 1.0f);
|
||||
M.resize(3, 4, 9.0f); // grow; newly appended elements get the fill value
|
||||
CHECK_EQ(M.rows(), 3, "rows after resize");
|
||||
CHECK_EQ(M.cols(), 4, "cols after resize");
|
||||
CHECK(M(2,3) == 9.0f, "last element should be the fill value after grow");
|
||||
}
|
||||
|
||||
TEST_CASE(Matrix_Resize_Shrink) {
|
||||
Mi M(4, 4, 5);
|
||||
M(0,0) = 11;
|
||||
M.resize(2, 2, 999); // shrink; size reduces
|
||||
CHECK_EQ(M.rows(), 2, "rows after shrink");
|
||||
CHECK_EQ(M.cols(), 2, "cols after shrink");
|
||||
// element mapping after shrink is implementation dependent; just check bounds usable
|
||||
M(1,1) = 3;
|
||||
CHECK_EQ(M(1,1), 3, "write after shrink works");
|
||||
}
|
||||
|
||||
// ------------------- row helpers -------------------
|
||||
TEST_CASE(Matrix_Get_Row) {
|
||||
Mi M(3,4,0);
|
||||
// set row 1 to [10,20,30,40]
|
||||
for (std::uint64_t j=0;j<4;++j) M(1,j) = (j+1)*10;
|
||||
auto r = M.get_row(1);
|
||||
CHECK_EQ(r.size(), 4, "row size");
|
||||
CHECK(r[0]==10 && r[1]==20 && r[2]==30 && r[3]==40, "row contents");
|
||||
}
|
||||
|
||||
TEST_CASE(Matrix_Set_Row) {
|
||||
Mi M(2,3,0);
|
||||
// Row 0: [1,2,3], Row 1: [4,5,6]
|
||||
M(0,0)=1; M(0,1)=2; M(0,2)=3;
|
||||
M(1,0)=4; M(1,1)=5; M(1,2)=6;
|
||||
utils::Vector<int64_t> v(3, 0);
|
||||
v[0]=7; v[1]=8; v[2]=9;
|
||||
M.set_row(0, v);
|
||||
CHECK(M(0,0)==7 && M(0,1)==8 && M(0,2)==9, "set_row contents");
|
||||
}
|
||||
|
||||
M.swap_rows(0,1);
|
||||
CHECK(M(0,0)==4 && M(0,1)==5 && M(0,2)==6, "swap_rows row0 wrong");
|
||||
CHECK(M(1,0)==1 && M(1,1)==2 && M(1,2)==3, "swap_rows row1 wrong");
|
||||
|
||||
// swap back via cols
|
||||
M.swap_cols(0,2);
|
||||
// After swapping col0<->col2:
|
||||
// Row0: [6,5,4], Row1: [3,2,1]
|
||||
CHECK(M(0,0)==6 && M(0,1)==5 && M(0,2)==4, "swap_cols row0 wrong");
|
||||
CHECK(M(1,0)==3 && M(1,1)==2 && M(1,2)==1, "swap_cols row1 wrong");
|
||||
|
||||
// no-op swap (a==b) should not crash or change
|
||||
M.swap_rows(1,1);
|
||||
M.swap_cols(2,2);
|
||||
|
||||
// OOB checks
|
||||
TEST_CASE(Matrix_Row_OutOfRange_Throws) {
|
||||
Mi M(2,2,0);
|
||||
bool threw=false;
|
||||
try { M.swap_rows(5,1); } catch (const std::out_of_range&) { threw=true; }
|
||||
CHECK(threw, "swap_rows should throw on OOB");
|
||||
try { (void)M.get_row(2); } catch(const std::out_of_range&) { threw=true; }
|
||||
CHECK(threw, "get_row out-of-range should throw");
|
||||
|
||||
threw=false;
|
||||
try { M.swap_cols(0,9); } catch (const std::out_of_range&) { threw=true; }
|
||||
CHECK(threw, "swap_cols should throw on OOB");
|
||||
try {
|
||||
utils::Vector<int64_t> v(3,1); // wrong size
|
||||
M.set_row(1, v);
|
||||
} catch(const std::runtime_error&) { threw=true; }
|
||||
CHECK(threw, "set_row size mismatch should throw");
|
||||
}
|
||||
|
||||
// ---------- data() layout (contiguous row-major) ----------
|
||||
TEST_CASE(Matrix_Data_Layout) {
|
||||
Md M(2,3, 0.0);
|
||||
// Fill increasing sequence
|
||||
double val=1.0;
|
||||
for (uint64_t i=0;i<M.rows();++i)
|
||||
for (uint64_t j=0;j<M.cols();++j)
|
||||
M(i,j) = val++;
|
||||
|
||||
const double* p = M.data();
|
||||
// Expect row-major: [1,2,3,4,5,6]
|
||||
CHECK(p[0]==1.0 && p[1]==2.0 && p[2]==3.0 && p[3]==4.0 && p[4]==5.0 && p[5]==6.0,
|
||||
"data() row-major layout wrong");
|
||||
// ------------------- col helpers -------------------
|
||||
TEST_CASE(Matrix_Get_Col) {
|
||||
Mi M(3,2,0);
|
||||
M(0,1)=5; M(1,1)=6; M(2,1)=7;
|
||||
auto c = M.get_col(1);
|
||||
CHECK_EQ(c.size(), 3, "col size");
|
||||
CHECK(c[0]==5 && c[1]==6 && c[2]==7, "col contents");
|
||||
}
|
||||
|
||||
// ---------- Stream output ----------
|
||||
TEST_CASE(Matrix_StreamOutput) {
|
||||
TEST_CASE(Matrix_Set_Col) {
|
||||
Mi M(3,2,0);
|
||||
utils::Vector<int64_t> v(3, 0);
|
||||
v[0]=1; v[1]=4; v[2]=9;
|
||||
M.set_col(0, v);
|
||||
CHECK(M(0,0)==1 && M(1,0)==4 && M(2,0)==9, "set_col contents");
|
||||
}
|
||||
|
||||
TEST_CASE(Matrix_Col_OutOfRange_Throws) {
|
||||
Mi M(2,2,0);
|
||||
bool threw=false;
|
||||
try { (void)M.get_col(2); } catch(const std::out_of_range&) { threw=true; }
|
||||
CHECK(threw, "get_col out-of-range should throw");
|
||||
|
||||
threw=false;
|
||||
try {
|
||||
utils::Vector<int64_t> v(1,1); // wrong size
|
||||
M.set_col(1, v);
|
||||
} catch(const std::runtime_error&) { threw=true; }
|
||||
CHECK(threw, "set_col size mismatch should throw");
|
||||
}
|
||||
|
||||
// ------------------- swap rows/cols -------------------
|
||||
TEST_CASE(Matrix_Swap_Rows) {
|
||||
Mi M(2,3,0);
|
||||
// row0: 1 2 3, row1: 4 5 6
|
||||
for (std::uint64_t j=0;j<3;++j){ M(0,j)=j+1; M(1,j)=j+4; }
|
||||
M.swap_rows(0,1);
|
||||
CHECK(M(0,0)==4 && M(0,1)==5 && M(0,2)==6, "row0 after swap");
|
||||
CHECK(M(1,0)==1 && M(1,1)==2 && M(1,2)==3, "row1 after swap");
|
||||
}
|
||||
|
||||
TEST_CASE(Matrix_Swap_Cols) {
|
||||
Mi M(3,3,0);
|
||||
// col0: 9 8 7, col2: 1 2 3
|
||||
M(0,0)=9; M(1,0)=8; M(2,0)=7;
|
||||
M(0,2)=1; M(1,2)=2; M(2,2)=3;
|
||||
M.swap_cols(0,2);
|
||||
CHECK(M(0,0)==1 && M(1,0)==2 && M(2,0)==3, "col0 after swap");
|
||||
CHECK(M(0,2)==9 && M(1,2)==8 && M(2,2)==7, "col2 after swap");
|
||||
}
|
||||
|
||||
TEST_CASE(Matrix_Swap_OutOfRange_Throws) {
|
||||
Mi M(2,2,0);
|
||||
bool threw=false;
|
||||
try { M.swap_rows(0,2); } catch(const std::out_of_range&) { threw=true; }
|
||||
CHECK(threw, "swap_rows out-of-range should throw");
|
||||
threw=false;
|
||||
try { M.swap_cols(0,3); } catch(const std::out_of_range&) { threw=true; }
|
||||
CHECK(threw, "swap_cols out-of-range should throw");
|
||||
}
|
||||
|
||||
// ------------------- stream output (basic sanity) -------------------
|
||||
TEST_CASE(Matrix_Stream_ToString) {
|
||||
Mf M(2,2,0.0f);
|
||||
M(0,0)=1.0f; M(0,1)=2.0f;
|
||||
M(1,0)=3.0f; M(1,1)=4.0f;
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << M;
|
||||
const std::string s = oss.str();
|
||||
// Format example:
|
||||
// [[1.000, 2.000],
|
||||
// [3.000, 4.000]]
|
||||
CHECK(s.find("[[1.000, 2.000],") != std::string::npos, "ostream first row format");
|
||||
CHECK(s.find("[3.000, 4.000]]") != std::string::npos, "ostream second row format");
|
||||
M(0,0)=1.0f; M(0,1)=2.0f; M(1,0)=3.0f; M(1,1)=4.0f;
|
||||
std::ostringstream os;
|
||||
os << M;
|
||||
auto s = os.str();
|
||||
CHECK(s.find("[[") != std::string::npos, "starts with [[");
|
||||
CHECK(s.find("1.000") != std::string::npos, "contains formatted 1.000");
|
||||
CHECK(s.find("4.000") != std::string::npos, "contains formatted 4.000");
|
||||
}
|
||||
Reference in New Issue
Block a user