Ready for fvm steady case
This commit is contained in:
+136
-73
@@ -1,88 +1,151 @@
|
||||
|
||||
#include "test_common.h"
|
||||
#include "./utils/utils.h" // matrix.h, vector.h
|
||||
//#include "./utils/matrix.h" // matrix.h, vector.h
|
||||
#include "./numerics/transpose.h" // numerics::transpose / inplace_transpose
|
||||
|
||||
using utils::Mi; using utils::Mf; using utils::Md;
|
||||
|
||||
//
|
||||
// ---------- Out-of-place transpose (rectangular) ----------
|
||||
//
|
||||
TEST_CASE(Transpose_Rectangular_OutOfPlace) {
|
||||
// A = [ [1, 2, 3],
|
||||
// [4, 5, 6] ] (2x3)
|
||||
Md A(2,3,0.0);
|
||||
A(0,0)=1; A(0,1)=2; A(0,2)=3;
|
||||
A(1,0)=4; A(1,1)=5; A(1,2)=6;
|
||||
|
||||
auto AT = numerics::transpose(A); // (3x2)
|
||||
|
||||
CHECK(AT.rows()==3 && AT.cols()==2, "shape wrong after transpose");
|
||||
CHECK(AT(0,0)==1 && AT(1,0)==2 && AT(2,0)==3, "first column wrong");
|
||||
CHECK(AT(0,1)==4 && AT(1,1)==5 && AT(2,1)==6, "second column wrong");
|
||||
|
||||
// Involution: T(T(A)) == A
|
||||
auto ATT = numerics::transpose(AT);
|
||||
CHECK(ATT == A, "transpose(transpose(A)) != A");
|
||||
/// ---- helpers ----
|
||||
template <typename T>
|
||||
static void fill_seq(utils::Matrix<T>& M, T start = T(0), T step = T(1)) {
|
||||
std::uint64_t k = 0;
|
||||
for (std::uint64_t i=0; i<M.rows(); ++i)
|
||||
for (std::uint64_t j=0; j<M.cols(); ++j, ++k)
|
||||
M(i,j) = start + step * static_cast<T>(k);
|
||||
}
|
||||
|
||||
//
|
||||
// ---------- In-place transpose (square) ----------
|
||||
//
|
||||
TEST_CASE(Transpose_Square_InPlace) {
|
||||
// 3x3 with distinct values
|
||||
Mf S(3,3,0.0f);
|
||||
float val = 1.0f;
|
||||
for (uint64_t i=0;i<3;++i)
|
||||
for (uint64_t j=0;j<3;++j)
|
||||
S(i,j) = val++;
|
||||
|
||||
// Make an explicit transpose to compare against
|
||||
auto ST = numerics::transpose(S);
|
||||
|
||||
// In-place should match the out-of-place result
|
||||
numerics::inplace_transpose(S);
|
||||
CHECK(S == ST, "inplace_transpose result mismatch");
|
||||
|
||||
// Involution: applying in-place again should return original
|
||||
numerics::inplace_transpose(S);
|
||||
// Now S should equal the original pre-inplace matrix (which was transposed above)
|
||||
// We can reconstruct original by transposing ST:
|
||||
auto orig = numerics::transpose(ST);
|
||||
CHECK(S == orig, "inplace transpose twice should restore original");
|
||||
template <typename T>
|
||||
static bool mats_equal(const utils::Matrix<T>& X, const utils::Matrix<T>& Y) {
|
||||
if (X.rows()!=Y.rows() || X.cols()!=Y.cols()) return false;
|
||||
for (std::uint64_t i=0; i<X.rows(); ++i)
|
||||
for (std::uint64_t j=0; j<X.cols(); ++j)
|
||||
if (X(i,j) != Y(i,j)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// ---------- In-place transpose must throw on non-square ----------
|
||||
//
|
||||
TEST_CASE(Transpose_InPlace_Throws_On_Rectangular) {
|
||||
Md R(2,3,0.0); // rectangular
|
||||
bool threw = false;
|
||||
try {
|
||||
numerics::inplace_transpose(R);
|
||||
} catch (const std::runtime_error&) {
|
||||
threw = true;
|
||||
// ---- tests ----
|
||||
|
||||
// Empty and 1x1 edge cases
|
||||
TEST_CASE(Transpose_Edges) {
|
||||
utils::Mi E; // 0x0
|
||||
auto Et = numerics::transpose(E);
|
||||
CHECK(Et.rows()==0 && Et.cols()==0, "transpose of empty should be empty");
|
||||
|
||||
utils::Mi S(1,1,42);
|
||||
auto St = numerics::transpose(S);
|
||||
CHECK(St.rows()==1 && St.cols()==1, "1x1 stays 1x1");
|
||||
CHECK(St(0,0)==42, "1x1 value preserved");
|
||||
}
|
||||
|
||||
// Rectangular out-of-place
|
||||
TEST_CASE(Transpose_Rectangular) {
|
||||
const std::uint64_t r=3, c=5;
|
||||
utils::Mi A(r,c,0);
|
||||
fill_seq(A, int64_t(1), int64_t(1));
|
||||
auto B = numerics::transpose(A);
|
||||
|
||||
CHECK(B.rows()==c && B.cols()==r, "shape swapped");
|
||||
for (std::uint64_t i=0;i<r;++i)
|
||||
for (std::uint64_t j=0;j<c;++j)
|
||||
CHECK(B(j,i)==A(i,j), "transpose content mismatch");
|
||||
}
|
||||
|
||||
// Square: in-place equals out-of-place
|
||||
TEST_CASE(Transpose_Inplace_Equals_OutOfPlace) {
|
||||
const std::uint64_t n=7;
|
||||
utils::Mi A(n,n,0);
|
||||
fill_seq(A, int64_t(10), int64_t(3));
|
||||
auto B = numerics::transpose(A);
|
||||
|
||||
auto C = A; // copy
|
||||
numerics::inplace_transpose_square(C);
|
||||
CHECK(mats_equal(B, C), "inplace transpose should match out-of-place");
|
||||
}
|
||||
|
||||
// In-place should throw on non-square
|
||||
TEST_CASE(Transpose_Inplace_Throws_On_Rect) {
|
||||
utils::Mi A(2,3,0);
|
||||
bool threw=false;
|
||||
try { numerics::inplace_transpose_square(A); } catch(const std::runtime_error&) { threw=true; }
|
||||
CHECK(threw, "inplace_transpose_square must throw on non-square");
|
||||
}
|
||||
|
||||
// --- OMP variants (compile only with -fopenmp) ---
|
||||
#ifdef _OPENMP
|
||||
TEST_CASE(Transpose_OMP_OutOfPlace_Equals_Serial) {
|
||||
const std::uint64_t r=17, c=31;
|
||||
utils::Mi A(r,c,0);
|
||||
fill_seq(A, int64_t(5), int64_t(2));
|
||||
|
||||
auto B_serial = numerics::transpose(A);
|
||||
auto B_omp = numerics::transpose_omp(A);
|
||||
CHECK(mats_equal(B_serial, B_omp), "transpose_omp != transpose");
|
||||
}
|
||||
|
||||
TEST_CASE(Transpose_OMP_Inplace_Equals_Serial) {
|
||||
const std::uint64_t n=32;
|
||||
utils::Mi A(n,n,0);
|
||||
fill_seq(A, int64_t(0), int64_t(1));
|
||||
|
||||
auto B_ref = numerics::transpose(A);
|
||||
|
||||
auto C = A;
|
||||
numerics::inplace_transpose_square_omp(C);
|
||||
CHECK(mats_equal(B_ref, C), "inplace_transpose_square_omp != transpose");
|
||||
}
|
||||
|
||||
// Auto selectors (if you added transpose_auto / inplace_transpose_square_auto_auto)
|
||||
TEST_CASE(Transpose_Auto_Equals_Serial) {
|
||||
// Rectangular: transpose_auto
|
||||
utils::Mi A(23,11,0);
|
||||
fill_seq(A, int64_t(1), int64_t(1));
|
||||
auto B_ref = numerics::transpose(A);
|
||||
auto B_auto = numerics::transpose_auto(A);
|
||||
CHECK(mats_equal(B_ref, B_auto), "transpose_auto != transpose");
|
||||
|
||||
// Square: inplace_transpose_square_auto
|
||||
utils::Mi S(29,29,0);
|
||||
fill_seq(S, int64_t(4), int64_t(7));
|
||||
auto Tref = numerics::transpose(S);
|
||||
numerics::inplace_transpose_square_auto(S);
|
||||
CHECK(mats_equal(Tref, S), "inplace_transpose_square_auto != transpose");
|
||||
}
|
||||
|
||||
// Nested callsite sanity: call OMP versions inside an outer region
|
||||
TEST_CASE(Transpose_OMP_Nested_Callsite) {
|
||||
// Out-of-place on rectangular
|
||||
utils::Mi A(19,37,0);
|
||||
fill_seq(A, int64_t(2), int64_t(3));
|
||||
auto Bref = numerics::transpose(A);
|
||||
|
||||
int prev_levels = omp_get_max_active_levels();
|
||||
omp_set_max_active_levels(2);
|
||||
|
||||
utils::Mi Bnest;
|
||||
#pragma omp parallel num_threads(2)
|
||||
{
|
||||
#pragma omp single
|
||||
{
|
||||
Bnest = numerics::transpose_omp(A);
|
||||
}
|
||||
}
|
||||
CHECK(threw, "inplace_transpose must throw on non-square matrices");
|
||||
}
|
||||
CHECK(mats_equal(Bref, Bnest), "nested transpose_omp mismatch");
|
||||
|
||||
//
|
||||
// ---------- Edge cases: 0x0 and 1x1 ----------
|
||||
//
|
||||
TEST_CASE(Transpose_Edge_0x0_1x1) {
|
||||
// 0x0 should be fine both ways
|
||||
Md E; // 0x0
|
||||
auto ET = numerics::transpose(E);
|
||||
CHECK(ET.rows()==0 && ET.cols()==0, "0x0 transpose shape wrong");
|
||||
// in-place on 0x0 (rows==cols) should not throw
|
||||
numerics::inplace_transpose(E);
|
||||
CHECK(E.rows()==0 && E.cols()==0, "0x0 inplace transpose changed shape");
|
||||
// In-place on square
|
||||
utils::Mi S(41,41,0);
|
||||
fill_seq(S, int64_t(1), int64_t(5));
|
||||
auto Sref = numerics::transpose(S);
|
||||
|
||||
// 1x1 should be a no-op and not throw
|
||||
Mi I(1,1,0);
|
||||
I(0,0) = 42;
|
||||
auto IT = numerics::transpose(I);
|
||||
CHECK(IT.rows()==1 && IT.cols()==1 && IT(0,0)==42, "1x1 transpose wrong");
|
||||
numerics::inplace_transpose(I);
|
||||
CHECK(I(0,0)==42, "1x1 inplace transpose changed value");
|
||||
#pragma omp parallel num_threads(2)
|
||||
{
|
||||
#pragma omp single
|
||||
{
|
||||
numerics::inplace_transpose_square_omp(S);
|
||||
}
|
||||
}
|
||||
omp_set_max_active_levels(prev_levels);
|
||||
|
||||
CHECK(mats_equal(Sref, S), "nested inplace_transpose_square_omp mismatch");
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user