89 lines
2.8 KiB
C++
89 lines
2.8 KiB
C++
|
|
#include "test_common.h"
|
|
#include "./utils/utils.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");
|
|
}
|
|
|
|
//
|
|
// ---------- 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");
|
|
}
|
|
|
|
//
|
|
// ---------- 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;
|
|
}
|
|
CHECK(threw, "inplace_transpose must throw on non-square matrices");
|
|
}
|
|
|
|
//
|
|
// ---------- 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");
|
|
|
|
// 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");
|
|
}
|