#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"); }